Skip to main content

wasmer_compiler_singlepass/
codegen.rs

1#[cfg(feature = "unwind")]
2use crate::dwarf::WriterRelocate;
3use crate::{
4    address_map::get_function_address_map,
5    codegen_error,
6    common_decl::*,
7    config::Singlepass,
8    elf::{self, CompileOutput},
9    location::{Location, Reg},
10    machine::{
11        AssemblyComment, FinalizedAssembly, Label, Machine, NATIVE_PAGE_SIZE, UnsignedCondition,
12    },
13    output_reporter::ChunkedOutputReporter,
14    unwind::UnwindFrame,
15};
16#[cfg(feature = "unwind")]
17use gimli::write::Address;
18use itertools::Itertools;
19use smallvec::{SmallVec, smallvec};
20use std::{
21    cmp,
22    collections::HashMap,
23    iter,
24    ops::{AddAssign, Neg, SubAssign},
25};
26use target_lexicon::Architecture;
27
28#[cfg(feature = "unwind")]
29use wasmer_compiler::dwarf::{DwarfState, init_dwarf_unit};
30
31use wasmer_compiler::{
32    FunctionBodyData, WasmSourceMap,
33    misc::CompiledKind,
34    types::{
35        function::{CompiledFunction, CompiledFunctionFrameInfo, FunctionBody},
36        relocation::{Relocation, RelocationTarget},
37        section::SectionIndex,
38    },
39    wasmparser::{
40        BlockType as WpTypeOrFuncType, HeapType as WpHeapType, MemArg, Operator,
41        RefType as WpRefType, ValType as WpType,
42    },
43};
44
45#[cfg(feature = "unwind")]
46use wasmer_compiler::types::unwind::CompiledFunctionUnwindInfo;
47
48use wasmer_types::{
49    CompilationProgressCallback, CompileError, FunctionIndex, FunctionType, GlobalIndex,
50    LocalFunctionIndex, MemoryIndex, MemoryStyle, ModuleInfo, SignatureIndex, TableIndex,
51    TableStyle, TrapCode, Type, VMBuiltinFunctionIndex, VMOffsets,
52    entity::{EntityRef, PrimaryMap},
53};
54use wasmer_types::{
55    target::{CallingConvention, Target},
56    vmctx_offset,
57};
58
59#[allow(type_alias_bounds)]
60type LocationWithCanonicalization<M: Machine> = (Location<M::GPR, M::SIMD>, CanonicalizeType);
61
62/// Stack offset tracking in bytes where we track the maximum offset.
63#[derive(Default)]
64struct TrackedStackOffset {
65    offset: usize,
66    maximum_offset: usize,
67}
68
69impl TrackedStackOffset {
70    fn get(&self) -> usize {
71        self.offset
72    }
73
74    fn track_temporary_extra_allocation(&mut self, extra: usize) {
75        self.maximum_offset = self.maximum_offset.max(self.offset + extra);
76    }
77}
78
79impl AddAssign<usize> for TrackedStackOffset {
80    fn add_assign(&mut self, rhs: usize) {
81        self.offset += rhs;
82        self.maximum_offset = self.maximum_offset.max(self.offset);
83    }
84}
85
86impl SubAssign<usize> for TrackedStackOffset {
87    fn sub_assign(&mut self, rhs: usize) {
88        self.offset -= rhs;
89    }
90}
91
92/// The singlepass per-function code generator.
93pub struct FuncGen<'a, M: Machine> {
94    // Immutable properties assigned at creation time.
95    /// Static module information.
96    module: &'a ModuleInfo,
97
98    /// ModuleInfo compilation config.
99    config: &'a Singlepass,
100
101    /// Offsets of vmctx fields.
102    vmoffsets: &'a VMOffsets,
103
104    // // Memory plans.
105    memory_styles: &'a PrimaryMap<MemoryIndex, MemoryStyle>,
106
107    /// Function signature.
108    signature: FunctionType,
109
110    // Working storage.
111    /// Memory locations of local variables.
112    locals: Vec<Location<M::GPR, M::SIMD>>,
113
114    /// Types of local variables, including arguments.
115    local_types: Vec<WpType>,
116
117    /// Value stack.
118    value_stack: Vec<LocationWithCanonicalization<M>>,
119
120    /// A list of frames describing the current control stack.
121    control_stack: Vec<ControlFrame<M>>,
122
123    /// Stack offset tracking in bytes.
124    stack_offset: TrackedStackOffset,
125
126    save_area_offset: Option<usize>,
127
128    /// Low-level machine state.
129    machine: M,
130
131    /// Nesting level of unreachable code.
132    unreachable_depth: usize,
133
134    /// Index of a function defined locally inside the WebAssembly module.
135    local_func_index: LocalFunctionIndex,
136
137    /// Relocation information.
138    relocations: Vec<Relocation>,
139
140    /// A set of special labels for trapping.
141    special_labels: SpecialLabelSet,
142
143    /// Calling convention to use.
144    calling_convention: CallingConvention,
145
146    /// Name of the function.
147    function_name: String,
148
149    /// Assembly comments.
150    assembly_comments: HashMap<usize, AssemblyComment>,
151
152    /// Batched function local accounting backed by the module output budget.
153    output_reporter: ChunkedOutputReporter<'a>,
154
155    /// DWARF debug information accumulated for this function.
156    #[cfg(feature = "unwind")]
157    dwarf_state: Option<DwarfState>,
158}
159
160struct SpecialLabelSet {
161    integer_division_by_zero: Label,
162    integer_overflow: Label,
163    heap_access_oob: Label,
164    table_access_oob: Label,
165    indirect_call_null: Label,
166    bad_signature: Label,
167    unaligned_atomic: Label,
168}
169
170/// Type of a pending canonicalization floating point value.
171/// Sometimes we don't have the type information elsewhere and therefore we need to track it here.
172#[derive(Copy, Clone, Debug)]
173pub(crate) enum CanonicalizeType {
174    None,
175    F32,
176    F64,
177}
178
179impl CanonicalizeType {
180    fn to_size(self) -> Option<Size> {
181        match self {
182            CanonicalizeType::F32 => Some(Size::S32),
183            CanonicalizeType::F64 => Some(Size::S64),
184            CanonicalizeType::None => None,
185        }
186    }
187}
188
189trait WpTypeExt {
190    fn is_float(&self) -> bool;
191}
192
193impl WpTypeExt for WpType {
194    fn is_float(&self) -> bool {
195        matches!(self, WpType::F32 | WpType::F64)
196    }
197}
198
199#[derive(Clone)]
200pub enum ControlState<M: Machine> {
201    Function,
202    Block,
203    Loop,
204    If {
205        label_else: Label,
206        // Store the input parameters for the If block, as they'll need to be
207        // restored when processing the Else block (if present).
208        inputs: SmallVec<[LocationWithCanonicalization<M>; 1]>,
209    },
210    Else,
211}
212
213#[derive(Clone)]
214struct ControlFrame<M: Machine> {
215    pub state: ControlState<M>,
216    pub label: Label,
217    pub param_types: SmallVec<[WpType; 8]>,
218    pub return_types: SmallVec<[WpType; 1]>,
219    /// Value stack depth at the beginning of the frame (including params and results).
220    value_stack_depth: usize,
221}
222
223impl<M: Machine> ControlFrame<M> {
224    // Get value stack depth at the end of the frame.
225    fn value_stack_depth_after(&self) -> usize {
226        let mut depth: usize = self.value_stack_depth - self.param_types.len();
227
228        // For Loop, we have to use another slot for params that implements the PHI operation.
229        if matches!(self.state, ControlState::Loop) {
230            depth -= self.param_types.len();
231        }
232
233        depth
234    }
235
236    /// Returns the value stack depth at which resources should be deallocated.
237    /// For loops, this preserves PHI arguments by excluding them from deallocation.
238    fn value_stack_depth_for_release(&self) -> usize {
239        self.value_stack_depth - self.param_types.len()
240    }
241}
242
243fn type_to_wp_type(ty: &Type) -> WpType {
244    match ty {
245        Type::I32 => WpType::I32,
246        Type::I64 => WpType::I64,
247        Type::F32 => WpType::F32,
248        Type::F64 => WpType::F64,
249        Type::V128 => WpType::V128,
250        Type::ExternRef => WpType::Ref(WpRefType::new(true, WpHeapType::EXTERN).unwrap()),
251        Type::FuncRef => WpType::Ref(WpRefType::new(true, WpHeapType::FUNC).unwrap()),
252        Type::ExceptionRef => todo!(),
253    }
254}
255
256/// Abstraction for a 2-input, 1-output operator. Can be an integer/floating-point
257/// binop/cmpop.
258struct I2O1<R: Reg, S: Reg> {
259    loc_a: Location<R, S>,
260    loc_b: Location<R, S>,
261    ret: Location<R, S>,
262}
263
264/// Type of native call we emit.
265enum NativeCallType {
266    IncludeVMCtxArgument,
267    Unreachable,
268}
269
270const RED_ZONE_SIZE: usize = 32;
271
272impl<'a, M: Machine> FuncGen<'a, M> {
273    /// Charges newly emitted machine code to the function local output batch.
274    #[inline]
275    fn ensure_output_size_within_limit(&mut self) -> Result<(), CompileError> {
276        self.output_reporter
277            .check(self.machine.assembler_get_offset().0)
278    }
279
280    /// Acquires location from the machine state.
281    ///
282    /// If the returned location is used for stack value, `release_location` needs to be called on it;
283    /// Otherwise, if the returned locations is used for a local, `release_location` does not need to be called on it.
284    fn acquire_location(&mut self, ty: &WpType) -> Result<Location<M::GPR, M::SIMD>, CompileError> {
285        let loc = match *ty {
286            WpType::F32 | WpType::F64 => self.machine.pick_simd().map(Location::SIMD),
287            WpType::I32 | WpType::I64 => self.machine.pick_gpr().map(Location::GPR),
288            WpType::Ref(ty) if ty.is_extern_ref() || ty.is_func_ref() => {
289                self.machine.pick_gpr().map(Location::GPR)
290            }
291            _ => codegen_error!("can't acquire location for type {:?}", ty),
292        };
293
294        let Some(loc) = loc else {
295            return self.acquire_location_on_stack();
296        };
297
298        if let Location::GPR(x) = loc {
299            self.machine.reserve_gpr(x);
300        } else if let Location::SIMD(x) = loc {
301            self.machine.reserve_simd(x);
302        }
303        Ok(loc)
304    }
305
306    /// Acquire location that will live on the stack.
307    fn acquire_location_on_stack(&mut self) -> Result<Location<M::GPR, M::SIMD>, CompileError> {
308        let old_adjust = self.stack_offset.get().next_multiple_of(M::STACK_ALIGNMENT);
309        self.stack_offset += 8;
310        let stack_diff = self.stack_offset.get().next_multiple_of(M::STACK_ALIGNMENT) - old_adjust;
311
312        let loc = self.machine.local_on_stack(self.stack_offset.get() as i32);
313        if stack_diff > 0 {
314            self.machine.extend_stack(stack_diff as u32)?;
315        }
316
317        Ok(loc)
318    }
319
320    /// Releases locations used for stack value.
321    fn release_locations(
322        &mut self,
323        locs: &[LocationWithCanonicalization<M>],
324    ) -> Result<(), CompileError> {
325        self.release_stack_locations(locs)?;
326        self.release_reg_locations(locs)
327    }
328
329    fn release_reg_locations(
330        &mut self,
331        locs: &[LocationWithCanonicalization<M>],
332    ) -> Result<(), CompileError> {
333        for (loc, _) in locs.iter().rev() {
334            match *loc {
335                Location::GPR(ref x) => {
336                    self.machine.release_gpr(*x);
337                }
338                Location::SIMD(ref x) => {
339                    self.machine.release_simd(*x);
340                }
341                _ => {}
342            }
343        }
344        Ok(())
345    }
346
347    fn release_stack_locations(
348        &mut self,
349        locs: &[LocationWithCanonicalization<M>],
350    ) -> Result<(), CompileError> {
351        let old_adjust = self.stack_offset.get().next_multiple_of(M::STACK_ALIGNMENT);
352        for (loc, _) in locs.iter().rev() {
353            if let Location::Memory(..) = *loc {
354                self.check_location_on_stack(loc, self.stack_offset.get())?;
355                self.stack_offset -= 8;
356            }
357        }
358        let stack_diff = old_adjust - self.stack_offset.get().next_multiple_of(M::STACK_ALIGNMENT);
359        // It's important to emit a stack release instruction just once as we might be releasing
360        // potentially a big number of slots.
361        if stack_diff > 0 {
362            self.machine.truncate_stack(stack_diff as u32)?;
363        }
364
365        Ok(())
366    }
367
368    fn release_stack_locations_keep_stack_offset(
369        &mut self,
370        stack_depth: usize,
371    ) -> Result<(), CompileError> {
372        let mut stack_offset = self.stack_offset.get();
373        let old_adjust = stack_offset.next_multiple_of(M::STACK_ALIGNMENT);
374        let locs = &self.value_stack[stack_depth..];
375
376        for (loc, _) in locs.iter().rev() {
377            if let Location::Memory(..) = *loc {
378                self.check_location_on_stack(loc, stack_offset)?;
379                stack_offset -= 8;
380            }
381        }
382        let stack_diff = old_adjust - stack_offset.next_multiple_of(M::STACK_ALIGNMENT);
383        // It's important to emit a stack release instruction just once as we might be releasing
384        // potentially a big number of slots.
385        if stack_diff > 0 {
386            self.machine.truncate_stack(stack_diff as u32)?;
387        }
388
389        Ok(())
390    }
391
392    fn check_location_on_stack(
393        &self,
394        loc: &Location<M::GPR, M::SIMD>,
395        expected_stack_offset: usize,
396    ) -> Result<(), CompileError> {
397        let Location::Memory(reg, offset) = loc else {
398            codegen_error!("Expected stack memory location");
399        };
400        if reg != &self.machine.local_pointer() {
401            codegen_error!("Expected location pointer for value on stack");
402        }
403        if *offset >= 0 {
404            codegen_error!("Invalid memory offset {offset}");
405        }
406        let offset = offset.neg() as usize;
407        if offset != expected_stack_offset {
408            codegen_error!(
409                "Invalid memory offset {offset}!={}",
410                self.stack_offset.get()
411            );
412        }
413        Ok(())
414    }
415
416    /// Allocate return slots for block operands (Block, If, Loop) and swap them with
417    /// the corresponding input parameters on the value stack.
418    ///
419    /// This method reserves memory slots that can accommodate both integer and
420    /// floating-point types, then swaps these slots with the last `stack_slots`
421    /// values on the stack to position them correctly for the block's return values.
422    /// that are already present at the value stack.
423    fn allocate_return_slots_and_swap(
424        &mut self,
425        stack_slots: usize,
426        return_slots: usize,
427    ) -> Result<(), CompileError> {
428        // No shuffling needed.
429        if return_slots == 0 {
430            return Ok(());
431        }
432
433        /* To allocate N return slots, we first allocate N additional stack (memory) slots and then "shift" the
434        existing stack slots. This results in the layout: [value stack before frame, ret0, ret1, ret2, ..., retN, arg0, arg1, ..., argN],
435        where some of the argN values may reside in registers and others in memory on the stack. */
436        let latest_slots = self
437            .value_stack
438            .drain(self.value_stack.len() - stack_slots..)
439            .collect_vec();
440        let extra_slots = (0..return_slots)
441            .map(|_| self.acquire_location_on_stack())
442            .collect::<Result<Vec<_>, _>>()?;
443
444        let mut all_memory_slots = latest_slots
445            .iter()
446            .filter_map(|(loc, _)| {
447                if let Location::Memory(..) = loc {
448                    Some(loc)
449                } else {
450                    None
451                }
452            })
453            .chain(extra_slots.iter())
454            .collect_vec();
455
456        // First put the newly allocated return values to the value stack.
457        self.value_stack.extend(
458            all_memory_slots
459                .iter()
460                .take(return_slots)
461                .map(|loc| (**loc, CanonicalizeType::None)),
462        );
463
464        // Then map all memory stack slots to a new location (in reverse order).
465        let mut new_params_reversed = Vec::new();
466        for (loc, canonicalize) in latest_slots.iter().rev() {
467            let mapped_loc = if matches!(loc, Location::Memory(..)) {
468                let dest = all_memory_slots.pop().unwrap();
469                self.machine.emit_relaxed_mov(Size::S64, *loc, *dest)?;
470                *dest
471            } else {
472                *loc
473            };
474            new_params_reversed.push((mapped_loc, *canonicalize));
475            self.ensure_output_size_within_limit()?;
476        }
477        self.value_stack
478            .extend(new_params_reversed.into_iter().rev());
479
480        Ok(())
481    }
482
483    #[allow(clippy::type_complexity)]
484    fn init_locals(
485        &mut self,
486        n: usize,
487        sig: FunctionType,
488        calling_convention: CallingConvention,
489    ) -> Result<Vec<Location<M::GPR, M::SIMD>>, CompileError> {
490        self.add_assembly_comment(AssemblyComment::InitializeLocals);
491
492        // How many machine stack slots will all the locals use?
493        let num_mem_slots = (0..n)
494            .filter(|&x| self.machine.is_local_on_stack(x))
495            .count();
496
497        // Total size (in bytes) of the pre-allocated "static area" for this function's
498        // locals and callee-saved registers.
499        let mut static_area_size: usize = 0;
500
501        // Callee-saved registers used for locals.
502        // Keep this consistent with the "Save callee-saved registers" code below.
503        for i in 0..n {
504            // If a local is not stored on stack, then it is allocated to a callee-saved register.
505            if !self.machine.is_local_on_stack(i) {
506                static_area_size += 8;
507            }
508        }
509
510        // Callee-saved vmctx.
511        static_area_size += 8;
512
513        // Total size of callee saved registers.
514        let callee_saved_regs_size = static_area_size;
515
516        // Now we can determine concrete locations for locals.
517        let locations: Vec<Location<M::GPR, M::SIMD>> = (0..n)
518            .map(|i| self.machine.get_local_location(i, callee_saved_regs_size))
519            .collect();
520
521        // Add size of locals on stack.
522        static_area_size += num_mem_slots * 8;
523
524        // Allocate save area, without actually writing to it.
525        static_area_size = static_area_size.next_multiple_of(M::STACK_ALIGNMENT);
526
527        // Stack probe.
528        //
529        // `rep stosq` writes data from low address to high address and may skip the stack guard page.
530        // so here we probe it explicitly when needed.
531        for i in (sig.params().len()..n)
532            .step_by(NATIVE_PAGE_SIZE / 8)
533            .skip(1)
534        {
535            self.machine.zero_location(Size::S64, locations[i])?;
536            self.ensure_output_size_within_limit()?;
537        }
538
539        self.machine.extend_stack(static_area_size as _)?;
540
541        // Save callee-saved registers.
542        for loc in locations.iter() {
543            if let Location::GPR(_) = *loc {
544                self.stack_offset += 8;
545                self.machine
546                    .move_local(self.stack_offset.get() as i32, *loc)?;
547            }
548        }
549
550        // Save the Reg use for vmctx.
551        self.stack_offset += 8;
552        self.machine.move_local(
553            self.stack_offset.get() as i32,
554            Location::GPR(self.machine.get_vmctx_reg()),
555        )?;
556
557        // Save the offset of register save area.
558        self.save_area_offset = Some(self.stack_offset.get());
559
560        // Load in-register parameters into the allocated locations.
561        // Locals are allocated on the stack from higher address to lower address,
562        // so we won't skip the stack guard page here.
563        let mut stack_offset: usize = 0;
564        for (i, param) in sig.params().iter().enumerate() {
565            let sz = match *param {
566                Type::I32 | Type::F32 => Size::S32,
567                Type::I64 | Type::F64 => Size::S64,
568                Type::ExternRef | Type::FuncRef => Size::S64,
569                _ => {
570                    codegen_error!("singlepass init_local unimplemented type: {param}")
571                }
572            };
573            let loc = self.machine.get_call_param_location(
574                sig.results().len(),
575                i + 1,
576                sz,
577                &mut stack_offset,
578                calling_convention,
579            );
580            self.machine
581                .move_location_extend(sz, false, loc, Size::S64, locations[i])?;
582            self.ensure_output_size_within_limit()?;
583        }
584
585        // Load vmctx into it's GPR.
586        self.machine.move_location(
587            Size::S64,
588            Location::GPR(self.machine.get_simple_param_location(0)),
589            Location::GPR(self.machine.get_vmctx_reg()),
590        )?;
591
592        // Initialize all normal locals to zero.
593        let mut init_stack_loc_cnt = 0;
594        let mut last_stack_loc = Location::Memory(self.machine.local_pointer(), i32::MAX);
595        for location in locations.iter().take(n).skip(sig.params().len()) {
596            match location {
597                Location::Memory(_, _) => {
598                    init_stack_loc_cnt += 1;
599                    last_stack_loc = cmp::min(last_stack_loc, *location);
600                }
601                Location::GPR(_) => {
602                    self.machine.zero_location(Size::S64, *location)?;
603                }
604                _ => codegen_error!("singlepass init_local unreachable"),
605            }
606        }
607        if init_stack_loc_cnt > 0 {
608            self.machine
609                .init_stack_loc(init_stack_loc_cnt, last_stack_loc)?;
610        }
611
612        // Add the size of all locals allocated to stack.
613        self.stack_offset += static_area_size - callee_saved_regs_size;
614
615        Ok(locations)
616    }
617
618    fn finalize_locals(&mut self) -> Result<(), CompileError> {
619        // Unwind stack to the "save area".
620        self.machine
621            .restore_saved_area(self.save_area_offset.unwrap() as i32)?;
622
623        // Restore register used by vmctx.
624        self.machine
625            .pop_location(Location::GPR(self.machine.get_vmctx_reg()))?;
626
627        // Restore callee-saved registers.
628        for loc in self.locals.iter().rev() {
629            if let Location::GPR(_) = *loc {
630                self.machine.pop_location(*loc)?;
631            }
632        }
633        Ok(())
634    }
635
636    /// Set the source location of the Wasm to the given offset.
637    pub fn set_srcloc(&mut self, offset: u32) {
638        self.machine.set_srcloc(offset);
639    }
640
641    fn get_location_released(
642        &mut self,
643        loc: (Location<M::GPR, M::SIMD>, CanonicalizeType),
644    ) -> Result<LocationWithCanonicalization<M>, CompileError> {
645        self.release_locations(&[loc])?;
646        Ok(loc)
647    }
648
649    fn pop_value_released(&mut self) -> Result<LocationWithCanonicalization<M>, CompileError> {
650        let loc = self.value_stack.pop().ok_or_else(|| {
651            CompileError::Codegen("pop_value_released: value stack is empty".to_owned())
652        })?;
653        self.get_location_released(loc)?;
654        Ok(loc)
655    }
656
657    fn fold_atomic_mem_addr(
658        &mut self,
659        addr: LocationWithCanonicalization<M>,
660        memarg: &MemArg,
661    ) -> Result<LocationWithCanonicalization<M>, CompileError> {
662        if memarg.offset == 0 {
663            return Ok(addr);
664        }
665
666        let offset = memarg.offset as u32;
667        match addr.0 {
668            Location::Imm32(value) => Ok(if let Some(addr) = value.checked_add(offset) {
669                (Location::Imm32(addr), CanonicalizeType::None)
670            } else {
671                self.machine
672                    .jmp_unconditional(self.special_labels.heap_access_oob)?;
673                (Location::Imm32(0), CanonicalizeType::None)
674            }),
675            Location::Imm64(_) => codegen_error!("memory.atomic address must be i32"),
676            _ => {
677                let effective_addr = self.machine.acquire_temp_gpr().unwrap();
678                let upper_bound = self.machine.acquire_temp_gpr().unwrap();
679                self.machine.move_location_extend(
680                    Size::S32,
681                    false,
682                    addr.0,
683                    Size::S64,
684                    Location::GPR(effective_addr),
685                )?;
686                self.machine.emit_binop_add64(
687                    Location::GPR(effective_addr),
688                    Location::Imm64(memarg.offset),
689                    Location::GPR(effective_addr),
690                )?;
691                // The use of the temporary register is necessary.
692                self.machine.move_location(
693                    Size::S64,
694                    Location::Imm64(0x1_0000_0000),
695                    Location::GPR(upper_bound),
696                )?;
697                self.machine.jmp_on_condition(
698                    UnsignedCondition::AboveEqual,
699                    Size::S64,
700                    Location::GPR(effective_addr),
701                    Location::GPR(upper_bound),
702                    self.special_labels.heap_access_oob,
703                )?;
704                self.machine
705                    .move_location(Size::S32, Location::GPR(effective_addr), addr.0)?;
706                self.machine.release_gpr(upper_bound);
707                self.machine.release_gpr(effective_addr);
708                Ok(addr)
709            }
710        }
711    }
712
713    /// Prepare data for binary operator with 2 inputs and 1 output.
714    fn i2o1_prepare(
715        &mut self,
716        ty: WpType,
717        canonicalize: CanonicalizeType,
718    ) -> Result<I2O1<M::GPR, M::SIMD>, CompileError> {
719        let loc_b = self.pop_value_released()?.0;
720        let loc_a = self.pop_value_released()?.0;
721        let ret = self.acquire_location(&ty)?;
722        self.value_stack.push((ret, canonicalize));
723        Ok(I2O1 { loc_a, loc_b, ret })
724    }
725
726    /// Emits a Native ABI call sequence.
727    ///
728    /// The caller MUST NOT hold any temporary registers allocated by `acquire_temp_gpr` when calling
729    /// this function.
730    fn emit_call_native<
731        I: Iterator<Item = (Location<M::GPR, M::SIMD>, CanonicalizeType)>,
732        J: Iterator<Item = WpType>,
733        K: Iterator<Item = WpType>,
734        F: FnOnce(&mut Self) -> Result<(), CompileError>,
735    >(
736        &mut self,
737        cb: F,
738        params: I,
739        params_type: J,
740        return_types: K,
741        call_type: NativeCallType,
742    ) -> Result<(), CompileError> {
743        let params = params.collect_vec();
744        let stack_params = params
745            .iter()
746            .copied()
747            .filter(|(param, _)| {
748                if let Location::Memory(reg, _) = param {
749                    debug_assert_eq!(reg, &self.machine.local_pointer());
750                    true
751                } else {
752                    false
753                }
754            })
755            .collect_vec();
756        let get_size = |param_type: WpType| match param_type {
757            WpType::F32 | WpType::I32 => Size::S32,
758            WpType::V128 => unimplemented!(),
759            _ => Size::S64,
760        };
761        let param_sizes = params_type.map(get_size).collect_vec();
762        let return_value_sizes = return_types.map(get_size).collect_vec();
763
764        /* We're going to reuse the memory param locations for the return values. Any extra needed slots will be allocated on stack. */
765        let used_stack_params = stack_params
766            .iter()
767            .take(return_value_sizes.len())
768            .copied()
769            .collect_vec();
770        // Reuse argument locations, not their pending canonicalization metadata.
771        let mut return_values = used_stack_params
772            .iter()
773            .map(|(loc, _)| (*loc, CanonicalizeType::None))
774            .collect_vec();
775        let extra_return_values = (0..return_value_sizes.len().saturating_sub(stack_params.len()))
776            .map(|_| -> Result<_, CompileError> {
777                Ok((self.acquire_location_on_stack()?, CanonicalizeType::None))
778            })
779            .collect::<Result<Vec<_>, _>>()?;
780        return_values.extend(extra_return_values);
781
782        // Release the parameter slots that live in registers.
783        self.release_reg_locations(&params)?;
784
785        // Save used GPRs. Preserve correct stack alignment
786        let used_gprs = self.machine.get_used_gprs();
787        let mut used_stack = self.machine.push_used_gpr(&used_gprs)?;
788
789        // Save used SIMD registers.
790        let used_simds = self.machine.get_used_simd();
791        if !used_simds.is_empty() {
792            used_stack += self.machine.push_used_simd(&used_simds)?;
793        }
794        // mark the GPR used for Call as used
795        self.machine
796            .reserve_unused_temp_gpr(self.machine.get_gpr_for_call());
797
798        let calling_convention = self.calling_convention;
799
800        let mut stack_offset: usize = 0;
801        // Allocate space for return values relative to SP (the allocation happens in reverse order, thus start with return slots).
802        let mut return_args = Vec::with_capacity(return_value_sizes.len());
803        for i in 0..return_value_sizes.len() {
804            return_args.push(self.machine.get_return_value_location(i, &mut stack_offset));
805        }
806
807        // Allocate space for arguments relative to SP.
808        let mut args = Vec::with_capacity(params.len());
809        for (i, param_size) in param_sizes.iter().enumerate() {
810            args.push(self.machine.get_param_location(
811                match call_type {
812                    NativeCallType::IncludeVMCtxArgument => 1,
813                    NativeCallType::Unreachable => 0,
814                } + i,
815                *param_size,
816                &mut stack_offset,
817                calling_convention,
818            ));
819        }
820
821        // Align stack to 16 bytes.
822        let stack_unaligned = (self.stack_offset.get().next_multiple_of(M::STACK_ALIGNMENT)
823            + used_stack
824            + stack_offset)
825            % 16;
826        if stack_unaligned != 0 {
827            stack_offset += 16 - stack_unaligned;
828        }
829        self.machine.extend_stack(stack_offset as u32)?;
830
831        #[allow(clippy::type_complexity)]
832        let mut call_movs = Vec::new();
833        // Prepare register & stack parameters.
834        for (i, ((param, _), param_size)) in
835            (params.iter().zip(param_sizes.iter())).enumerate().rev()
836        {
837            let loc = args[i];
838            match loc {
839                Location::GPR(x) => {
840                    call_movs.push((*param, x, *param_size));
841                }
842                Location::Memory(_, _) => {
843                    self.machine
844                        .move_location_for_native(param_sizes[i], *param, loc)?;
845                    self.ensure_output_size_within_limit()?;
846                }
847                _ => {
848                    return Err(CompileError::Codegen(
849                        "emit_call_native loc: unreachable code".to_owned(),
850                    ));
851                }
852            }
853        }
854
855        // Sort register moves so that register are not overwritten before read.
856        Self::sort_call_movs(&mut call_movs);
857
858        // Emit register moves.
859        for (loc, gpr, size) in call_movs {
860            if loc != Location::GPR(gpr) {
861                self.machine
862                    .move_location(Size::S64, loc, Location::GPR(gpr))?;
863            }
864            // Adjust the argument if required by ABI
865            self.machine.adjust_gpr_param_location(gpr, size)?;
866        }
867
868        if matches!(call_type, NativeCallType::IncludeVMCtxArgument) {
869            // Put vmctx as the first parameter.
870            self.machine.move_location(
871                Size::S64,
872                Location::GPR(self.machine.get_vmctx_reg()),
873                Location::GPR(self.machine.get_simple_param_location(0)),
874            )?; // vmctx
875        }
876
877        self.stack_offset
878            .track_temporary_extra_allocation(stack_offset + used_stack);
879        // release the GPR used for call
880        self.machine.release_gpr(self.machine.get_gpr_for_call());
881
882        let begin = self.machine.assembler_get_offset().0;
883        cb(self)?;
884        if matches!(call_type, NativeCallType::Unreachable) {
885            let end = self.machine.assembler_get_offset().0;
886            self.machine.mark_address_range_with_trap_code(
887                TrapCode::UnreachableCodeReached,
888                begin,
889                end,
890            );
891        }
892
893        // Take the returned values from the fn call.
894        for (i, &return_type) in return_value_sizes.iter().enumerate() {
895            self.machine.move_location_for_native(
896                return_type,
897                return_args[i],
898                return_values[i].0,
899            )?;
900            self.ensure_output_size_within_limit()?;
901        }
902
903        // Restore stack.
904        if stack_offset > 0 {
905            self.machine.truncate_stack(stack_offset as u32)?;
906        }
907
908        // Restore SIMDs.
909        if !used_simds.is_empty() {
910            self.machine.pop_used_simd(&used_simds)?;
911        }
912
913        // Restore GPRs.
914        self.machine.pop_used_gpr(&used_gprs)?;
915
916        // We are re-using the params for the return values, thus release just the chunk
917        // we're not planning to use!
918        let params_to_release =
919            &stack_params[cmp::min(stack_params.len(), return_value_sizes.len())..];
920        self.release_stack_locations(params_to_release)?;
921
922        self.value_stack.extend(return_values);
923
924        Ok(())
925    }
926
927    /// Emits a memory operation.
928    fn op_memory<
929        F: FnOnce(&mut Self, bool, bool, i32, Label, Label) -> Result<(), CompileError>,
930    >(
931        &mut self,
932        memory_index: MemoryIndex,
933        cb: F,
934    ) -> Result<(), CompileError> {
935        let need_check = match self.memory_styles[memory_index] {
936            MemoryStyle::Static => false,
937            MemoryStyle::Dynamic { .. } => true,
938        };
939
940        let local_memory_index = self.module.local_memory_index(memory_index);
941        let is_imported = local_memory_index.is_none();
942        let offset = if let Some(local_memory_index) = local_memory_index {
943            self.vmoffsets.vmctx_vmmemory_definition(local_memory_index)
944        } else {
945            self.vmoffsets
946                .vmctx_vmmemory_import_definition(memory_index)
947        };
948        cb(
949            self,
950            need_check,
951            is_imported,
952            vmctx_offset(offset)?,
953            self.special_labels.heap_access_oob,
954            self.special_labels.unaligned_atomic,
955        )
956    }
957
958    fn emit_head(&mut self) -> Result<(), CompileError> {
959        self.add_assembly_comment(AssemblyComment::FunctionPrologue);
960        self.machine.emit_function_prolog()?;
961
962        // Initialize locals.
963        self.locals = self.init_locals(
964            self.local_types.len(),
965            self.signature.clone(),
966            self.calling_convention,
967        )?;
968
969        // simulate "red zone" if not supported by the platform
970        self.add_assembly_comment(AssemblyComment::RedZone);
971        self.stack_offset += RED_ZONE_SIZE;
972        self.machine.extend_stack(RED_ZONE_SIZE as u32)?;
973
974        let return_types: SmallVec<_> = self
975            .signature
976            .results()
977            .iter()
978            .map(type_to_wp_type)
979            .collect();
980
981        // Push return value slots for the function return on the stack.
982        self.value_stack.extend((0..return_types.len()).map(|i| {
983            (
984                self.machine.get_call_return_value_location(i),
985                CanonicalizeType::None,
986            )
987        }));
988
989        self.control_stack.push(ControlFrame {
990            state: ControlState::Function,
991            label: self.machine.get_label(),
992            value_stack_depth: return_types.len(),
993            param_types: smallvec![],
994            return_types,
995        });
996
997        // TODO: Full preemption by explicit signal checking
998
999        // We insert set StackOverflow as the default trap that can happen
1000        // anywhere in the function prologue.
1001        self.machine.insert_stackoverflow();
1002        self.add_assembly_comment(AssemblyComment::FunctionBody);
1003
1004        Ok(())
1005    }
1006
1007    #[allow(clippy::too_many_arguments)]
1008    pub fn new(
1009        module: &'a ModuleInfo,
1010        config: &'a Singlepass,
1011        vmoffsets: &'a VMOffsets,
1012        memory_styles: &'a PrimaryMap<MemoryIndex, MemoryStyle>,
1013        _table_styles: &'a PrimaryMap<TableIndex, TableStyle>,
1014        local_func_index: LocalFunctionIndex,
1015        local_types_excluding_arguments: &[WpType],
1016        machine: M,
1017        calling_convention: CallingConvention,
1018        progress_callback: Option<&'a CompilationProgressCallback>,
1019    ) -> Result<FuncGen<'a, M>, CompileError> {
1020        let func_index = module.func_index(local_func_index);
1021        let sig_index = module.functions[func_index];
1022        let signature = module.signatures[sig_index].clone();
1023
1024        let mut local_types: Vec<_> = signature.params().iter().map(type_to_wp_type).collect();
1025        local_types.extend_from_slice(local_types_excluding_arguments);
1026
1027        let mut machine = machine;
1028        let special_labels = SpecialLabelSet {
1029            integer_division_by_zero: machine.get_label(),
1030            integer_overflow: machine.get_label(),
1031            heap_access_oob: machine.get_label(),
1032            table_access_oob: machine.get_label(),
1033            indirect_call_null: machine.get_label(),
1034            bad_signature: machine.get_label(),
1035            unaligned_atomic: machine.get_label(),
1036        };
1037        let function_name = module
1038            .function_names
1039            .get(&func_index)
1040            .map(|fname| fname.to_string())
1041            .unwrap_or_else(|| format!("function_{}", func_index.as_u32()));
1042
1043        let mut fg = FuncGen {
1044            module,
1045            config,
1046            vmoffsets,
1047            memory_styles,
1048            // table_styles,
1049            signature,
1050            locals: vec![], // initialization deferred to emit_head
1051            local_types,
1052            value_stack: vec![],
1053            control_stack: vec![],
1054            stack_offset: TrackedStackOffset::default(),
1055            save_area_offset: None,
1056            machine,
1057            unreachable_depth: 0,
1058            local_func_index,
1059            relocations: vec![],
1060            special_labels,
1061            calling_convention,
1062            #[cfg(feature = "unwind")]
1063            dwarf_state: init_dwarf_unit(
1064                &function_name,
1065                module.name.as_deref(),
1066                "Wasmer (Singlepass)",
1067            )
1068            .ok(),
1069            function_name,
1070            assembly_comments: HashMap::new(),
1071            output_reporter: ChunkedOutputReporter::new(progress_callback),
1072        };
1073        fg.emit_head()?;
1074        Ok(fg)
1075    }
1076
1077    pub fn has_control_frames(&self) -> bool {
1078        !self.control_stack.is_empty()
1079    }
1080
1081    /// Moves the top `return_values` items from the value stack into the
1082    /// preallocated return slots starting at `value_stack_depth_after`.
1083    ///
1084    /// Used when completing Block/If/Loop constructs or returning from the
1085    /// function. Applies NaN canonicalization when enabled and supported.
1086    fn emit_return_values(
1087        &mut self,
1088        value_stack_depth_after: usize,
1089        return_values: usize,
1090    ) -> Result<(), CompileError> {
1091        let return_values: SmallVec<[LocationWithCanonicalization<M>; 8]> = self
1092            .value_stack
1093            .iter()
1094            .rev()
1095            .take(return_values)
1096            .copied()
1097            .collect();
1098        for (i, (stack_value, canonicalize)) in return_values.into_iter().enumerate() {
1099            let dst = self.value_stack[value_stack_depth_after - i - 1].0;
1100            if let Some(canonicalize_size) = canonicalize.to_size()
1101                && self.config.enable_nan_canonicalization
1102            {
1103                self.machine
1104                    .canonicalize_nan(canonicalize_size, stack_value, dst)?;
1105            } else {
1106                self.machine.emit_relaxed_mov(Size::S64, stack_value, dst)?;
1107            }
1108            self.ensure_output_size_within_limit()?;
1109        }
1110
1111        Ok(())
1112    }
1113
1114    /// Similar to `emit_return_values`, except it stores the `return_values` items into the slots
1115    /// preallocated for parameters of a loop.
1116    fn emit_loop_params_store(
1117        &mut self,
1118        value_stack_depth_after: usize,
1119        param_count: usize,
1120    ) -> Result<(), CompileError> {
1121        let params: SmallVec<[LocationWithCanonicalization<M>; 8]> = self
1122            .value_stack
1123            .iter()
1124            .rev()
1125            .take(param_count)
1126            .rev()
1127            .copied()
1128            .collect();
1129        for (i, (stack_value, canonicalize)) in params.into_iter().enumerate() {
1130            let dst = self.value_stack[value_stack_depth_after + i].0;
1131            if let Some(canonicalize_size) = canonicalize.to_size()
1132                && self.config.enable_nan_canonicalization
1133            {
1134                self.machine
1135                    .canonicalize_nan(canonicalize_size, stack_value, dst)?;
1136            } else {
1137                self.machine.emit_relaxed_mov(Size::S64, stack_value, dst)?;
1138            }
1139            self.ensure_output_size_within_limit()?;
1140        }
1141
1142        Ok(())
1143    }
1144
1145    fn return_types_for_block(&self, block_type: WpTypeOrFuncType) -> SmallVec<[WpType; 1]> {
1146        match block_type {
1147            WpTypeOrFuncType::Empty => smallvec![],
1148            WpTypeOrFuncType::Type(inner_ty) => smallvec![inner_ty],
1149            WpTypeOrFuncType::FuncType(sig_index) => SmallVec::from_iter(
1150                self.module.signatures[SignatureIndex::from_u32(sig_index)]
1151                    .results()
1152                    .iter()
1153                    .map(type_to_wp_type),
1154            ),
1155        }
1156    }
1157
1158    fn param_types_for_block(&self, block_type: WpTypeOrFuncType) -> SmallVec<[WpType; 8]> {
1159        match block_type {
1160            WpTypeOrFuncType::Empty | WpTypeOrFuncType::Type(_) => smallvec![],
1161            WpTypeOrFuncType::FuncType(sig_index) => SmallVec::from_iter(
1162                self.module.signatures[SignatureIndex::from_u32(sig_index)]
1163                    .params()
1164                    .iter()
1165                    .map(type_to_wp_type),
1166            ),
1167        }
1168    }
1169
1170    pub fn feed_operator(&mut self, op: Operator) -> Result<(), CompileError> {
1171        let was_unreachable;
1172
1173        if self.unreachable_depth > 0 {
1174            was_unreachable = true;
1175
1176            match op {
1177                Operator::Block { .. } | Operator::Loop { .. } | Operator::If { .. } => {
1178                    self.unreachable_depth += 1;
1179                }
1180                Operator::End => {
1181                    self.unreachable_depth -= 1;
1182                }
1183                Operator::Else
1184                    if self.unreachable_depth == 1
1185                        && self.control_stack.last().is_some_and(|frame| {
1186                            matches!(frame.state, ControlState::If { .. })
1187                        }) =>
1188                {
1189                    // We are in a reachable true branch
1190                    self.unreachable_depth -= 1;
1191                }
1192
1193                _ => {}
1194            }
1195            if self.unreachable_depth > 0 {
1196                return Ok(());
1197            }
1198        } else {
1199            was_unreachable = false;
1200        }
1201
1202        match op {
1203            Operator::GlobalGet { global_index } => {
1204                let global_index = GlobalIndex::from_u32(global_index);
1205
1206                let ty = type_to_wp_type(&self.module.globals[global_index].ty);
1207                let loc = self.acquire_location(&ty)?;
1208                self.value_stack.push((loc, CanonicalizeType::None));
1209
1210                let (src, tmp) = if let Some(local_global_index) =
1211                    self.module.local_global_index(global_index)
1212                {
1213                    let offset = self.vmoffsets.vmctx_vmglobal_definition(local_global_index);
1214                    (
1215                        Location::Memory(self.machine.get_vmctx_reg(), vmctx_offset(offset)?),
1216                        None,
1217                    )
1218                } else {
1219                    // Imported globals require one level of indirection.
1220                    let tmp = self.machine.acquire_temp_gpr().unwrap();
1221                    let offset = self
1222                        .vmoffsets
1223                        .vmctx_vmglobal_import_definition(global_index);
1224                    self.machine.emit_relaxed_mov(
1225                        Size::S64,
1226                        Location::Memory(self.machine.get_vmctx_reg(), vmctx_offset(offset)?),
1227                        Location::GPR(tmp),
1228                    )?;
1229                    (Location::Memory(tmp, 0), Some(tmp))
1230                };
1231
1232                self.machine.emit_relaxed_mov(Size::S64, src, loc)?;
1233
1234                if let Some(tmp) = tmp {
1235                    self.machine.release_gpr(tmp);
1236                }
1237            }
1238            Operator::GlobalSet { global_index } => {
1239                let global_index = GlobalIndex::from_u32(global_index);
1240                let (dst, tmp) = if let Some(local_global_index) =
1241                    self.module.local_global_index(global_index)
1242                {
1243                    let offset = self.vmoffsets.vmctx_vmglobal_definition(local_global_index);
1244                    (
1245                        Location::Memory(self.machine.get_vmctx_reg(), vmctx_offset(offset)?),
1246                        None,
1247                    )
1248                } else {
1249                    // Imported globals require one level of indirection.
1250                    let tmp = self.machine.acquire_temp_gpr().unwrap();
1251                    let offset = self
1252                        .vmoffsets
1253                        .vmctx_vmglobal_import_definition(global_index);
1254                    self.machine.emit_relaxed_mov(
1255                        Size::S64,
1256                        Location::Memory(self.machine.get_vmctx_reg(), vmctx_offset(offset)?),
1257                        Location::GPR(tmp),
1258                    )?;
1259                    (Location::Memory(tmp, 0), Some(tmp))
1260                };
1261                let (loc, canonicalize) = self.pop_value_released()?;
1262                if let Some(canonicalize_size) = canonicalize.to_size() {
1263                    if self.config.enable_nan_canonicalization {
1264                        self.machine.canonicalize_nan(canonicalize_size, loc, dst)?;
1265                    } else {
1266                        self.machine.emit_relaxed_mov(Size::S64, loc, dst)?;
1267                    }
1268                } else {
1269                    self.machine.emit_relaxed_mov(Size::S64, loc, dst)?;
1270                }
1271                if let Some(tmp) = tmp {
1272                    self.machine.release_gpr(tmp);
1273                }
1274            }
1275            Operator::LocalGet { local_index } => {
1276                let local_index = local_index as usize;
1277                let ret = self.acquire_location(&WpType::I64)?;
1278                self.machine
1279                    .emit_relaxed_mov(Size::S64, self.locals[local_index], ret)?;
1280                self.value_stack.push((ret, CanonicalizeType::None));
1281            }
1282            Operator::LocalSet { local_index } => {
1283                let local_index = local_index as usize;
1284                let (loc, canonicalize) = self.pop_value_released()?;
1285
1286                if self.local_types[local_index].is_float()
1287                    && let Some(canonicalize_size) = canonicalize.to_size()
1288                {
1289                    if self.config.enable_nan_canonicalization {
1290                        self.machine.canonicalize_nan(
1291                            canonicalize_size,
1292                            loc,
1293                            self.locals[local_index],
1294                        )
1295                    } else {
1296                        self.machine
1297                            .emit_relaxed_mov(Size::S64, loc, self.locals[local_index])
1298                    }
1299                } else {
1300                    self.machine
1301                        .emit_relaxed_mov(Size::S64, loc, self.locals[local_index])
1302                }?;
1303            }
1304            Operator::LocalTee { local_index } => {
1305                let local_index = local_index as usize;
1306                let (loc, canonicalize) = *self.value_stack.last().unwrap();
1307
1308                if self.local_types[local_index].is_float()
1309                    && let Some(canonicalize_size) = canonicalize.to_size()
1310                {
1311                    if self.config.enable_nan_canonicalization {
1312                        self.machine.canonicalize_nan(
1313                            canonicalize_size,
1314                            loc,
1315                            self.locals[local_index],
1316                        )
1317                    } else {
1318                        self.machine
1319                            .emit_relaxed_mov(Size::S64, loc, self.locals[local_index])
1320                    }
1321                } else {
1322                    self.machine
1323                        .emit_relaxed_mov(Size::S64, loc, self.locals[local_index])
1324                }?;
1325            }
1326            Operator::I32Const { value } => {
1327                self.value_stack
1328                    .push((Location::Imm32(value as u32), CanonicalizeType::None));
1329            }
1330            Operator::I32Add => {
1331                let I2O1 { loc_a, loc_b, ret } =
1332                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1333                self.machine.emit_binop_add32(loc_a, loc_b, ret)?;
1334            }
1335            Operator::I32Sub => {
1336                let I2O1 { loc_a, loc_b, ret } =
1337                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1338                self.machine.emit_binop_sub32(loc_a, loc_b, ret)?;
1339            }
1340            Operator::I32Mul => {
1341                let I2O1 { loc_a, loc_b, ret } =
1342                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1343                self.machine.emit_binop_mul32(loc_a, loc_b, ret)?;
1344            }
1345            Operator::I32DivU => {
1346                let I2O1 { loc_a, loc_b, ret } =
1347                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1348                self.machine.emit_binop_udiv32(
1349                    loc_a,
1350                    loc_b,
1351                    ret,
1352                    self.special_labels.integer_division_by_zero,
1353                )?;
1354            }
1355            Operator::I32DivS => {
1356                let I2O1 { loc_a, loc_b, ret } =
1357                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1358                self.machine.emit_binop_sdiv32(
1359                    loc_a,
1360                    loc_b,
1361                    ret,
1362                    self.special_labels.integer_division_by_zero,
1363                    self.special_labels.integer_overflow,
1364                )?;
1365            }
1366            Operator::I32RemU => {
1367                let I2O1 { loc_a, loc_b, ret } =
1368                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1369                self.machine.emit_binop_urem32(
1370                    loc_a,
1371                    loc_b,
1372                    ret,
1373                    self.special_labels.integer_division_by_zero,
1374                )?;
1375            }
1376            Operator::I32RemS => {
1377                let I2O1 { loc_a, loc_b, ret } =
1378                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1379                self.machine.emit_binop_srem32(
1380                    loc_a,
1381                    loc_b,
1382                    ret,
1383                    self.special_labels.integer_division_by_zero,
1384                )?;
1385            }
1386            Operator::I32And => {
1387                let I2O1 { loc_a, loc_b, ret } =
1388                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1389                self.machine.emit_binop_and32(loc_a, loc_b, ret)?;
1390            }
1391            Operator::I32Or => {
1392                let I2O1 { loc_a, loc_b, ret } =
1393                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1394                self.machine.emit_binop_or32(loc_a, loc_b, ret)?;
1395            }
1396            Operator::I32Xor => {
1397                let I2O1 { loc_a, loc_b, ret } =
1398                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1399                self.machine.emit_binop_xor32(loc_a, loc_b, ret)?;
1400            }
1401            Operator::I32Eq => {
1402                let I2O1 { loc_a, loc_b, ret } =
1403                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1404                self.machine.i32_cmp_eq(loc_a, loc_b, ret)?;
1405            }
1406            Operator::I32Ne => {
1407                let I2O1 { loc_a, loc_b, ret } =
1408                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1409                self.machine.i32_cmp_ne(loc_a, loc_b, ret)?;
1410            }
1411            Operator::I32Eqz => {
1412                let loc_a = self.pop_value_released()?.0;
1413                let ret = self.acquire_location(&WpType::I32)?;
1414                self.machine.i32_cmp_eq(loc_a, Location::Imm32(0), ret)?;
1415                self.value_stack.push((ret, CanonicalizeType::None));
1416            }
1417            Operator::I32Clz => {
1418                let loc = self.pop_value_released()?.0;
1419                let ret = self.acquire_location(&WpType::I32)?;
1420                self.value_stack.push((ret, CanonicalizeType::None));
1421                self.machine.i32_clz(loc, ret)?;
1422            }
1423            Operator::I32Ctz => {
1424                let loc = self.pop_value_released()?.0;
1425                let ret = self.acquire_location(&WpType::I32)?;
1426                self.value_stack.push((ret, CanonicalizeType::None));
1427                self.machine.i32_ctz(loc, ret)?;
1428            }
1429            Operator::I32Popcnt => {
1430                let loc = self.pop_value_released()?.0;
1431                let ret = self.acquire_location(&WpType::I32)?;
1432                self.value_stack.push((ret, CanonicalizeType::None));
1433                self.machine.i32_popcnt(loc, ret)?;
1434            }
1435            Operator::I32Shl => {
1436                let I2O1 { loc_a, loc_b, ret } =
1437                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1438                self.machine.i32_shl(loc_a, loc_b, ret)?;
1439            }
1440            Operator::I32ShrU => {
1441                let I2O1 { loc_a, loc_b, ret } =
1442                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1443                self.machine.i32_shr(loc_a, loc_b, ret)?;
1444            }
1445            Operator::I32ShrS => {
1446                let I2O1 { loc_a, loc_b, ret } =
1447                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1448                self.machine.i32_sar(loc_a, loc_b, ret)?;
1449            }
1450            Operator::I32Rotl => {
1451                let I2O1 { loc_a, loc_b, ret } =
1452                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1453                self.machine.i32_rol(loc_a, loc_b, ret)?;
1454            }
1455            Operator::I32Rotr => {
1456                let I2O1 { loc_a, loc_b, ret } =
1457                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1458                self.machine.i32_ror(loc_a, loc_b, ret)?;
1459            }
1460            Operator::I32LtU => {
1461                let I2O1 { loc_a, loc_b, ret } =
1462                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1463                self.machine.i32_cmp_lt_u(loc_a, loc_b, ret)?;
1464            }
1465            Operator::I32LeU => {
1466                let I2O1 { loc_a, loc_b, ret } =
1467                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1468                self.machine.i32_cmp_le_u(loc_a, loc_b, ret)?;
1469            }
1470            Operator::I32GtU => {
1471                let I2O1 { loc_a, loc_b, ret } =
1472                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1473                self.machine.i32_cmp_gt_u(loc_a, loc_b, ret)?;
1474            }
1475            Operator::I32GeU => {
1476                let I2O1 { loc_a, loc_b, ret } =
1477                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1478                self.machine.i32_cmp_ge_u(loc_a, loc_b, ret)?;
1479            }
1480            Operator::I32LtS => {
1481                let I2O1 { loc_a, loc_b, ret } =
1482                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1483                self.machine.i32_cmp_lt_s(loc_a, loc_b, ret)?;
1484            }
1485            Operator::I32LeS => {
1486                let I2O1 { loc_a, loc_b, ret } =
1487                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1488                self.machine.i32_cmp_le_s(loc_a, loc_b, ret)?;
1489            }
1490            Operator::I32GtS => {
1491                let I2O1 { loc_a, loc_b, ret } =
1492                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1493                self.machine.i32_cmp_gt_s(loc_a, loc_b, ret)?;
1494            }
1495            Operator::I32GeS => {
1496                let I2O1 { loc_a, loc_b, ret } =
1497                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1498                self.machine.i32_cmp_ge_s(loc_a, loc_b, ret)?;
1499            }
1500            Operator::I64Const { value } => {
1501                let value = value as u64;
1502                self.value_stack
1503                    .push((Location::Imm64(value), CanonicalizeType::None));
1504            }
1505            Operator::I64Add => {
1506                let I2O1 { loc_a, loc_b, ret } =
1507                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1508                self.machine.emit_binop_add64(loc_a, loc_b, ret)?;
1509            }
1510            Operator::I64Sub => {
1511                let I2O1 { loc_a, loc_b, ret } =
1512                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1513                self.machine.emit_binop_sub64(loc_a, loc_b, ret)?;
1514            }
1515            Operator::I64Mul => {
1516                let I2O1 { loc_a, loc_b, ret } =
1517                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1518                self.machine.emit_binop_mul64(loc_a, loc_b, ret)?;
1519            }
1520            Operator::I64DivU => {
1521                let I2O1 { loc_a, loc_b, ret } =
1522                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1523                self.machine.emit_binop_udiv64(
1524                    loc_a,
1525                    loc_b,
1526                    ret,
1527                    self.special_labels.integer_division_by_zero,
1528                )?;
1529            }
1530            Operator::I64DivS => {
1531                let I2O1 { loc_a, loc_b, ret } =
1532                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1533                self.machine.emit_binop_sdiv64(
1534                    loc_a,
1535                    loc_b,
1536                    ret,
1537                    self.special_labels.integer_division_by_zero,
1538                    self.special_labels.integer_overflow,
1539                )?;
1540            }
1541            Operator::I64RemU => {
1542                let I2O1 { loc_a, loc_b, ret } =
1543                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1544                self.machine.emit_binop_urem64(
1545                    loc_a,
1546                    loc_b,
1547                    ret,
1548                    self.special_labels.integer_division_by_zero,
1549                )?;
1550            }
1551            Operator::I64RemS => {
1552                let I2O1 { loc_a, loc_b, ret } =
1553                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1554                self.machine.emit_binop_srem64(
1555                    loc_a,
1556                    loc_b,
1557                    ret,
1558                    self.special_labels.integer_division_by_zero,
1559                )?;
1560            }
1561            Operator::I64And => {
1562                let I2O1 { loc_a, loc_b, ret } =
1563                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1564                self.machine.emit_binop_and64(loc_a, loc_b, ret)?;
1565            }
1566            Operator::I64Or => {
1567                let I2O1 { loc_a, loc_b, ret } =
1568                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1569                self.machine.emit_binop_or64(loc_a, loc_b, ret)?;
1570            }
1571            Operator::I64Xor => {
1572                let I2O1 { loc_a, loc_b, ret } =
1573                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1574                self.machine.emit_binop_xor64(loc_a, loc_b, ret)?;
1575            }
1576            Operator::I64Eq => {
1577                let I2O1 { loc_a, loc_b, ret } =
1578                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1579                self.machine.i64_cmp_eq(loc_a, loc_b, ret)?;
1580            }
1581            Operator::I64Ne => {
1582                let I2O1 { loc_a, loc_b, ret } =
1583                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1584                self.machine.i64_cmp_ne(loc_a, loc_b, ret)?;
1585            }
1586            Operator::I64Eqz => {
1587                let loc_a = self.pop_value_released()?.0;
1588                let ret = self.acquire_location(&WpType::I64)?;
1589                self.machine.i64_cmp_eq(loc_a, Location::Imm64(0), ret)?;
1590                self.value_stack.push((ret, CanonicalizeType::None));
1591            }
1592            Operator::I64Clz => {
1593                let loc = self.pop_value_released()?.0;
1594                let ret = self.acquire_location(&WpType::I64)?;
1595                self.value_stack.push((ret, CanonicalizeType::None));
1596                self.machine.i64_clz(loc, ret)?;
1597            }
1598            Operator::I64Ctz => {
1599                let loc = self.pop_value_released()?.0;
1600                let ret = self.acquire_location(&WpType::I64)?;
1601                self.value_stack.push((ret, CanonicalizeType::None));
1602                self.machine.i64_ctz(loc, ret)?;
1603            }
1604            Operator::I64Popcnt => {
1605                let loc = self.pop_value_released()?.0;
1606                let ret = self.acquire_location(&WpType::I64)?;
1607                self.value_stack.push((ret, CanonicalizeType::None));
1608                self.machine.i64_popcnt(loc, ret)?;
1609            }
1610            Operator::I64Shl => {
1611                let I2O1 { loc_a, loc_b, ret } =
1612                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1613                self.machine.i64_shl(loc_a, loc_b, ret)?;
1614            }
1615            Operator::I64ShrU => {
1616                let I2O1 { loc_a, loc_b, ret } =
1617                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1618                self.machine.i64_shr(loc_a, loc_b, ret)?;
1619            }
1620            Operator::I64ShrS => {
1621                let I2O1 { loc_a, loc_b, ret } =
1622                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1623                self.machine.i64_sar(loc_a, loc_b, ret)?;
1624            }
1625            Operator::I64Rotl => {
1626                let I2O1 { loc_a, loc_b, ret } =
1627                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1628                self.machine.i64_rol(loc_a, loc_b, ret)?;
1629            }
1630            Operator::I64Rotr => {
1631                let I2O1 { loc_a, loc_b, ret } =
1632                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1633                self.machine.i64_ror(loc_a, loc_b, ret)?;
1634            }
1635            Operator::I64LtU => {
1636                let I2O1 { loc_a, loc_b, ret } =
1637                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1638                self.machine.i64_cmp_lt_u(loc_a, loc_b, ret)?;
1639            }
1640            Operator::I64LeU => {
1641                let I2O1 { loc_a, loc_b, ret } =
1642                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1643                self.machine.i64_cmp_le_u(loc_a, loc_b, ret)?;
1644            }
1645            Operator::I64GtU => {
1646                let I2O1 { loc_a, loc_b, ret } =
1647                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1648                self.machine.i64_cmp_gt_u(loc_a, loc_b, ret)?;
1649            }
1650            Operator::I64GeU => {
1651                let I2O1 { loc_a, loc_b, ret } =
1652                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1653                self.machine.i64_cmp_ge_u(loc_a, loc_b, ret)?;
1654            }
1655            Operator::I64LtS => {
1656                let I2O1 { loc_a, loc_b, ret } =
1657                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1658                self.machine.i64_cmp_lt_s(loc_a, loc_b, ret)?;
1659            }
1660            Operator::I64LeS => {
1661                let I2O1 { loc_a, loc_b, ret } =
1662                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1663                self.machine.i64_cmp_le_s(loc_a, loc_b, ret)?;
1664            }
1665            Operator::I64GtS => {
1666                let I2O1 { loc_a, loc_b, ret } =
1667                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1668                self.machine.i64_cmp_gt_s(loc_a, loc_b, ret)?;
1669            }
1670            Operator::I64GeS => {
1671                let I2O1 { loc_a, loc_b, ret } =
1672                    self.i2o1_prepare(WpType::I64, CanonicalizeType::None)?;
1673                self.machine.i64_cmp_ge_s(loc_a, loc_b, ret)?;
1674            }
1675            Operator::I64ExtendI32U => {
1676                let loc = self.pop_value_released()?.0;
1677                let ret = self.acquire_location(&WpType::I64)?;
1678                self.value_stack.push((ret, CanonicalizeType::None));
1679                self.machine.emit_relaxed_mov(Size::S32, loc, ret)?;
1680
1681                // A 32-bit memory write does not automatically clear the upper 32 bits of a 64-bit word.
1682                // So, we need to explicitly write zero to the upper half here.
1683                if let Location::Memory(base, off) = ret {
1684                    self.machine.emit_relaxed_mov(
1685                        Size::S32,
1686                        Location::Imm32(0),
1687                        Location::Memory(base, off + 4),
1688                    )?;
1689                }
1690            }
1691            Operator::I64ExtendI32S => {
1692                let loc = self.pop_value_released()?.0;
1693                let ret = self.acquire_location(&WpType::I64)?;
1694                self.value_stack.push((ret, CanonicalizeType::None));
1695                self.machine
1696                    .emit_relaxed_sign_extension(Size::S32, loc, Size::S64, ret)?;
1697            }
1698            Operator::I32Extend8S => {
1699                let loc = self.pop_value_released()?.0;
1700                let ret = self.acquire_location(&WpType::I32)?;
1701                self.value_stack.push((ret, CanonicalizeType::None));
1702
1703                self.machine
1704                    .emit_relaxed_sign_extension(Size::S8, loc, Size::S32, ret)?;
1705            }
1706            Operator::I32Extend16S => {
1707                let loc = self.pop_value_released()?.0;
1708                let ret = self.acquire_location(&WpType::I32)?;
1709                self.value_stack.push((ret, CanonicalizeType::None));
1710
1711                self.machine
1712                    .emit_relaxed_sign_extension(Size::S16, loc, Size::S32, ret)?;
1713            }
1714            Operator::I64Extend8S => {
1715                let loc = self.pop_value_released()?.0;
1716                let ret = self.acquire_location(&WpType::I64)?;
1717                self.value_stack.push((ret, CanonicalizeType::None));
1718
1719                self.machine
1720                    .emit_relaxed_sign_extension(Size::S8, loc, Size::S64, ret)?;
1721            }
1722            Operator::I64Extend16S => {
1723                let loc = self.pop_value_released()?.0;
1724                let ret = self.acquire_location(&WpType::I64)?;
1725                self.value_stack.push((ret, CanonicalizeType::None));
1726
1727                self.machine
1728                    .emit_relaxed_sign_extension(Size::S16, loc, Size::S64, ret)?;
1729            }
1730            Operator::I64Extend32S => {
1731                let loc = self.pop_value_released()?.0;
1732                let ret = self.acquire_location(&WpType::I64)?;
1733                self.value_stack.push((ret, CanonicalizeType::None));
1734
1735                self.machine
1736                    .emit_relaxed_sign_extension(Size::S32, loc, Size::S64, ret)?;
1737            }
1738            Operator::I32WrapI64 => {
1739                let loc = self.pop_value_released()?.0;
1740                let ret = self.acquire_location(&WpType::I32)?;
1741                self.value_stack.push((ret, CanonicalizeType::None));
1742                self.machine.emit_relaxed_mov(Size::S32, loc, ret)?;
1743            }
1744
1745            Operator::F32Const { value } => {
1746                self.value_stack
1747                    .push((Location::Imm32(value.bits()), CanonicalizeType::None));
1748            }
1749            Operator::F32Add => {
1750                let I2O1 { loc_a, loc_b, ret } =
1751                    self.i2o1_prepare(WpType::F64, CanonicalizeType::F32)?;
1752                self.machine.f32_add(loc_a, loc_b, ret)?;
1753            }
1754            Operator::F32Sub => {
1755                let I2O1 { loc_a, loc_b, ret } =
1756                    self.i2o1_prepare(WpType::F64, CanonicalizeType::F32)?;
1757                self.machine.f32_sub(loc_a, loc_b, ret)?;
1758            }
1759            Operator::F32Mul => {
1760                let I2O1 { loc_a, loc_b, ret } =
1761                    self.i2o1_prepare(WpType::F64, CanonicalizeType::F32)?;
1762                self.machine.f32_mul(loc_a, loc_b, ret)?;
1763            }
1764            Operator::F32Div => {
1765                let I2O1 { loc_a, loc_b, ret } =
1766                    self.i2o1_prepare(WpType::F64, CanonicalizeType::F32)?;
1767                self.machine.f32_div(loc_a, loc_b, ret)?;
1768            }
1769            Operator::F32Max => {
1770                let I2O1 { loc_a, loc_b, ret } =
1771                    self.i2o1_prepare(WpType::F64, CanonicalizeType::None)?;
1772                self.machine.f32_max(loc_a, loc_b, ret)?;
1773            }
1774            Operator::F32Min => {
1775                let I2O1 { loc_a, loc_b, ret } =
1776                    self.i2o1_prepare(WpType::F64, CanonicalizeType::None)?;
1777                self.machine.f32_min(loc_a, loc_b, ret)?;
1778            }
1779            Operator::F32Eq => {
1780                let I2O1 { loc_a, loc_b, ret } =
1781                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1782                self.machine.f32_cmp_eq(loc_a, loc_b, ret)?;
1783            }
1784            Operator::F32Ne => {
1785                let I2O1 { loc_a, loc_b, ret } =
1786                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1787                self.machine.f32_cmp_ne(loc_a, loc_b, ret)?;
1788            }
1789            Operator::F32Lt => {
1790                let I2O1 { loc_a, loc_b, ret } =
1791                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1792                self.machine.f32_cmp_lt(loc_a, loc_b, ret)?;
1793            }
1794            Operator::F32Le => {
1795                let I2O1 { loc_a, loc_b, ret } =
1796                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1797                self.machine.f32_cmp_le(loc_a, loc_b, ret)?;
1798            }
1799            Operator::F32Gt => {
1800                let I2O1 { loc_a, loc_b, ret } =
1801                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1802                self.machine.f32_cmp_gt(loc_a, loc_b, ret)?;
1803            }
1804            Operator::F32Ge => {
1805                let I2O1 { loc_a, loc_b, ret } =
1806                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1807                self.machine.f32_cmp_ge(loc_a, loc_b, ret)?;
1808            }
1809            Operator::F32Nearest => {
1810                let loc = self.pop_value_released()?.0;
1811                let ret = self.acquire_location(&WpType::F64)?;
1812                self.value_stack.push((ret, CanonicalizeType::F32));
1813                self.machine.f32_nearest(loc, ret)?;
1814            }
1815            Operator::F32Floor => {
1816                let loc = self.pop_value_released()?.0;
1817                let ret = self.acquire_location(&WpType::F64)?;
1818                self.value_stack.push((ret, CanonicalizeType::F32));
1819                self.machine.f32_floor(loc, ret)?;
1820            }
1821            Operator::F32Ceil => {
1822                let loc = self.pop_value_released()?.0;
1823                let ret = self.acquire_location(&WpType::F64)?;
1824                self.value_stack.push((ret, CanonicalizeType::F32));
1825                self.machine.f32_ceil(loc, ret)?;
1826            }
1827            Operator::F32Trunc => {
1828                let loc = self.pop_value_released()?.0;
1829                let ret = self.acquire_location(&WpType::F64)?;
1830                self.value_stack.push((ret, CanonicalizeType::F32));
1831                self.machine.f32_trunc(loc, ret)?;
1832            }
1833            Operator::F32Sqrt => {
1834                let loc = self.pop_value_released()?.0;
1835                let ret = self.acquire_location(&WpType::F64)?;
1836                self.value_stack.push((ret, CanonicalizeType::F32));
1837                self.machine.f32_sqrt(loc, ret)?;
1838            }
1839
1840            Operator::F32Copysign => {
1841                let loc_b = self.pop_value_released()?;
1842                let loc_a = self.pop_value_released()?;
1843                let ret = self.acquire_location(&WpType::F32)?;
1844                self.value_stack.push((ret, CanonicalizeType::None));
1845
1846                let tmp1 = self.machine.acquire_temp_gpr().unwrap();
1847                let tmp2 = self.machine.acquire_temp_gpr().unwrap();
1848
1849                if self.config.enable_nan_canonicalization {
1850                    for ((loc, fp), tmp) in [(loc_a, tmp1), (loc_b, tmp2)] {
1851                        if fp.to_size().is_some() {
1852                            self.machine
1853                                .canonicalize_nan(Size::S32, loc, Location::GPR(tmp))?
1854                        } else {
1855                            self.machine
1856                                .move_location(Size::S32, loc, Location::GPR(tmp))?
1857                        }
1858                    }
1859                } else {
1860                    self.machine
1861                        .move_location(Size::S32, loc_a.0, Location::GPR(tmp1))?;
1862                    self.machine
1863                        .move_location(Size::S32, loc_b.0, Location::GPR(tmp2))?;
1864                }
1865                self.machine.emit_i32_copysign(tmp1, tmp2)?;
1866                self.machine
1867                    .move_location(Size::S32, Location::GPR(tmp1), ret)?;
1868                self.machine.release_gpr(tmp2);
1869                self.machine.release_gpr(tmp1);
1870            }
1871
1872            Operator::F32Abs => {
1873                let (loc, canonicalize) = self.pop_value_released()?;
1874                let ret = self.acquire_location(&WpType::F32)?;
1875                self.value_stack.push((ret, canonicalize));
1876
1877                self.machine.f32_abs(loc, ret)?;
1878            }
1879
1880            Operator::F32Neg => {
1881                let (loc, mut canonicalize) = self.pop_value_released()?;
1882                let ret = self.acquire_location(&WpType::F32)?;
1883
1884                if self.config.enable_nan_canonicalization
1885                    && let Some(canonicalize_size) = canonicalize.to_size()
1886                {
1887                    self.machine.canonicalize_nan(canonicalize_size, loc, ret)?;
1888                    self.machine.f32_neg(ret, ret)?;
1889                    canonicalize = CanonicalizeType::None;
1890                } else {
1891                    self.machine.f32_neg(loc, ret)?;
1892                }
1893                self.value_stack.push((ret, canonicalize));
1894            }
1895
1896            Operator::F64Const { value } => {
1897                self.value_stack
1898                    .push((Location::Imm64(value.bits()), CanonicalizeType::None));
1899            }
1900            Operator::F64Add => {
1901                let I2O1 { loc_a, loc_b, ret } =
1902                    self.i2o1_prepare(WpType::F64, CanonicalizeType::F64)?;
1903                self.machine.f64_add(loc_a, loc_b, ret)?;
1904            }
1905            Operator::F64Sub => {
1906                let I2O1 { loc_a, loc_b, ret } =
1907                    self.i2o1_prepare(WpType::F64, CanonicalizeType::F64)?;
1908                self.machine.f64_sub(loc_a, loc_b, ret)?;
1909            }
1910            Operator::F64Mul => {
1911                let I2O1 { loc_a, loc_b, ret } =
1912                    self.i2o1_prepare(WpType::F64, CanonicalizeType::F64)?;
1913                self.machine.f64_mul(loc_a, loc_b, ret)?;
1914            }
1915            Operator::F64Div => {
1916                let I2O1 { loc_a, loc_b, ret } =
1917                    self.i2o1_prepare(WpType::F64, CanonicalizeType::F64)?;
1918                self.machine.f64_div(loc_a, loc_b, ret)?;
1919            }
1920            Operator::F64Max => {
1921                let I2O1 { loc_a, loc_b, ret } =
1922                    self.i2o1_prepare(WpType::F64, CanonicalizeType::None)?;
1923                self.machine.f64_max(loc_a, loc_b, ret)?;
1924            }
1925            Operator::F64Min => {
1926                let I2O1 { loc_a, loc_b, ret } =
1927                    self.i2o1_prepare(WpType::F64, CanonicalizeType::None)?;
1928                self.machine.f64_min(loc_a, loc_b, ret)?;
1929            }
1930            Operator::F64Eq => {
1931                let I2O1 { loc_a, loc_b, ret } =
1932                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1933                self.machine.f64_cmp_eq(loc_a, loc_b, ret)?;
1934            }
1935            Operator::F64Ne => {
1936                let I2O1 { loc_a, loc_b, ret } =
1937                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1938                self.machine.f64_cmp_ne(loc_a, loc_b, ret)?;
1939            }
1940            Operator::F64Lt => {
1941                let I2O1 { loc_a, loc_b, ret } =
1942                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1943                self.machine.f64_cmp_lt(loc_a, loc_b, ret)?;
1944            }
1945            Operator::F64Le => {
1946                let I2O1 { loc_a, loc_b, ret } =
1947                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1948                self.machine.f64_cmp_le(loc_a, loc_b, ret)?;
1949            }
1950            Operator::F64Gt => {
1951                let I2O1 { loc_a, loc_b, ret } =
1952                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1953                self.machine.f64_cmp_gt(loc_a, loc_b, ret)?;
1954            }
1955            Operator::F64Ge => {
1956                let I2O1 { loc_a, loc_b, ret } =
1957                    self.i2o1_prepare(WpType::I32, CanonicalizeType::None)?;
1958                self.machine.f64_cmp_ge(loc_a, loc_b, ret)?;
1959            }
1960            Operator::F64Nearest => {
1961                let loc = self.pop_value_released()?.0;
1962                let ret = self.acquire_location(&WpType::F64)?;
1963                self.value_stack.push((ret, CanonicalizeType::F64));
1964                self.machine.f64_nearest(loc, ret)?;
1965            }
1966            Operator::F64Floor => {
1967                let loc = self.pop_value_released()?.0;
1968                let ret = self.acquire_location(&WpType::F64)?;
1969                self.value_stack.push((ret, CanonicalizeType::F64));
1970                self.machine.f64_floor(loc, ret)?;
1971            }
1972            Operator::F64Ceil => {
1973                let loc = self.pop_value_released()?.0;
1974                let ret = self.acquire_location(&WpType::F64)?;
1975                self.value_stack.push((ret, CanonicalizeType::F64));
1976                self.machine.f64_ceil(loc, ret)?;
1977            }
1978            Operator::F64Trunc => {
1979                let loc = self.pop_value_released()?.0;
1980                let ret = self.acquire_location(&WpType::F64)?;
1981                self.value_stack.push((ret, CanonicalizeType::F64));
1982                self.machine.f64_trunc(loc, ret)?;
1983            }
1984            Operator::F64Sqrt => {
1985                let loc = self.pop_value_released()?.0;
1986                let ret = self.acquire_location(&WpType::F64)?;
1987                self.value_stack.push((ret, CanonicalizeType::F64));
1988                self.machine.f64_sqrt(loc, ret)?;
1989            }
1990
1991            Operator::F64Copysign => {
1992                let loc_b = self.pop_value_released()?;
1993                let loc_a = self.pop_value_released()?;
1994                let ret = self.acquire_location(&WpType::F64)?;
1995                self.value_stack.push((ret, CanonicalizeType::None));
1996
1997                let tmp1 = self.machine.acquire_temp_gpr().unwrap();
1998                let tmp2 = self.machine.acquire_temp_gpr().unwrap();
1999
2000                if self.config.enable_nan_canonicalization {
2001                    for ((loc, fp), tmp) in [(loc_a, tmp1), (loc_b, tmp2)] {
2002                        if fp.to_size().is_some() {
2003                            self.machine
2004                                .canonicalize_nan(Size::S64, loc, Location::GPR(tmp))?
2005                        } else {
2006                            self.machine
2007                                .move_location(Size::S64, loc, Location::GPR(tmp))?
2008                        }
2009                    }
2010                } else {
2011                    self.machine
2012                        .move_location(Size::S64, loc_a.0, Location::GPR(tmp1))?;
2013                    self.machine
2014                        .move_location(Size::S64, loc_b.0, Location::GPR(tmp2))?;
2015                }
2016                self.machine.emit_i64_copysign(tmp1, tmp2)?;
2017                self.machine
2018                    .move_location(Size::S64, Location::GPR(tmp1), ret)?;
2019
2020                self.machine.release_gpr(tmp2);
2021                self.machine.release_gpr(tmp1);
2022            }
2023
2024            Operator::F64Abs => {
2025                let (loc, canonicalize) = self.pop_value_released()?;
2026                let ret = self.acquire_location(&WpType::F64)?;
2027                self.value_stack.push((ret, canonicalize));
2028
2029                self.machine.f64_abs(loc, ret)?;
2030            }
2031
2032            Operator::F64Neg => {
2033                let (loc, canonicalize) = self.pop_value_released()?;
2034                let ret = self.acquire_location(&WpType::F64)?;
2035                self.value_stack.push((ret, canonicalize));
2036
2037                self.machine.f64_neg(loc, ret)?;
2038            }
2039
2040            Operator::F64PromoteF32 => {
2041                let (loc, canonicalize) = self.pop_value_released()?;
2042                let ret = self.acquire_location(&WpType::F64)?;
2043                self.value_stack.push((ret, CanonicalizeType::None));
2044                if self.config.enable_nan_canonicalization
2045                    && let Some(canonicalize_size) = canonicalize.to_size()
2046                {
2047                    self.machine.canonicalize_nan(canonicalize_size, loc, ret)?;
2048                    self.machine.convert_f64_f32(ret, ret)?;
2049                } else {
2050                    self.machine.convert_f64_f32(loc, ret)?;
2051                }
2052            }
2053            Operator::F32DemoteF64 => {
2054                let (loc, canonicalize) = self.pop_value_released()?;
2055                let ret = self.acquire_location(&WpType::F32)?;
2056                self.value_stack.push((ret, CanonicalizeType::None));
2057                if self.config.enable_nan_canonicalization
2058                    && let Some(canonicalize_size) = canonicalize.to_size()
2059                {
2060                    self.machine.canonicalize_nan(canonicalize_size, loc, ret)?;
2061                    self.machine.convert_f32_f64(ret, ret)?;
2062                } else {
2063                    self.machine.convert_f32_f64(loc, ret)?;
2064                }
2065            }
2066
2067            Operator::I32ReinterpretF32 => {
2068                let (loc, canonicalize) = self.pop_value_released()?;
2069                let ret = self.acquire_location(&WpType::I32)?;
2070                self.value_stack.push((ret, CanonicalizeType::None));
2071
2072                if !self.config.enable_nan_canonicalization
2073                    || matches!(canonicalize, CanonicalizeType::None)
2074                {
2075                    if loc != ret {
2076                        self.machine.emit_relaxed_mov(Size::S32, loc, ret)?;
2077                    }
2078                } else {
2079                    self.machine.canonicalize_nan(Size::S32, loc, ret)?;
2080                }
2081            }
2082            Operator::F32ReinterpretI32 => {
2083                let loc = self.pop_value_released()?.0;
2084                let ret = self.acquire_location(&WpType::F32)?;
2085                self.value_stack.push((ret, CanonicalizeType::None));
2086
2087                if loc != ret {
2088                    self.machine.emit_relaxed_mov(Size::S32, loc, ret)?;
2089                }
2090            }
2091
2092            Operator::I64ReinterpretF64 => {
2093                let (loc, canonicalize) = self.pop_value_released()?;
2094                let ret = self.acquire_location(&WpType::I64)?;
2095                self.value_stack.push((ret, CanonicalizeType::None));
2096
2097                if !self.config.enable_nan_canonicalization
2098                    || matches!(canonicalize, CanonicalizeType::None)
2099                {
2100                    if loc != ret {
2101                        self.machine.emit_relaxed_mov(Size::S64, loc, ret)?;
2102                    }
2103                } else {
2104                    self.machine.canonicalize_nan(Size::S64, loc, ret)?;
2105                }
2106            }
2107            Operator::F64ReinterpretI64 => {
2108                let loc = self.pop_value_released()?.0;
2109                let ret = self.acquire_location(&WpType::F64)?;
2110                self.value_stack.push((ret, CanonicalizeType::None));
2111
2112                if loc != ret {
2113                    self.machine.emit_relaxed_mov(Size::S64, loc, ret)?;
2114                }
2115            }
2116
2117            Operator::I32TruncF32U => {
2118                let loc = self.pop_value_released()?.0;
2119                let ret = self.acquire_location(&WpType::I32)?;
2120                self.value_stack.push((ret, CanonicalizeType::None));
2121
2122                self.machine.convert_i32_f32(loc, ret, false, false)?;
2123            }
2124
2125            Operator::I32TruncSatF32U => {
2126                let loc = self.pop_value_released()?.0;
2127                let ret = self.acquire_location(&WpType::I32)?;
2128                self.value_stack.push((ret, CanonicalizeType::None));
2129
2130                self.machine.convert_i32_f32(loc, ret, false, true)?;
2131            }
2132
2133            Operator::I32TruncF32S => {
2134                let loc = self.pop_value_released()?.0;
2135                let ret = self.acquire_location(&WpType::I32)?;
2136                self.value_stack.push((ret, CanonicalizeType::None));
2137
2138                self.machine.convert_i32_f32(loc, ret, true, false)?;
2139            }
2140            Operator::I32TruncSatF32S => {
2141                let loc = self.pop_value_released()?.0;
2142                let ret = self.acquire_location(&WpType::I32)?;
2143                self.value_stack.push((ret, CanonicalizeType::None));
2144
2145                self.machine.convert_i32_f32(loc, ret, true, true)?;
2146            }
2147
2148            Operator::I64TruncF32S => {
2149                let loc = self.pop_value_released()?.0;
2150                let ret = self.acquire_location(&WpType::I64)?;
2151                self.value_stack.push((ret, CanonicalizeType::None));
2152
2153                self.machine.convert_i64_f32(loc, ret, true, false)?;
2154            }
2155
2156            Operator::I64TruncSatF32S => {
2157                let loc = self.pop_value_released()?.0;
2158                let ret = self.acquire_location(&WpType::I64)?;
2159                self.value_stack.push((ret, CanonicalizeType::None));
2160
2161                self.machine.convert_i64_f32(loc, ret, true, true)?;
2162            }
2163
2164            Operator::I64TruncF32U => {
2165                let loc = self.pop_value_released()?.0;
2166                let ret = self.acquire_location(&WpType::I64)?;
2167                self.value_stack.push((ret, CanonicalizeType::None));
2168
2169                self.machine.convert_i64_f32(loc, ret, false, false)?;
2170            }
2171            Operator::I64TruncSatF32U => {
2172                let loc = self.pop_value_released()?.0;
2173                let ret = self.acquire_location(&WpType::I64)?;
2174                self.value_stack.push((ret, CanonicalizeType::None));
2175
2176                self.machine.convert_i64_f32(loc, ret, false, true)?;
2177            }
2178
2179            Operator::I32TruncF64U => {
2180                let loc = self.pop_value_released()?.0;
2181                let ret = self.acquire_location(&WpType::I32)?;
2182                self.value_stack.push((ret, CanonicalizeType::None));
2183
2184                self.machine.convert_i32_f64(loc, ret, false, false)?;
2185            }
2186
2187            Operator::I32TruncSatF64U => {
2188                let loc = self.pop_value_released()?.0;
2189                let ret = self.acquire_location(&WpType::I32)?;
2190                self.value_stack.push((ret, CanonicalizeType::None));
2191
2192                self.machine.convert_i32_f64(loc, ret, false, true)?;
2193            }
2194
2195            Operator::I32TruncF64S => {
2196                let loc = self.pop_value_released()?.0;
2197                let ret = self.acquire_location(&WpType::I32)?;
2198                self.value_stack.push((ret, CanonicalizeType::None));
2199
2200                self.machine.convert_i32_f64(loc, ret, true, false)?;
2201            }
2202
2203            Operator::I32TruncSatF64S => {
2204                let loc = self.pop_value_released()?.0;
2205                let ret = self.acquire_location(&WpType::I32)?;
2206                self.value_stack.push((ret, CanonicalizeType::None));
2207
2208                self.machine.convert_i32_f64(loc, ret, true, true)?;
2209            }
2210
2211            Operator::I64TruncF64S => {
2212                let loc = self.pop_value_released()?.0;
2213                let ret = self.acquire_location(&WpType::I64)?;
2214                self.value_stack.push((ret, CanonicalizeType::None));
2215
2216                self.machine.convert_i64_f64(loc, ret, true, false)?;
2217            }
2218
2219            Operator::I64TruncSatF64S => {
2220                let loc = self.pop_value_released()?.0;
2221                let ret = self.acquire_location(&WpType::I64)?;
2222                self.value_stack.push((ret, CanonicalizeType::None));
2223
2224                self.machine.convert_i64_f64(loc, ret, true, true)?;
2225            }
2226
2227            Operator::I64TruncF64U => {
2228                let loc = self.pop_value_released()?.0;
2229                let ret = self.acquire_location(&WpType::I64)?;
2230                self.value_stack.push((ret, CanonicalizeType::None));
2231
2232                self.machine.convert_i64_f64(loc, ret, false, false)?;
2233            }
2234
2235            Operator::I64TruncSatF64U => {
2236                let loc = self.pop_value_released()?.0;
2237                let ret = self.acquire_location(&WpType::I64)?;
2238                self.value_stack.push((ret, CanonicalizeType::None));
2239
2240                self.machine.convert_i64_f64(loc, ret, false, true)?;
2241            }
2242
2243            Operator::F32ConvertI32S => {
2244                let loc = self.pop_value_released()?.0;
2245                let ret = self.acquire_location(&WpType::F32)?;
2246                self.value_stack.push((ret, CanonicalizeType::None));
2247
2248                self.machine.convert_f32_i32(loc, true, ret)?;
2249            }
2250            Operator::F32ConvertI32U => {
2251                let loc = self.pop_value_released()?.0;
2252                let ret = self.acquire_location(&WpType::F32)?;
2253                self.value_stack.push((ret, CanonicalizeType::None));
2254
2255                self.machine.convert_f32_i32(loc, false, ret)?;
2256            }
2257            Operator::F32ConvertI64S => {
2258                let loc = self.pop_value_released()?.0;
2259                let ret = self.acquire_location(&WpType::F32)?;
2260                self.value_stack.push((ret, CanonicalizeType::None));
2261
2262                self.machine.convert_f32_i64(loc, true, ret)?;
2263            }
2264            Operator::F32ConvertI64U => {
2265                let loc = self.pop_value_released()?.0;
2266                let ret = self.acquire_location(&WpType::F32)?;
2267                self.value_stack.push((ret, CanonicalizeType::None));
2268
2269                self.machine.convert_f32_i64(loc, false, ret)?;
2270            }
2271
2272            Operator::F64ConvertI32S => {
2273                let loc = self.pop_value_released()?.0;
2274                let ret = self.acquire_location(&WpType::F64)?;
2275                self.value_stack.push((ret, CanonicalizeType::None));
2276
2277                self.machine.convert_f64_i32(loc, true, ret)?;
2278            }
2279            Operator::F64ConvertI32U => {
2280                let loc = self.pop_value_released()?.0;
2281                let ret = self.acquire_location(&WpType::F64)?;
2282                self.value_stack.push((ret, CanonicalizeType::None));
2283
2284                self.machine.convert_f64_i32(loc, false, ret)?;
2285            }
2286            Operator::F64ConvertI64S => {
2287                let loc = self.pop_value_released()?.0;
2288                let ret = self.acquire_location(&WpType::F64)?;
2289                self.value_stack.push((ret, CanonicalizeType::None));
2290
2291                self.machine.convert_f64_i64(loc, true, ret)?;
2292            }
2293            Operator::F64ConvertI64U => {
2294                let loc = self.pop_value_released()?.0;
2295                let ret = self.acquire_location(&WpType::F64)?;
2296                self.value_stack.push((ret, CanonicalizeType::None));
2297
2298                self.machine.convert_f64_i64(loc, false, ret)?;
2299            }
2300
2301            Operator::Call { function_index } => {
2302                let function_index = function_index as usize;
2303
2304                let sig_index = *self
2305                    .module
2306                    .functions
2307                    .get(FunctionIndex::new(function_index))
2308                    .unwrap();
2309                let sig = self.module.signatures.get(sig_index).unwrap();
2310                let param_types: SmallVec<[WpType; 8]> =
2311                    sig.params().iter().map(type_to_wp_type).collect();
2312                let return_types: SmallVec<[WpType; 1]> =
2313                    sig.results().iter().map(type_to_wp_type).collect();
2314
2315                let params: SmallVec<[_; 8]> = self
2316                    .value_stack
2317                    .drain(self.value_stack.len() - param_types.len()..)
2318                    .collect();
2319
2320                // Pop arguments off the FP stack and canonicalize them if needed.
2321                //
2322                // Canonicalization state will be lost across function calls, so early canonicalization
2323                // is necessary here.
2324                if self.config.enable_nan_canonicalization {
2325                    for (loc, canonicalize) in params.iter() {
2326                        if let Some(size) = canonicalize.to_size() {
2327                            self.machine.canonicalize_nan(size, *loc, *loc)?;
2328                        }
2329                    }
2330                }
2331
2332                // Imported functions are called through trampolines placed as custom sections.
2333                let reloc_target = if function_index < self.module.num_imported_functions {
2334                    RelocationTarget::CustomSection(SectionIndex::new(function_index))
2335                } else {
2336                    RelocationTarget::LocalFunc(LocalFunctionIndex::new(
2337                        function_index - self.module.num_imported_functions,
2338                    ))
2339                };
2340                self.emit_call_native(
2341                    |this| {
2342                        let offset = this
2343                            .machine
2344                            .mark_instruction_with_trap_code(TrapCode::StackOverflow);
2345                        let mut relocations = this.machine.emit_call_with_reloc(reloc_target)?;
2346                        this.machine.mark_instruction_address_end(offset);
2347                        this.relocations.append(&mut relocations);
2348                        Ok(())
2349                    },
2350                    params.iter().copied(),
2351                    param_types.iter().copied(),
2352                    return_types.iter().copied(),
2353                    NativeCallType::IncludeVMCtxArgument,
2354                )?;
2355            }
2356            Operator::CallIndirect {
2357                type_index,
2358                table_index,
2359            } => {
2360                // TODO: removed restriction on always being table idx 0;
2361                // does any code depend on this?
2362                let table_index = TableIndex::new(table_index as _);
2363                let index = SignatureIndex::new(type_index as usize);
2364                let sig = self.module.signatures.get(index).unwrap();
2365                let expected_sig_hash = self.module.signature_hashes.get(index).unwrap();
2366                let table = self.module.tables.get(table_index).unwrap();
2367                let local_fixed_funcref_table = self
2368                    .module
2369                    .local_table_index(table_index)
2370                    .filter(|_| table.is_fixed_funcref_table());
2371                let param_types: SmallVec<[WpType; 8]> =
2372                    sig.params().iter().map(type_to_wp_type).collect();
2373                let return_types: SmallVec<[WpType; 1]> =
2374                    sig.results().iter().map(type_to_wp_type).collect();
2375
2376                let func_index = self.pop_value_released()?.0;
2377
2378                let params: SmallVec<[_; 8]> = self
2379                    .value_stack
2380                    .drain(self.value_stack.len() - param_types.len()..)
2381                    .collect();
2382
2383                // Pop arguments off the FP stack and canonicalize them if needed.
2384                //
2385                // Canonicalization state will be lost across function calls, so early canonicalization
2386                // is necessary here.
2387                if self.config.enable_nan_canonicalization {
2388                    for (loc, canonicalize) in params.iter() {
2389                        if let Some(size) = canonicalize.to_size() {
2390                            self.machine.canonicalize_nan(size, *loc, *loc)?;
2391                        }
2392                    }
2393                }
2394
2395                let table_base = self.machine.acquire_temp_gpr().unwrap();
2396                let table_count = self.machine.acquire_temp_gpr().unwrap();
2397                let sig_hash = self.machine.acquire_temp_gpr().unwrap();
2398
2399                if let Some(local_table_index) = local_fixed_funcref_table {
2400                    self.machine.move_location(
2401                        Size::S64,
2402                        Location::GPR(self.machine.get_vmctx_reg()),
2403                        Location::GPR(table_base),
2404                    )?;
2405                    self.machine.location_add(
2406                        Size::S64,
2407                        Location::Imm32(
2408                            self.vmoffsets
2409                                .vmctx_fixed_funcref_table_anyfuncs(local_table_index)
2410                                .expect("fixed funcref table must have inline VMContext storage"),
2411                        ),
2412                        Location::GPR(table_base),
2413                        false,
2414                    )?;
2415                    self.machine.move_location(
2416                        Size::S32,
2417                        Location::Imm32(table.minimum),
2418                        Location::GPR(table_count),
2419                    )?;
2420                } else if let Some(local_table_index) = self.module.local_table_index(table_index) {
2421                    let (vmctx_offset_base, vmctx_offset_len) = (
2422                        vmctx_offset(self.vmoffsets.vmctx_vmtable_definition(local_table_index))?,
2423                        vmctx_offset(
2424                            self.vmoffsets
2425                                .vmctx_vmtable_definition_current_elements(local_table_index),
2426                        )?,
2427                    );
2428                    self.machine.move_location(
2429                        Size::S64,
2430                        Location::Memory(self.machine.get_vmctx_reg(), vmctx_offset_base),
2431                        Location::GPR(table_base),
2432                    )?;
2433                    self.machine.move_location(
2434                        Size::S32,
2435                        Location::Memory(self.machine.get_vmctx_reg(), vmctx_offset_len),
2436                        Location::GPR(table_count),
2437                    )?;
2438                } else {
2439                    // Do an indirection.
2440                    let import_offset = self.vmoffsets.vmctx_vmtable_import(table_index);
2441                    self.machine.move_location(
2442                        Size::S64,
2443                        Location::Memory(
2444                            self.machine.get_vmctx_reg(),
2445                            vmctx_offset(import_offset)?,
2446                        ),
2447                        Location::GPR(table_base),
2448                    )?;
2449
2450                    // Load len.
2451                    self.machine.move_location(
2452                        Size::S32,
2453                        Location::Memory(
2454                            table_base,
2455                            self.vmoffsets.vmtable_definition_current_elements() as _,
2456                        ),
2457                        Location::GPR(table_count),
2458                    )?;
2459
2460                    // Load base.
2461                    self.machine.move_location(
2462                        Size::S64,
2463                        Location::Memory(table_base, self.vmoffsets.vmtable_definition_base() as _),
2464                        Location::GPR(table_base),
2465                    )?;
2466                }
2467
2468                self.machine.jmp_on_condition(
2469                    UnsignedCondition::BelowEqual,
2470                    Size::S32,
2471                    Location::GPR(table_count),
2472                    func_index,
2473                    self.special_labels.table_access_oob,
2474                )?;
2475                self.machine
2476                    .move_location(Size::S32, func_index, Location::GPR(table_count))?;
2477                self.machine.emit_imul_imm32(
2478                    Size::S64,
2479                    if local_fixed_funcref_table.is_some() {
2480                        u32::from(self.vmoffsets.size_of_vmcaller_checked_anyfunc())
2481                    } else {
2482                        u32::from(self.vmoffsets.size_of_vm_funcref())
2483                    },
2484                    table_count,
2485                )?;
2486                self.machine.location_add(
2487                    Size::S64,
2488                    Location::GPR(table_base),
2489                    Location::GPR(table_count),
2490                    false,
2491                )?;
2492
2493                if local_fixed_funcref_table.is_some() {
2494                    self.machine.move_location(
2495                        Size::S64,
2496                        Location::Memory(
2497                            table_count,
2498                            i32::from(self.vmoffsets.vmcaller_checked_anyfunc_func_ptr()),
2499                        ),
2500                        Location::GPR(table_base),
2501                    )?;
2502                    self.machine.jmp_on_condition(
2503                        UnsignedCondition::Equal,
2504                        Size::S64,
2505                        Location::GPR(table_base),
2506                        Location::Imm32(0),
2507                        self.special_labels.indirect_call_null,
2508                    )?;
2509                } else {
2510                    // deref the table to get a VMFuncRef
2511                    self.machine.move_location(
2512                        Size::S64,
2513                        Location::Memory(
2514                            table_count,
2515                            i32::from(self.vmoffsets.vm_funcref_anyfunc_ptr()),
2516                        ),
2517                        Location::GPR(table_count),
2518                    )?;
2519                    // Trap if the FuncRef is null
2520                    self.machine.jmp_on_condition(
2521                        UnsignedCondition::Equal,
2522                        Size::S64,
2523                        Location::GPR(table_count),
2524                        Location::Imm32(0),
2525                        self.special_labels.indirect_call_null,
2526                    )?;
2527                }
2528                self.machine.move_location(
2529                    Size::S32,
2530                    Location::Imm32(expected_sig_hash.as_u32()),
2531                    Location::GPR(sig_hash),
2532                )?;
2533
2534                // Trap if signature mismatches.
2535                self.machine.jmp_on_condition(
2536                    UnsignedCondition::NotEqual,
2537                    Size::S32,
2538                    Location::GPR(sig_hash),
2539                    Location::Memory(
2540                        table_count,
2541                        i32::from(self.vmoffsets.vmcaller_checked_anyfunc_signature_hash()),
2542                    ),
2543                    self.special_labels.bad_signature,
2544                )?;
2545                self.machine.release_gpr(sig_hash);
2546                self.machine.release_gpr(table_count);
2547                self.machine.release_gpr(table_base);
2548
2549                let gpr_for_call = self.machine.get_gpr_for_call();
2550                if table_count != gpr_for_call {
2551                    self.machine.move_location(
2552                        Size::S64,
2553                        Location::GPR(table_count),
2554                        Location::GPR(gpr_for_call),
2555                    )?;
2556                }
2557
2558                let vmcaller_checked_anyfunc_func_ptr =
2559                    i32::from(self.vmoffsets.vmcaller_checked_anyfunc_func_ptr());
2560                let vmcaller_checked_anyfunc_vmctx =
2561                    i32::from(self.vmoffsets.vmcaller_checked_anyfunc_vmctx());
2562
2563                self.emit_call_native(
2564                    |this| {
2565                        let offset = this
2566                            .machine
2567                            .mark_instruction_with_trap_code(TrapCode::StackOverflow);
2568
2569                        // We set the context pointer
2570                        this.machine.move_location(
2571                            Size::S64,
2572                            Location::Memory(gpr_for_call, vmcaller_checked_anyfunc_vmctx),
2573                            Location::GPR(this.machine.get_simple_param_location(0)),
2574                        )?;
2575
2576                        this.machine.emit_call_location(Location::Memory(
2577                            gpr_for_call,
2578                            vmcaller_checked_anyfunc_func_ptr,
2579                        ))?;
2580                        this.machine.mark_instruction_address_end(offset);
2581                        Ok(())
2582                    },
2583                    params.iter().copied(),
2584                    param_types.iter().copied(),
2585                    return_types.iter().copied(),
2586                    NativeCallType::IncludeVMCtxArgument,
2587                )?;
2588            }
2589            Operator::If { blockty } => {
2590                let label_end = self.machine.get_label();
2591                let label_else = self.machine.get_label();
2592
2593                let return_types = self.return_types_for_block(blockty);
2594                let param_types = self.param_types_for_block(blockty);
2595                self.allocate_return_slots_and_swap(param_types.len() + 1, return_types.len())?;
2596
2597                let cond = self.pop_value_released()?.0;
2598
2599                /* We might hit a situation where an Operator::If is missing an Operator::Else. In such a situation,
2600                the result value just fallthrough from the If block inputs! However, we don't know the information upfront. */
2601                if param_types.len() == return_types.len() {
2602                    for (input, return_value) in self
2603                        .value_stack
2604                        .iter()
2605                        .rev()
2606                        .take(param_types.len())
2607                        .zip(self.value_stack.iter().rev().skip(param_types.len()))
2608                    {
2609                        self.machine
2610                            .emit_relaxed_mov(Size::S64, input.0, return_value.0)?;
2611                    }
2612                }
2613
2614                let frame = ControlFrame {
2615                    state: ControlState::If {
2616                        label_else,
2617                        inputs: SmallVec::from_iter(
2618                            self.value_stack
2619                                .iter()
2620                                .rev()
2621                                .take(param_types.len())
2622                                .rev()
2623                                .copied(),
2624                        ),
2625                    },
2626                    label: label_end,
2627                    param_types,
2628                    return_types,
2629                    value_stack_depth: self.value_stack.len(),
2630                };
2631                self.control_stack.push(frame);
2632                self.machine.jmp_on_condition(
2633                    UnsignedCondition::Equal,
2634                    Size::S32,
2635                    cond,
2636                    Location::Imm32(0),
2637                    label_else,
2638                )?;
2639            }
2640            Operator::Else => {
2641                let frame = self.control_stack.last().unwrap();
2642
2643                if !was_unreachable && !frame.return_types.is_empty() {
2644                    self.emit_return_values(
2645                        frame.value_stack_depth_after(),
2646                        frame.return_types.len(),
2647                    )?;
2648                }
2649
2650                let frame = &self.control_stack.last_mut().unwrap();
2651                let locs = self
2652                    .value_stack
2653                    .drain(frame.value_stack_depth_after()..)
2654                    .collect_vec();
2655                self.release_locations(&locs)?;
2656                let frame = &mut self.control_stack.last_mut().unwrap();
2657
2658                // The Else block must be provided the very same inputs as the previous If block had,
2659                // and so we need to copy the already consumed stack values.
2660                let ControlState::If {
2661                    label_else,
2662                    ref inputs,
2663                } = frame.state
2664                else {
2665                    panic!("Operator::Else must be connected to Operator::If statement");
2666                };
2667                for (input, _) in inputs {
2668                    match input {
2669                        Location::GPR(x) => {
2670                            self.machine.reserve_gpr(*x);
2671                        }
2672                        Location::SIMD(x) => {
2673                            self.machine.reserve_simd(*x);
2674                        }
2675                        Location::Memory(reg, _) => {
2676                            debug_assert_eq!(reg, &self.machine.local_pointer());
2677                            self.stack_offset += 8;
2678                        }
2679                        _ => {}
2680                    }
2681                }
2682                self.value_stack.extend(inputs);
2683
2684                self.machine.jmp_unconditional(frame.label)?;
2685                self.machine.emit_label(label_else)?;
2686                frame.state = ControlState::Else;
2687            }
2688            // `TypedSelect` must be used for extern refs so ref counting should
2689            // be done with TypedSelect. But otherwise they're the same.
2690            Operator::TypedSelect { .. } | Operator::Select => {
2691                let cond = self.pop_value_released()?.0;
2692                let (v_b, canonicalize_b) = self.pop_value_released()?;
2693                let (v_a, canonicalize_a) = self.pop_value_released()?;
2694                let ret = self.acquire_location(&WpType::I64)?;
2695                self.value_stack.push((ret, CanonicalizeType::None));
2696
2697                let end_label = self.machine.get_label();
2698                let zero_label = self.machine.get_label();
2699
2700                self.machine.jmp_on_condition(
2701                    UnsignedCondition::Equal,
2702                    Size::S32,
2703                    cond,
2704                    Location::Imm32(0),
2705                    zero_label,
2706                )?;
2707                if self.config.enable_nan_canonicalization
2708                    && let Some(size) = canonicalize_a.to_size()
2709                {
2710                    self.machine.canonicalize_nan(size, v_a, ret)?;
2711                } else if v_a != ret {
2712                    self.machine.emit_relaxed_mov(Size::S64, v_a, ret)?;
2713                }
2714                self.machine.jmp_unconditional(end_label)?;
2715                self.machine.emit_label(zero_label)?;
2716                if self.config.enable_nan_canonicalization
2717                    && let Some(size) = canonicalize_b.to_size()
2718                {
2719                    self.machine.canonicalize_nan(size, v_b, ret)?;
2720                } else if v_b != ret {
2721                    self.machine.emit_relaxed_mov(Size::S64, v_b, ret)?;
2722                }
2723                self.machine.emit_label(end_label)?;
2724            }
2725            Operator::Block { blockty } => {
2726                let return_types = self.return_types_for_block(blockty);
2727                let param_types = self.param_types_for_block(blockty);
2728                self.allocate_return_slots_and_swap(param_types.len(), return_types.len())?;
2729
2730                let frame = ControlFrame {
2731                    state: ControlState::Block,
2732                    label: self.machine.get_label(),
2733                    param_types,
2734                    return_types,
2735                    value_stack_depth: self.value_stack.len(),
2736                };
2737                self.control_stack.push(frame);
2738            }
2739            Operator::Loop { blockty } => {
2740                self.machine.align_for_loop()?;
2741                let label = self.machine.get_label();
2742
2743                let return_types = self.return_types_for_block(blockty);
2744                let param_types = self.param_types_for_block(blockty);
2745                let params_count = param_types.len();
2746                // We need extra space for params as we need to implement the PHI operation.
2747                self.allocate_return_slots_and_swap(
2748                    param_types.len(),
2749                    param_types.len() + return_types.len(),
2750                )?;
2751
2752                self.control_stack.push(ControlFrame {
2753                    state: ControlState::Loop,
2754                    label,
2755                    param_types: param_types.clone(),
2756                    return_types: return_types.clone(),
2757                    value_stack_depth: self.value_stack.len(),
2758                });
2759
2760                // For proper PHI implementation, we must copy pre-loop params to PHI params.
2761                let params = self
2762                    .value_stack
2763                    .drain((self.value_stack.len() - params_count)..)
2764                    .collect_vec();
2765                for (param, phi_param) in params.iter().rev().zip(self.value_stack.iter().rev()) {
2766                    if let Some(canonicalize_size) = param.1.to_size()
2767                        && self.config.enable_nan_canonicalization
2768                    {
2769                        self.machine
2770                            .canonicalize_nan(canonicalize_size, param.0, phi_param.0)?;
2771                    } else {
2772                        self.machine
2773                            .emit_relaxed_mov(Size::S64, param.0, phi_param.0)?;
2774                    }
2775                }
2776                self.release_locations(&params)?;
2777
2778                self.machine.emit_label(label)?;
2779
2780                // Put on the stack PHI inputs for further use.
2781                let phi_params = self
2782                    .value_stack
2783                    .iter()
2784                    .rev()
2785                    .take(params_count)
2786                    .rev()
2787                    .copied()
2788                    .collect_vec();
2789                for (i, phi_param) in phi_params.into_iter().enumerate() {
2790                    let loc = self.acquire_location(&param_types[i])?;
2791                    self.machine.emit_relaxed_mov(Size::S64, phi_param.0, loc)?;
2792                    self.value_stack.push((loc, phi_param.1));
2793                }
2794
2795                // TODO: Re-enable interrupt signal check without branching
2796            }
2797            Operator::Nop => {}
2798            Operator::MemorySize { mem } => {
2799                let memory_index = MemoryIndex::new(mem as usize);
2800                let local_memory_index = self.module.local_memory_index(memory_index);
2801                let index_arg =
2802                    local_memory_index.map_or(memory_index.index() as u32, |index| index.as_u32());
2803                self.machine.move_location(
2804                    Size::S64,
2805                    Location::Memory(
2806                        self.machine.get_vmctx_reg(),
2807                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(
2808                            if local_memory_index.is_some() {
2809                                VMBuiltinFunctionIndex::get_memory32_size_index()
2810                            } else {
2811                                VMBuiltinFunctionIndex::get_imported_memory32_size_index()
2812                            },
2813                        ))?,
2814                    ),
2815                    Location::GPR(self.machine.get_gpr_for_call()),
2816                )?;
2817                self.emit_call_native(
2818                    |this| {
2819                        this.machine
2820                            .emit_call_register(this.machine.get_gpr_for_call())
2821                    },
2822                    // [vmctx, memory_index]
2823                    iter::once((Location::Imm32(index_arg), CanonicalizeType::None)),
2824                    iter::once(WpType::I32),
2825                    iter::once(WpType::I32),
2826                    NativeCallType::IncludeVMCtxArgument,
2827                )?;
2828            }
2829            Operator::MemoryInit { data_index, mem } => {
2830                let len = self.value_stack.pop().unwrap();
2831                let src = self.value_stack.pop().unwrap();
2832                let dst = self.value_stack.pop().unwrap();
2833
2834                self.machine.move_location(
2835                    Size::S64,
2836                    Location::Memory(
2837                        self.machine.get_vmctx_reg(),
2838                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(
2839                            VMBuiltinFunctionIndex::get_memory_init_index(),
2840                        ))?,
2841                    ),
2842                    Location::GPR(self.machine.get_gpr_for_call()),
2843                )?;
2844
2845                self.emit_call_native(
2846                    |this| {
2847                        this.machine
2848                            .emit_call_register(this.machine.get_gpr_for_call())
2849                    },
2850                    // [vmctx, memory_index, data_index, dst, src, len]
2851                    [
2852                        (Location::Imm32(mem), CanonicalizeType::None),
2853                        (Location::Imm32(data_index), CanonicalizeType::None),
2854                        dst,
2855                        src,
2856                        len,
2857                    ]
2858                    .iter()
2859                    .cloned(),
2860                    [
2861                        WpType::I32,
2862                        WpType::I32,
2863                        WpType::I32,
2864                        WpType::I32,
2865                        WpType::I32,
2866                    ]
2867                    .iter()
2868                    .cloned(),
2869                    iter::empty(),
2870                    NativeCallType::IncludeVMCtxArgument,
2871                )?;
2872            }
2873            Operator::DataDrop { data_index } => {
2874                self.machine.move_location(
2875                    Size::S64,
2876                    Location::Memory(
2877                        self.machine.get_vmctx_reg(),
2878                        vmctx_offset(
2879                            self.vmoffsets.vmctx_builtin_function(
2880                                VMBuiltinFunctionIndex::get_data_drop_index(),
2881                            ),
2882                        )?,
2883                    ),
2884                    Location::GPR(self.machine.get_gpr_for_call()),
2885                )?;
2886
2887                self.emit_call_native(
2888                    |this| {
2889                        this.machine
2890                            .emit_call_register(this.machine.get_gpr_for_call())
2891                    },
2892                    // [vmctx, data_index]
2893                    iter::once((Location::Imm32(data_index), CanonicalizeType::None)),
2894                    iter::once(WpType::I32),
2895                    iter::empty(),
2896                    NativeCallType::IncludeVMCtxArgument,
2897                )?;
2898            }
2899            Operator::MemoryCopy { dst_mem, src_mem } => {
2900                let len = self.value_stack.pop().unwrap();
2901                let src_pos = self.value_stack.pop().unwrap();
2902                let dst_pos = self.value_stack.pop().unwrap();
2903
2904                self.machine.move_location(
2905                    Size::S64,
2906                    Location::Memory(
2907                        self.machine.get_vmctx_reg(),
2908                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(
2909                            VMBuiltinFunctionIndex::get_memory_copy_index(),
2910                        ))?,
2911                    ),
2912                    Location::GPR(self.machine.get_gpr_for_call()),
2913                )?;
2914
2915                self.emit_call_native(
2916                    |this| {
2917                        this.machine
2918                            .emit_call_register(this.machine.get_gpr_for_call())
2919                    },
2920                    // [vmctx, dst_memory_index, src_memory_index, dst, src, len]
2921                    [
2922                        (Location::Imm32(dst_mem), CanonicalizeType::None),
2923                        (Location::Imm32(src_mem), CanonicalizeType::None),
2924                        dst_pos,
2925                        src_pos,
2926                        len,
2927                    ]
2928                    .iter()
2929                    .cloned(),
2930                    [
2931                        WpType::I32,
2932                        WpType::I32,
2933                        WpType::I32,
2934                        WpType::I32,
2935                        WpType::I32,
2936                    ]
2937                    .iter()
2938                    .cloned(),
2939                    iter::empty(),
2940                    NativeCallType::IncludeVMCtxArgument,
2941                )?;
2942            }
2943            Operator::MemoryFill { mem } => {
2944                let len = self.value_stack.pop().unwrap();
2945                let val = self.value_stack.pop().unwrap();
2946                let dst = self.value_stack.pop().unwrap();
2947
2948                let memory_index = MemoryIndex::new(mem as usize);
2949                let (memory_fill_index, index_arg) =
2950                    if let Some(local_index) = self.module.local_memory_index(memory_index) {
2951                        (
2952                            VMBuiltinFunctionIndex::get_memory_fill_index(),
2953                            local_index.as_u32(),
2954                        )
2955                    } else {
2956                        (
2957                            VMBuiltinFunctionIndex::get_imported_memory_fill_index(),
2958                            memory_index.as_u32(),
2959                        )
2960                    };
2961
2962                self.machine.move_location(
2963                    Size::S64,
2964                    Location::Memory(
2965                        self.machine.get_vmctx_reg(),
2966                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(memory_fill_index))?,
2967                    ),
2968                    Location::GPR(self.machine.get_gpr_for_call()),
2969                )?;
2970
2971                self.emit_call_native(
2972                    |this| {
2973                        this.machine
2974                            .emit_call_register(this.machine.get_gpr_for_call())
2975                    },
2976                    // [vmctx, memory_index, dst, src, len]
2977                    [
2978                        (Location::Imm32(index_arg), CanonicalizeType::None),
2979                        dst,
2980                        val,
2981                        len,
2982                    ]
2983                    .iter()
2984                    .cloned(),
2985                    [WpType::I32, WpType::I32, WpType::I32, WpType::I32]
2986                        .iter()
2987                        .cloned(),
2988                    iter::empty(),
2989                    NativeCallType::IncludeVMCtxArgument,
2990                )?;
2991            }
2992            Operator::MemoryGrow { mem } => {
2993                let memory_index = MemoryIndex::new(mem as usize);
2994                let local_memory_index = self.module.local_memory_index(memory_index);
2995                let index_arg =
2996                    local_memory_index.map_or(memory_index.index() as u32, |index| index.as_u32());
2997                let param_pages = self.value_stack.pop().unwrap();
2998
2999                self.machine.move_location(
3000                    Size::S64,
3001                    Location::Memory(
3002                        self.machine.get_vmctx_reg(),
3003                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(
3004                            if local_memory_index.is_some() {
3005                                VMBuiltinFunctionIndex::get_memory32_grow_index()
3006                            } else {
3007                                VMBuiltinFunctionIndex::get_imported_memory32_grow_index()
3008                            },
3009                        ))?,
3010                    ),
3011                    Location::GPR(self.machine.get_gpr_for_call()),
3012                )?;
3013
3014                self.emit_call_native(
3015                    |this| {
3016                        this.machine
3017                            .emit_call_register(this.machine.get_gpr_for_call())
3018                    },
3019                    // [vmctx, val, memory_index]
3020                    [
3021                        param_pages,
3022                        (Location::Imm32(index_arg), CanonicalizeType::None),
3023                    ]
3024                    .iter()
3025                    .cloned(),
3026                    [WpType::I32, WpType::I32].iter().cloned(),
3027                    iter::once(WpType::I32),
3028                    NativeCallType::IncludeVMCtxArgument,
3029                )?;
3030            }
3031            Operator::I32Load { ref memarg } => {
3032                let target = self.pop_value_released()?.0;
3033                let ret = self.acquire_location(&WpType::I32)?;
3034                self.value_stack.push((ret, CanonicalizeType::None));
3035                self.op_memory(
3036                    MemoryIndex::from_u32(memarg.memory),
3037                    |this,
3038                     need_check,
3039                     imported_memories,
3040                     offset,
3041                     heap_access_oob,
3042                     unaligned_atomic| {
3043                        this.machine.i32_load(
3044                            target,
3045                            memarg,
3046                            ret,
3047                            need_check,
3048                            imported_memories,
3049                            offset,
3050                            heap_access_oob,
3051                            unaligned_atomic,
3052                        )
3053                    },
3054                )?;
3055            }
3056            Operator::F32Load { ref memarg } => {
3057                let target = self.pop_value_released()?.0;
3058                let ret = self.acquire_location(&WpType::F32)?;
3059                self.value_stack.push((ret, CanonicalizeType::None));
3060                self.op_memory(
3061                    MemoryIndex::from_u32(memarg.memory),
3062                    |this,
3063                     need_check,
3064                     imported_memories,
3065                     offset,
3066                     heap_access_oob,
3067                     unaligned_atomic| {
3068                        this.machine.f32_load(
3069                            target,
3070                            memarg,
3071                            ret,
3072                            need_check,
3073                            imported_memories,
3074                            offset,
3075                            heap_access_oob,
3076                            unaligned_atomic,
3077                        )
3078                    },
3079                )?;
3080            }
3081            Operator::I32Load8U { ref memarg } => {
3082                let target = self.pop_value_released()?.0;
3083                let ret = self.acquire_location(&WpType::I32)?;
3084                self.value_stack.push((ret, CanonicalizeType::None));
3085                self.op_memory(
3086                    MemoryIndex::from_u32(memarg.memory),
3087                    |this,
3088                     need_check,
3089                     imported_memories,
3090                     offset,
3091                     heap_access_oob,
3092                     unaligned_atomic| {
3093                        this.machine.i32_load_8u(
3094                            target,
3095                            memarg,
3096                            ret,
3097                            need_check,
3098                            imported_memories,
3099                            offset,
3100                            heap_access_oob,
3101                            unaligned_atomic,
3102                        )
3103                    },
3104                )?;
3105            }
3106            Operator::I32Load8S { ref memarg } => {
3107                let target = self.pop_value_released()?.0;
3108                let ret = self.acquire_location(&WpType::I32)?;
3109                self.value_stack.push((ret, CanonicalizeType::None));
3110                self.op_memory(
3111                    MemoryIndex::from_u32(memarg.memory),
3112                    |this,
3113                     need_check,
3114                     imported_memories,
3115                     offset,
3116                     heap_access_oob,
3117                     unaligned_atomic| {
3118                        this.machine.i32_load_8s(
3119                            target,
3120                            memarg,
3121                            ret,
3122                            need_check,
3123                            imported_memories,
3124                            offset,
3125                            heap_access_oob,
3126                            unaligned_atomic,
3127                        )
3128                    },
3129                )?;
3130            }
3131            Operator::I32Load16U { ref memarg } => {
3132                let target = self.pop_value_released()?.0;
3133                let ret = self.acquire_location(&WpType::I32)?;
3134                self.value_stack.push((ret, CanonicalizeType::None));
3135                self.op_memory(
3136                    MemoryIndex::from_u32(memarg.memory),
3137                    |this,
3138                     need_check,
3139                     imported_memories,
3140                     offset,
3141                     heap_access_oob,
3142                     unaligned_atomic| {
3143                        this.machine.i32_load_16u(
3144                            target,
3145                            memarg,
3146                            ret,
3147                            need_check,
3148                            imported_memories,
3149                            offset,
3150                            heap_access_oob,
3151                            unaligned_atomic,
3152                        )
3153                    },
3154                )?;
3155            }
3156            Operator::I32Load16S { ref memarg } => {
3157                let target = self.pop_value_released()?.0;
3158                let ret = self.acquire_location(&WpType::I32)?;
3159                self.value_stack.push((ret, CanonicalizeType::None));
3160                self.op_memory(
3161                    MemoryIndex::from_u32(memarg.memory),
3162                    |this,
3163                     need_check,
3164                     imported_memories,
3165                     offset,
3166                     heap_access_oob,
3167                     unaligned_atomic| {
3168                        this.machine.i32_load_16s(
3169                            target,
3170                            memarg,
3171                            ret,
3172                            need_check,
3173                            imported_memories,
3174                            offset,
3175                            heap_access_oob,
3176                            unaligned_atomic,
3177                        )
3178                    },
3179                )?;
3180            }
3181            Operator::I32Store { ref memarg } => {
3182                let target_value = self.pop_value_released()?.0;
3183                let target_addr = self.pop_value_released()?.0;
3184                self.op_memory(
3185                    MemoryIndex::from_u32(memarg.memory),
3186                    |this,
3187                     need_check,
3188                     imported_memories,
3189                     offset,
3190                     heap_access_oob,
3191                     unaligned_atomic| {
3192                        this.machine.i32_save(
3193                            target_value,
3194                            memarg,
3195                            target_addr,
3196                            need_check,
3197                            imported_memories,
3198                            offset,
3199                            heap_access_oob,
3200                            unaligned_atomic,
3201                        )
3202                    },
3203                )?;
3204            }
3205            Operator::F32Store { ref memarg } => {
3206                let (target_value, canonicalize) = self.pop_value_released()?;
3207                let target_addr = self.pop_value_released()?.0;
3208                self.op_memory(
3209                    MemoryIndex::from_u32(memarg.memory),
3210                    |this,
3211                     need_check,
3212                     imported_memories,
3213                     offset,
3214                     heap_access_oob,
3215                     unaligned_atomic| {
3216                        this.machine.f32_save(
3217                            target_value,
3218                            memarg,
3219                            target_addr,
3220                            self.config.enable_nan_canonicalization
3221                                && !matches!(canonicalize, CanonicalizeType::None),
3222                            need_check,
3223                            imported_memories,
3224                            offset,
3225                            heap_access_oob,
3226                            unaligned_atomic,
3227                        )
3228                    },
3229                )?;
3230            }
3231            Operator::I32Store8 { ref memarg } => {
3232                let target_value = self.pop_value_released()?.0;
3233                let target_addr = self.pop_value_released()?.0;
3234                self.op_memory(
3235                    MemoryIndex::from_u32(memarg.memory),
3236                    |this,
3237                     need_check,
3238                     imported_memories,
3239                     offset,
3240                     heap_access_oob,
3241                     unaligned_atomic| {
3242                        this.machine.i32_save_8(
3243                            target_value,
3244                            memarg,
3245                            target_addr,
3246                            need_check,
3247                            imported_memories,
3248                            offset,
3249                            heap_access_oob,
3250                            unaligned_atomic,
3251                        )
3252                    },
3253                )?;
3254            }
3255            Operator::I32Store16 { ref memarg } => {
3256                let target_value = self.pop_value_released()?.0;
3257                let target_addr = self.pop_value_released()?.0;
3258                self.op_memory(
3259                    MemoryIndex::from_u32(memarg.memory),
3260                    |this,
3261                     need_check,
3262                     imported_memories,
3263                     offset,
3264                     heap_access_oob,
3265                     unaligned_atomic| {
3266                        this.machine.i32_save_16(
3267                            target_value,
3268                            memarg,
3269                            target_addr,
3270                            need_check,
3271                            imported_memories,
3272                            offset,
3273                            heap_access_oob,
3274                            unaligned_atomic,
3275                        )
3276                    },
3277                )?;
3278            }
3279            Operator::I64Load { ref memarg } => {
3280                let target = self.pop_value_released()?.0;
3281                let ret = self.acquire_location(&WpType::I64)?;
3282                self.value_stack.push((ret, CanonicalizeType::None));
3283                self.op_memory(
3284                    MemoryIndex::from_u32(memarg.memory),
3285                    |this,
3286                     need_check,
3287                     imported_memories,
3288                     offset,
3289                     heap_access_oob,
3290                     unaligned_atomic| {
3291                        this.machine.i64_load(
3292                            target,
3293                            memarg,
3294                            ret,
3295                            need_check,
3296                            imported_memories,
3297                            offset,
3298                            heap_access_oob,
3299                            unaligned_atomic,
3300                        )
3301                    },
3302                )?;
3303            }
3304            Operator::F64Load { ref memarg } => {
3305                let target = self.pop_value_released()?.0;
3306                let ret = self.acquire_location(&WpType::F64)?;
3307                self.value_stack.push((ret, CanonicalizeType::None));
3308                self.op_memory(
3309                    MemoryIndex::from_u32(memarg.memory),
3310                    |this,
3311                     need_check,
3312                     imported_memories,
3313                     offset,
3314                     heap_access_oob,
3315                     unaligned_atomic| {
3316                        this.machine.f64_load(
3317                            target,
3318                            memarg,
3319                            ret,
3320                            need_check,
3321                            imported_memories,
3322                            offset,
3323                            heap_access_oob,
3324                            unaligned_atomic,
3325                        )
3326                    },
3327                )?;
3328            }
3329            Operator::I64Load8U { ref memarg } => {
3330                let target = self.pop_value_released()?.0;
3331                let ret = self.acquire_location(&WpType::I64)?;
3332                self.value_stack.push((ret, CanonicalizeType::None));
3333                self.op_memory(
3334                    MemoryIndex::from_u32(memarg.memory),
3335                    |this,
3336                     need_check,
3337                     imported_memories,
3338                     offset,
3339                     heap_access_oob,
3340                     unaligned_atomic| {
3341                        this.machine.i64_load_8u(
3342                            target,
3343                            memarg,
3344                            ret,
3345                            need_check,
3346                            imported_memories,
3347                            offset,
3348                            heap_access_oob,
3349                            unaligned_atomic,
3350                        )
3351                    },
3352                )?;
3353            }
3354            Operator::I64Load8S { ref memarg } => {
3355                let target = self.pop_value_released()?.0;
3356                let ret = self.acquire_location(&WpType::I64)?;
3357                self.value_stack.push((ret, CanonicalizeType::None));
3358                self.op_memory(
3359                    MemoryIndex::from_u32(memarg.memory),
3360                    |this,
3361                     need_check,
3362                     imported_memories,
3363                     offset,
3364                     heap_access_oob,
3365                     unaligned_atomic| {
3366                        this.machine.i64_load_8s(
3367                            target,
3368                            memarg,
3369                            ret,
3370                            need_check,
3371                            imported_memories,
3372                            offset,
3373                            heap_access_oob,
3374                            unaligned_atomic,
3375                        )
3376                    },
3377                )?;
3378            }
3379            Operator::I64Load16U { ref memarg } => {
3380                let target = self.pop_value_released()?.0;
3381                let ret = self.acquire_location(&WpType::I64)?;
3382                self.value_stack.push((ret, CanonicalizeType::None));
3383                self.op_memory(
3384                    MemoryIndex::from_u32(memarg.memory),
3385                    |this,
3386                     need_check,
3387                     imported_memories,
3388                     offset,
3389                     heap_access_oob,
3390                     unaligned_atomic| {
3391                        this.machine.i64_load_16u(
3392                            target,
3393                            memarg,
3394                            ret,
3395                            need_check,
3396                            imported_memories,
3397                            offset,
3398                            heap_access_oob,
3399                            unaligned_atomic,
3400                        )
3401                    },
3402                )?;
3403            }
3404            Operator::I64Load16S { ref memarg } => {
3405                let target = self.pop_value_released()?.0;
3406                let ret = self.acquire_location(&WpType::I64)?;
3407                self.value_stack.push((ret, CanonicalizeType::None));
3408                self.op_memory(
3409                    MemoryIndex::from_u32(memarg.memory),
3410                    |this,
3411                     need_check,
3412                     imported_memories,
3413                     offset,
3414                     heap_access_oob,
3415                     unaligned_atomic| {
3416                        this.machine.i64_load_16s(
3417                            target,
3418                            memarg,
3419                            ret,
3420                            need_check,
3421                            imported_memories,
3422                            offset,
3423                            heap_access_oob,
3424                            unaligned_atomic,
3425                        )
3426                    },
3427                )?;
3428            }
3429            Operator::I64Load32U { ref memarg } => {
3430                let target = self.pop_value_released()?.0;
3431                let ret = self.acquire_location(&WpType::I64)?;
3432                self.value_stack.push((ret, CanonicalizeType::None));
3433                self.op_memory(
3434                    MemoryIndex::from_u32(memarg.memory),
3435                    |this,
3436                     need_check,
3437                     imported_memories,
3438                     offset,
3439                     heap_access_oob,
3440                     unaligned_atomic| {
3441                        this.machine.i64_load_32u(
3442                            target,
3443                            memarg,
3444                            ret,
3445                            need_check,
3446                            imported_memories,
3447                            offset,
3448                            heap_access_oob,
3449                            unaligned_atomic,
3450                        )
3451                    },
3452                )?;
3453            }
3454            Operator::I64Load32S { ref memarg } => {
3455                let target = self.pop_value_released()?.0;
3456                let ret = self.acquire_location(&WpType::I64)?;
3457                self.value_stack.push((ret, CanonicalizeType::None));
3458                self.op_memory(
3459                    MemoryIndex::from_u32(memarg.memory),
3460                    |this,
3461                     need_check,
3462                     imported_memories,
3463                     offset,
3464                     heap_access_oob,
3465                     unaligned_atomic| {
3466                        this.machine.i64_load_32s(
3467                            target,
3468                            memarg,
3469                            ret,
3470                            need_check,
3471                            imported_memories,
3472                            offset,
3473                            heap_access_oob,
3474                            unaligned_atomic,
3475                        )
3476                    },
3477                )?;
3478            }
3479            Operator::I64Store { ref memarg } => {
3480                let target_value = self.pop_value_released()?.0;
3481                let target_addr = self.pop_value_released()?.0;
3482
3483                self.op_memory(
3484                    MemoryIndex::from_u32(memarg.memory),
3485                    |this,
3486                     need_check,
3487                     imported_memories,
3488                     offset,
3489                     heap_access_oob,
3490                     unaligned_atomic| {
3491                        this.machine.i64_save(
3492                            target_value,
3493                            memarg,
3494                            target_addr,
3495                            need_check,
3496                            imported_memories,
3497                            offset,
3498                            heap_access_oob,
3499                            unaligned_atomic,
3500                        )
3501                    },
3502                )?;
3503            }
3504            Operator::F64Store { ref memarg } => {
3505                let (target_value, canonicalize) = self.pop_value_released()?;
3506                let target_addr = self.pop_value_released()?.0;
3507                self.op_memory(
3508                    MemoryIndex::from_u32(memarg.memory),
3509                    |this,
3510                     need_check,
3511                     imported_memories,
3512                     offset,
3513                     heap_access_oob,
3514                     unaligned_atomic| {
3515                        this.machine.f64_save(
3516                            target_value,
3517                            memarg,
3518                            target_addr,
3519                            self.config.enable_nan_canonicalization
3520                                && !matches!(canonicalize, CanonicalizeType::None),
3521                            need_check,
3522                            imported_memories,
3523                            offset,
3524                            heap_access_oob,
3525                            unaligned_atomic,
3526                        )
3527                    },
3528                )?;
3529            }
3530            Operator::I64Store8 { ref memarg } => {
3531                let target_value = self.pop_value_released()?.0;
3532                let target_addr = self.pop_value_released()?.0;
3533                self.op_memory(
3534                    MemoryIndex::from_u32(memarg.memory),
3535                    |this,
3536                     need_check,
3537                     imported_memories,
3538                     offset,
3539                     heap_access_oob,
3540                     unaligned_atomic| {
3541                        this.machine.i64_save_8(
3542                            target_value,
3543                            memarg,
3544                            target_addr,
3545                            need_check,
3546                            imported_memories,
3547                            offset,
3548                            heap_access_oob,
3549                            unaligned_atomic,
3550                        )
3551                    },
3552                )?;
3553            }
3554            Operator::I64Store16 { ref memarg } => {
3555                let target_value = self.pop_value_released()?.0;
3556                let target_addr = self.pop_value_released()?.0;
3557                self.op_memory(
3558                    MemoryIndex::from_u32(memarg.memory),
3559                    |this,
3560                     need_check,
3561                     imported_memories,
3562                     offset,
3563                     heap_access_oob,
3564                     unaligned_atomic| {
3565                        this.machine.i64_save_16(
3566                            target_value,
3567                            memarg,
3568                            target_addr,
3569                            need_check,
3570                            imported_memories,
3571                            offset,
3572                            heap_access_oob,
3573                            unaligned_atomic,
3574                        )
3575                    },
3576                )?;
3577            }
3578            Operator::I64Store32 { ref memarg } => {
3579                let target_value = self.pop_value_released()?.0;
3580                let target_addr = self.pop_value_released()?.0;
3581                self.op_memory(
3582                    MemoryIndex::from_u32(memarg.memory),
3583                    |this,
3584                     need_check,
3585                     imported_memories,
3586                     offset,
3587                     heap_access_oob,
3588                     unaligned_atomic| {
3589                        this.machine.i64_save_32(
3590                            target_value,
3591                            memarg,
3592                            target_addr,
3593                            need_check,
3594                            imported_memories,
3595                            offset,
3596                            heap_access_oob,
3597                            unaligned_atomic,
3598                        )
3599                    },
3600                )?;
3601            }
3602            Operator::Unreachable => {
3603                self.machine.move_location(
3604                    Size::S64,
3605                    Location::Memory(
3606                        self.machine.get_vmctx_reg(),
3607                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(
3608                            VMBuiltinFunctionIndex::get_raise_trap_index(),
3609                        ))?,
3610                    ),
3611                    Location::GPR(self.machine.get_gpr_for_call()),
3612                )?;
3613
3614                self.emit_call_native(
3615                    |this| {
3616                        this.machine
3617                            .emit_call_register(this.machine.get_gpr_for_call())
3618                    },
3619                    // [trap_code]
3620                    [(
3621                        Location::Imm32(TrapCode::UnreachableCodeReached as u32),
3622                        CanonicalizeType::None,
3623                    )]
3624                    .iter()
3625                    .cloned(),
3626                    [WpType::I32].iter().cloned(),
3627                    iter::empty(),
3628                    NativeCallType::Unreachable,
3629                )?;
3630                self.unreachable_depth = 1;
3631            }
3632            Operator::Return => {
3633                let frame = &self.control_stack[0];
3634                if !frame.return_types.is_empty() {
3635                    self.emit_return_values(
3636                        frame.value_stack_depth_after(),
3637                        frame.return_types.len(),
3638                    )?;
3639                }
3640                let frame = &self.control_stack[0];
3641                let frame_depth = frame.value_stack_depth_for_release();
3642                let label = frame.label;
3643                self.release_stack_locations_keep_stack_offset(frame_depth)?;
3644                self.machine.jmp_unconditional(label)?;
3645                self.unreachable_depth = 1;
3646            }
3647            Operator::Br { relative_depth } => {
3648                let frame =
3649                    &self.control_stack[self.control_stack.len() - 1 - (relative_depth as usize)];
3650                if matches!(frame.state, ControlState::Loop) {
3651                    // Store into the PHI params of the loop, not to the return values.
3652                    self.emit_loop_params_store(
3653                        frame.value_stack_depth_after(),
3654                        frame.param_types.len(),
3655                    )?;
3656                } else if !frame.return_types.is_empty() {
3657                    self.emit_return_values(
3658                        frame.value_stack_depth_after(),
3659                        frame.return_types.len(),
3660                    )?;
3661                }
3662                let stack_len = self.control_stack.len();
3663                let frame = &mut self.control_stack[stack_len - 1 - (relative_depth as usize)];
3664                let frame_depth = frame.value_stack_depth_for_release();
3665                let label = frame.label;
3666
3667                self.release_stack_locations_keep_stack_offset(frame_depth)?;
3668                self.machine.jmp_unconditional(label)?;
3669                self.unreachable_depth = 1;
3670            }
3671            Operator::BrIf { relative_depth } => {
3672                let after = self.machine.get_label();
3673                let cond = self.pop_value_released()?.0;
3674                self.machine.jmp_on_condition(
3675                    UnsignedCondition::Equal,
3676                    Size::S32,
3677                    cond,
3678                    Location::Imm32(0),
3679                    after,
3680                )?;
3681
3682                let frame =
3683                    &self.control_stack[self.control_stack.len() - 1 - (relative_depth as usize)];
3684                if matches!(frame.state, ControlState::Loop) {
3685                    // Store into the PHI params of the loop, not to the return values.
3686                    self.emit_loop_params_store(
3687                        frame.value_stack_depth_after(),
3688                        frame.param_types.len(),
3689                    )?;
3690                } else if !frame.return_types.is_empty() {
3691                    self.emit_return_values(
3692                        frame.value_stack_depth_after(),
3693                        frame.return_types.len(),
3694                    )?;
3695                }
3696                let stack_len = self.control_stack.len();
3697                let frame = &mut self.control_stack[stack_len - 1 - (relative_depth as usize)];
3698                let stack_depth = frame.value_stack_depth_for_release();
3699                let label = frame.label;
3700                self.release_stack_locations_keep_stack_offset(stack_depth)?;
3701                self.machine.jmp_unconditional(label)?;
3702
3703                self.machine.emit_label(after)?;
3704            }
3705            Operator::BrTable { ref targets } => {
3706                let default_target = targets.default();
3707                let targets = targets
3708                    .targets()
3709                    .collect::<Result<Vec<_>, _>>()
3710                    .map_err(|e| CompileError::Codegen(format!("BrTable read_table: {e:?}")))?;
3711                let cond = self.pop_value_released()?.0;
3712                let table_label = self.machine.get_label();
3713                let mut table: Vec<Label> = vec![];
3714                let default_br = self.machine.get_label();
3715                self.machine.jmp_on_condition(
3716                    UnsignedCondition::AboveEqual,
3717                    Size::S32,
3718                    cond,
3719                    Location::Imm32(targets.len() as u32),
3720                    default_br,
3721                )?;
3722
3723                self.machine.emit_jmp_to_jumptable(table_label, cond)?;
3724
3725                for target in targets.iter() {
3726                    let label = self.machine.get_label();
3727                    self.machine.emit_label(label)?;
3728                    table.push(label);
3729                    let frame =
3730                        &self.control_stack[self.control_stack.len() - 1 - (*target as usize)];
3731                    if matches!(frame.state, ControlState::Loop) {
3732                        // Store into the PHI params of the loop, not to the return values.
3733                        self.emit_loop_params_store(
3734                            frame.value_stack_depth_after(),
3735                            frame.param_types.len(),
3736                        )?;
3737                    } else if !frame.return_types.is_empty() {
3738                        self.emit_return_values(
3739                            frame.value_stack_depth_after(),
3740                            frame.return_types.len(),
3741                        )?;
3742                    }
3743                    let frame =
3744                        &self.control_stack[self.control_stack.len() - 1 - (*target as usize)];
3745                    let stack_depth = frame.value_stack_depth_for_release();
3746                    let label = frame.label;
3747                    self.release_stack_locations_keep_stack_offset(stack_depth)?;
3748                    self.machine.jmp_unconditional(label)?;
3749                    self.ensure_output_size_within_limit()?;
3750                }
3751                self.machine.emit_label(default_br)?;
3752
3753                {
3754                    let frame = &self.control_stack
3755                        [self.control_stack.len() - 1 - (default_target as usize)];
3756                    if matches!(frame.state, ControlState::Loop) {
3757                        // Store into the PHI params of the loop, not to the return values.
3758                        self.emit_loop_params_store(
3759                            frame.value_stack_depth_after(),
3760                            frame.param_types.len(),
3761                        )?;
3762                    } else if !frame.return_types.is_empty() {
3763                        self.emit_return_values(
3764                            frame.value_stack_depth_after(),
3765                            frame.return_types.len(),
3766                        )?;
3767                    }
3768                    let frame = &self.control_stack
3769                        [self.control_stack.len() - 1 - (default_target as usize)];
3770                    let stack_depth = frame.value_stack_depth_for_release();
3771                    let label = frame.label;
3772                    self.release_stack_locations_keep_stack_offset(stack_depth)?;
3773                    self.machine.jmp_unconditional(label)?;
3774                }
3775
3776                self.machine.emit_label(table_label)?;
3777                for x in table {
3778                    self.machine.jmp_unconditional(x)?;
3779                    self.ensure_output_size_within_limit()?;
3780                }
3781                self.unreachable_depth = 1;
3782            }
3783            Operator::Drop => {
3784                self.pop_value_released()?;
3785            }
3786            Operator::End => {
3787                let frame = self.control_stack.pop().unwrap();
3788
3789                if !was_unreachable && !frame.return_types.is_empty() {
3790                    self.emit_return_values(
3791                        frame.value_stack_depth_after(),
3792                        frame.return_types.len(),
3793                    )?;
3794                }
3795
3796                if self.control_stack.is_empty() {
3797                    self.machine.emit_label(frame.label)?;
3798                    self.finalize_locals()?;
3799                    self.machine.emit_function_epilog()?;
3800
3801                    // Make a copy of the return value in XMM0, as required by the SysV CC.
3802                    #[allow(clippy::collapsible_if, reason = "hard to read otherwise")]
3803                    if let Ok(&return_type) = self.signature.results().iter().exactly_one()
3804                        && (return_type == Type::F32 || return_type == Type::F64)
3805                    {
3806                        self.machine.emit_function_return_float()?;
3807                    }
3808                    self.machine.emit_ret()?;
3809                } else {
3810                    let released = &self.value_stack.clone()[frame.value_stack_depth_after()..];
3811                    self.release_locations(released)?;
3812                    self.value_stack.truncate(frame.value_stack_depth_after());
3813
3814                    if !matches!(frame.state, ControlState::Loop) {
3815                        self.machine.emit_label(frame.label)?;
3816                    }
3817
3818                    if let ControlState::If { label_else, .. } = frame.state {
3819                        self.machine.emit_label(label_else)?;
3820                    }
3821
3822                    // At this point the return values are properly sitting in the value_stack and are properly canonicalized.
3823                }
3824            }
3825            Operator::AtomicFence => {
3826                // Fence is a nop.
3827                //
3828                // Fence was added to preserve information about fences from
3829                // source languages. If in the future Wasm extends the memory
3830                // model, and if we hadn't recorded what fences used to be there,
3831                // it would lead to data races that weren't present in the
3832                // original source language.
3833                self.machine.emit_memory_fence()?;
3834            }
3835            Operator::I32AtomicLoad { ref memarg } => {
3836                let target = self.pop_value_released()?.0;
3837                let ret = self.acquire_location(&WpType::I32)?;
3838                self.value_stack.push((ret, CanonicalizeType::None));
3839                self.op_memory(
3840                    MemoryIndex::from_u32(memarg.memory),
3841                    |this,
3842                     need_check,
3843                     imported_memories,
3844                     offset,
3845                     heap_access_oob,
3846                     unaligned_atomic| {
3847                        this.machine.i32_atomic_load(
3848                            target,
3849                            memarg,
3850                            ret,
3851                            need_check,
3852                            imported_memories,
3853                            offset,
3854                            heap_access_oob,
3855                            unaligned_atomic,
3856                        )
3857                    },
3858                )?;
3859            }
3860            Operator::I32AtomicLoad8U { ref memarg } => {
3861                let target = self.pop_value_released()?.0;
3862                let ret = self.acquire_location(&WpType::I32)?;
3863                self.value_stack.push((ret, CanonicalizeType::None));
3864                self.op_memory(
3865                    MemoryIndex::from_u32(memarg.memory),
3866                    |this,
3867                     need_check,
3868                     imported_memories,
3869                     offset,
3870                     heap_access_oob,
3871                     unaligned_atomic| {
3872                        this.machine.i32_atomic_load_8u(
3873                            target,
3874                            memarg,
3875                            ret,
3876                            need_check,
3877                            imported_memories,
3878                            offset,
3879                            heap_access_oob,
3880                            unaligned_atomic,
3881                        )
3882                    },
3883                )?;
3884            }
3885            Operator::I32AtomicLoad16U { ref memarg } => {
3886                let target = self.pop_value_released()?.0;
3887                let ret = self.acquire_location(&WpType::I32)?;
3888                self.value_stack.push((ret, CanonicalizeType::None));
3889                self.op_memory(
3890                    MemoryIndex::from_u32(memarg.memory),
3891                    |this,
3892                     need_check,
3893                     imported_memories,
3894                     offset,
3895                     heap_access_oob,
3896                     unaligned_atomic| {
3897                        this.machine.i32_atomic_load_16u(
3898                            target,
3899                            memarg,
3900                            ret,
3901                            need_check,
3902                            imported_memories,
3903                            offset,
3904                            heap_access_oob,
3905                            unaligned_atomic,
3906                        )
3907                    },
3908                )?;
3909            }
3910            Operator::I32AtomicStore { ref memarg } => {
3911                let target_value = self.pop_value_released()?.0;
3912                let target_addr = self.pop_value_released()?.0;
3913                self.op_memory(
3914                    MemoryIndex::from_u32(memarg.memory),
3915                    |this,
3916                     need_check,
3917                     imported_memories,
3918                     offset,
3919                     heap_access_oob,
3920                     unaligned_atomic| {
3921                        this.machine.i32_atomic_save(
3922                            target_value,
3923                            memarg,
3924                            target_addr,
3925                            need_check,
3926                            imported_memories,
3927                            offset,
3928                            heap_access_oob,
3929                            unaligned_atomic,
3930                        )
3931                    },
3932                )?;
3933            }
3934            Operator::I32AtomicStore8 { ref memarg } => {
3935                let target_value = self.pop_value_released()?.0;
3936                let target_addr = self.pop_value_released()?.0;
3937                self.op_memory(
3938                    MemoryIndex::from_u32(memarg.memory),
3939                    |this,
3940                     need_check,
3941                     imported_memories,
3942                     offset,
3943                     heap_access_oob,
3944                     unaligned_atomic| {
3945                        this.machine.i32_atomic_save_8(
3946                            target_value,
3947                            memarg,
3948                            target_addr,
3949                            need_check,
3950                            imported_memories,
3951                            offset,
3952                            heap_access_oob,
3953                            unaligned_atomic,
3954                        )
3955                    },
3956                )?;
3957            }
3958            Operator::I32AtomicStore16 { ref memarg } => {
3959                let target_value = self.pop_value_released()?.0;
3960                let target_addr = self.pop_value_released()?.0;
3961                self.op_memory(
3962                    MemoryIndex::from_u32(memarg.memory),
3963                    |this,
3964                     need_check,
3965                     imported_memories,
3966                     offset,
3967                     heap_access_oob,
3968                     unaligned_atomic| {
3969                        this.machine.i32_atomic_save_16(
3970                            target_value,
3971                            memarg,
3972                            target_addr,
3973                            need_check,
3974                            imported_memories,
3975                            offset,
3976                            heap_access_oob,
3977                            unaligned_atomic,
3978                        )
3979                    },
3980                )?;
3981            }
3982            Operator::I64AtomicLoad { ref memarg } => {
3983                let target = self.pop_value_released()?.0;
3984                let ret = self.acquire_location(&WpType::I64)?;
3985                self.value_stack.push((ret, CanonicalizeType::None));
3986                self.op_memory(
3987                    MemoryIndex::from_u32(memarg.memory),
3988                    |this,
3989                     need_check,
3990                     imported_memories,
3991                     offset,
3992                     heap_access_oob,
3993                     unaligned_atomic| {
3994                        this.machine.i64_atomic_load(
3995                            target,
3996                            memarg,
3997                            ret,
3998                            need_check,
3999                            imported_memories,
4000                            offset,
4001                            heap_access_oob,
4002                            unaligned_atomic,
4003                        )
4004                    },
4005                )?;
4006            }
4007            Operator::I64AtomicLoad8U { ref memarg } => {
4008                let target = self.pop_value_released()?.0;
4009                let ret = self.acquire_location(&WpType::I64)?;
4010                self.value_stack.push((ret, CanonicalizeType::None));
4011                self.op_memory(
4012                    MemoryIndex::from_u32(memarg.memory),
4013                    |this,
4014                     need_check,
4015                     imported_memories,
4016                     offset,
4017                     heap_access_oob,
4018                     unaligned_atomic| {
4019                        this.machine.i64_atomic_load_8u(
4020                            target,
4021                            memarg,
4022                            ret,
4023                            need_check,
4024                            imported_memories,
4025                            offset,
4026                            heap_access_oob,
4027                            unaligned_atomic,
4028                        )
4029                    },
4030                )?;
4031            }
4032            Operator::I64AtomicLoad16U { ref memarg } => {
4033                let target = self.pop_value_released()?.0;
4034                let ret = self.acquire_location(&WpType::I64)?;
4035                self.value_stack.push((ret, CanonicalizeType::None));
4036                self.op_memory(
4037                    MemoryIndex::from_u32(memarg.memory),
4038                    |this,
4039                     need_check,
4040                     imported_memories,
4041                     offset,
4042                     heap_access_oob,
4043                     unaligned_atomic| {
4044                        this.machine.i64_atomic_load_16u(
4045                            target,
4046                            memarg,
4047                            ret,
4048                            need_check,
4049                            imported_memories,
4050                            offset,
4051                            heap_access_oob,
4052                            unaligned_atomic,
4053                        )
4054                    },
4055                )?;
4056            }
4057            Operator::I64AtomicLoad32U { ref memarg } => {
4058                let target = self.pop_value_released()?.0;
4059                let ret = self.acquire_location(&WpType::I64)?;
4060                self.value_stack.push((ret, CanonicalizeType::None));
4061                self.op_memory(
4062                    MemoryIndex::from_u32(memarg.memory),
4063                    |this,
4064                     need_check,
4065                     imported_memories,
4066                     offset,
4067                     heap_access_oob,
4068                     unaligned_atomic| {
4069                        this.machine.i64_atomic_load_32u(
4070                            target,
4071                            memarg,
4072                            ret,
4073                            need_check,
4074                            imported_memories,
4075                            offset,
4076                            heap_access_oob,
4077                            unaligned_atomic,
4078                        )
4079                    },
4080                )?;
4081            }
4082            Operator::I64AtomicStore { ref memarg } => {
4083                let target_value = self.pop_value_released()?.0;
4084                let target_addr = self.pop_value_released()?.0;
4085                self.op_memory(
4086                    MemoryIndex::from_u32(memarg.memory),
4087                    |this,
4088                     need_check,
4089                     imported_memories,
4090                     offset,
4091                     heap_access_oob,
4092                     unaligned_atomic| {
4093                        this.machine.i64_atomic_save(
4094                            target_value,
4095                            memarg,
4096                            target_addr,
4097                            need_check,
4098                            imported_memories,
4099                            offset,
4100                            heap_access_oob,
4101                            unaligned_atomic,
4102                        )
4103                    },
4104                )?;
4105            }
4106            Operator::I64AtomicStore8 { ref memarg } => {
4107                let target_value = self.pop_value_released()?.0;
4108                let target_addr = self.pop_value_released()?.0;
4109                self.op_memory(
4110                    MemoryIndex::from_u32(memarg.memory),
4111                    |this,
4112                     need_check,
4113                     imported_memories,
4114                     offset,
4115                     heap_access_oob,
4116                     unaligned_atomic| {
4117                        this.machine.i64_atomic_save_8(
4118                            target_value,
4119                            memarg,
4120                            target_addr,
4121                            need_check,
4122                            imported_memories,
4123                            offset,
4124                            heap_access_oob,
4125                            unaligned_atomic,
4126                        )
4127                    },
4128                )?;
4129            }
4130            Operator::I64AtomicStore16 { ref memarg } => {
4131                let target_value = self.pop_value_released()?.0;
4132                let target_addr = self.pop_value_released()?.0;
4133                self.op_memory(
4134                    MemoryIndex::from_u32(memarg.memory),
4135                    |this,
4136                     need_check,
4137                     imported_memories,
4138                     offset,
4139                     heap_access_oob,
4140                     unaligned_atomic| {
4141                        this.machine.i64_atomic_save_16(
4142                            target_value,
4143                            memarg,
4144                            target_addr,
4145                            need_check,
4146                            imported_memories,
4147                            offset,
4148                            heap_access_oob,
4149                            unaligned_atomic,
4150                        )
4151                    },
4152                )?;
4153            }
4154            Operator::I64AtomicStore32 { ref memarg } => {
4155                let target_value = self.pop_value_released()?.0;
4156                let target_addr = self.pop_value_released()?.0;
4157                self.op_memory(
4158                    MemoryIndex::from_u32(memarg.memory),
4159                    |this,
4160                     need_check,
4161                     imported_memories,
4162                     offset,
4163                     heap_access_oob,
4164                     unaligned_atomic| {
4165                        this.machine.i64_atomic_save_32(
4166                            target_value,
4167                            memarg,
4168                            target_addr,
4169                            need_check,
4170                            imported_memories,
4171                            offset,
4172                            heap_access_oob,
4173                            unaligned_atomic,
4174                        )
4175                    },
4176                )?;
4177            }
4178            Operator::I32AtomicRmwAdd { ref memarg } => {
4179                let loc = self.pop_value_released()?.0;
4180                let target = self.pop_value_released()?.0;
4181                let ret = self.acquire_location(&WpType::I32)?;
4182                self.value_stack.push((ret, CanonicalizeType::None));
4183                self.op_memory(
4184                    MemoryIndex::from_u32(memarg.memory),
4185                    |this,
4186                     need_check,
4187                     imported_memories,
4188                     offset,
4189                     heap_access_oob,
4190                     unaligned_atomic| {
4191                        this.machine.i32_atomic_add(
4192                            loc,
4193                            target,
4194                            memarg,
4195                            ret,
4196                            need_check,
4197                            imported_memories,
4198                            offset,
4199                            heap_access_oob,
4200                            unaligned_atomic,
4201                        )
4202                    },
4203                )?;
4204            }
4205            Operator::I64AtomicRmwAdd { ref memarg } => {
4206                let loc = self.pop_value_released()?.0;
4207                let target = self.pop_value_released()?.0;
4208                let ret = self.acquire_location(&WpType::I64)?;
4209                self.value_stack.push((ret, CanonicalizeType::None));
4210                self.op_memory(
4211                    MemoryIndex::from_u32(memarg.memory),
4212                    |this,
4213                     need_check,
4214                     imported_memories,
4215                     offset,
4216                     heap_access_oob,
4217                     unaligned_atomic| {
4218                        this.machine.i64_atomic_add(
4219                            loc,
4220                            target,
4221                            memarg,
4222                            ret,
4223                            need_check,
4224                            imported_memories,
4225                            offset,
4226                            heap_access_oob,
4227                            unaligned_atomic,
4228                        )
4229                    },
4230                )?;
4231            }
4232            Operator::I32AtomicRmw8AddU { ref memarg } => {
4233                let loc = self.pop_value_released()?.0;
4234                let target = self.pop_value_released()?.0;
4235                let ret = self.acquire_location(&WpType::I32)?;
4236                self.value_stack.push((ret, CanonicalizeType::None));
4237                self.op_memory(
4238                    MemoryIndex::from_u32(memarg.memory),
4239                    |this,
4240                     need_check,
4241                     imported_memories,
4242                     offset,
4243                     heap_access_oob,
4244                     unaligned_atomic| {
4245                        this.machine.i32_atomic_add_8u(
4246                            loc,
4247                            target,
4248                            memarg,
4249                            ret,
4250                            need_check,
4251                            imported_memories,
4252                            offset,
4253                            heap_access_oob,
4254                            unaligned_atomic,
4255                        )
4256                    },
4257                )?;
4258            }
4259            Operator::I32AtomicRmw16AddU { ref memarg } => {
4260                let loc = self.pop_value_released()?.0;
4261                let target = self.pop_value_released()?.0;
4262                let ret = self.acquire_location(&WpType::I32)?;
4263                self.value_stack.push((ret, CanonicalizeType::None));
4264                self.op_memory(
4265                    MemoryIndex::from_u32(memarg.memory),
4266                    |this,
4267                     need_check,
4268                     imported_memories,
4269                     offset,
4270                     heap_access_oob,
4271                     unaligned_atomic| {
4272                        this.machine.i32_atomic_add_16u(
4273                            loc,
4274                            target,
4275                            memarg,
4276                            ret,
4277                            need_check,
4278                            imported_memories,
4279                            offset,
4280                            heap_access_oob,
4281                            unaligned_atomic,
4282                        )
4283                    },
4284                )?;
4285            }
4286            Operator::I64AtomicRmw8AddU { ref memarg } => {
4287                let loc = self.pop_value_released()?.0;
4288                let target = self.pop_value_released()?.0;
4289                let ret = self.acquire_location(&WpType::I64)?;
4290                self.value_stack.push((ret, CanonicalizeType::None));
4291                self.op_memory(
4292                    MemoryIndex::from_u32(memarg.memory),
4293                    |this,
4294                     need_check,
4295                     imported_memories,
4296                     offset,
4297                     heap_access_oob,
4298                     unaligned_atomic| {
4299                        this.machine.i64_atomic_add_8u(
4300                            loc,
4301                            target,
4302                            memarg,
4303                            ret,
4304                            need_check,
4305                            imported_memories,
4306                            offset,
4307                            heap_access_oob,
4308                            unaligned_atomic,
4309                        )
4310                    },
4311                )?;
4312            }
4313            Operator::I64AtomicRmw16AddU { ref memarg } => {
4314                let loc = self.pop_value_released()?.0;
4315                let target = self.pop_value_released()?.0;
4316                let ret = self.acquire_location(&WpType::I64)?;
4317                self.value_stack.push((ret, CanonicalizeType::None));
4318                self.op_memory(
4319                    MemoryIndex::from_u32(memarg.memory),
4320                    |this,
4321                     need_check,
4322                     imported_memories,
4323                     offset,
4324                     heap_access_oob,
4325                     unaligned_atomic| {
4326                        this.machine.i64_atomic_add_16u(
4327                            loc,
4328                            target,
4329                            memarg,
4330                            ret,
4331                            need_check,
4332                            imported_memories,
4333                            offset,
4334                            heap_access_oob,
4335                            unaligned_atomic,
4336                        )
4337                    },
4338                )?;
4339            }
4340            Operator::I64AtomicRmw32AddU { ref memarg } => {
4341                let loc = self.pop_value_released()?.0;
4342                let target = self.pop_value_released()?.0;
4343                let ret = self.acquire_location(&WpType::I64)?;
4344                self.value_stack.push((ret, CanonicalizeType::None));
4345                self.op_memory(
4346                    MemoryIndex::from_u32(memarg.memory),
4347                    |this,
4348                     need_check,
4349                     imported_memories,
4350                     offset,
4351                     heap_access_oob,
4352                     unaligned_atomic| {
4353                        this.machine.i64_atomic_add_32u(
4354                            loc,
4355                            target,
4356                            memarg,
4357                            ret,
4358                            need_check,
4359                            imported_memories,
4360                            offset,
4361                            heap_access_oob,
4362                            unaligned_atomic,
4363                        )
4364                    },
4365                )?;
4366            }
4367            Operator::I32AtomicRmwSub { ref memarg } => {
4368                let loc = self.pop_value_released()?.0;
4369                let target = self.pop_value_released()?.0;
4370                let ret = self.acquire_location(&WpType::I32)?;
4371                self.value_stack.push((ret, CanonicalizeType::None));
4372                self.op_memory(
4373                    MemoryIndex::from_u32(memarg.memory),
4374                    |this,
4375                     need_check,
4376                     imported_memories,
4377                     offset,
4378                     heap_access_oob,
4379                     unaligned_atomic| {
4380                        this.machine.i32_atomic_sub(
4381                            loc,
4382                            target,
4383                            memarg,
4384                            ret,
4385                            need_check,
4386                            imported_memories,
4387                            offset,
4388                            heap_access_oob,
4389                            unaligned_atomic,
4390                        )
4391                    },
4392                )?;
4393            }
4394            Operator::I64AtomicRmwSub { ref memarg } => {
4395                let loc = self.pop_value_released()?.0;
4396                let target = self.pop_value_released()?.0;
4397                let ret = self.acquire_location(&WpType::I64)?;
4398                self.value_stack.push((ret, CanonicalizeType::None));
4399                self.op_memory(
4400                    MemoryIndex::from_u32(memarg.memory),
4401                    |this,
4402                     need_check,
4403                     imported_memories,
4404                     offset,
4405                     heap_access_oob,
4406                     unaligned_atomic| {
4407                        this.machine.i64_atomic_sub(
4408                            loc,
4409                            target,
4410                            memarg,
4411                            ret,
4412                            need_check,
4413                            imported_memories,
4414                            offset,
4415                            heap_access_oob,
4416                            unaligned_atomic,
4417                        )
4418                    },
4419                )?;
4420            }
4421            Operator::I32AtomicRmw8SubU { ref memarg } => {
4422                let loc = self.pop_value_released()?.0;
4423                let target = self.pop_value_released()?.0;
4424                let ret = self.acquire_location(&WpType::I32)?;
4425                self.value_stack.push((ret, CanonicalizeType::None));
4426                self.op_memory(
4427                    MemoryIndex::from_u32(memarg.memory),
4428                    |this,
4429                     need_check,
4430                     imported_memories,
4431                     offset,
4432                     heap_access_oob,
4433                     unaligned_atomic| {
4434                        this.machine.i32_atomic_sub_8u(
4435                            loc,
4436                            target,
4437                            memarg,
4438                            ret,
4439                            need_check,
4440                            imported_memories,
4441                            offset,
4442                            heap_access_oob,
4443                            unaligned_atomic,
4444                        )
4445                    },
4446                )?;
4447            }
4448            Operator::I32AtomicRmw16SubU { ref memarg } => {
4449                let loc = self.pop_value_released()?.0;
4450                let target = self.pop_value_released()?.0;
4451                let ret = self.acquire_location(&WpType::I32)?;
4452                self.value_stack.push((ret, CanonicalizeType::None));
4453                self.op_memory(
4454                    MemoryIndex::from_u32(memarg.memory),
4455                    |this,
4456                     need_check,
4457                     imported_memories,
4458                     offset,
4459                     heap_access_oob,
4460                     unaligned_atomic| {
4461                        this.machine.i32_atomic_sub_16u(
4462                            loc,
4463                            target,
4464                            memarg,
4465                            ret,
4466                            need_check,
4467                            imported_memories,
4468                            offset,
4469                            heap_access_oob,
4470                            unaligned_atomic,
4471                        )
4472                    },
4473                )?;
4474            }
4475            Operator::I64AtomicRmw8SubU { ref memarg } => {
4476                let loc = self.pop_value_released()?.0;
4477                let target = self.pop_value_released()?.0;
4478                let ret = self.acquire_location(&WpType::I64)?;
4479                self.value_stack.push((ret, CanonicalizeType::None));
4480                self.op_memory(
4481                    MemoryIndex::from_u32(memarg.memory),
4482                    |this,
4483                     need_check,
4484                     imported_memories,
4485                     offset,
4486                     heap_access_oob,
4487                     unaligned_atomic| {
4488                        this.machine.i64_atomic_sub_8u(
4489                            loc,
4490                            target,
4491                            memarg,
4492                            ret,
4493                            need_check,
4494                            imported_memories,
4495                            offset,
4496                            heap_access_oob,
4497                            unaligned_atomic,
4498                        )
4499                    },
4500                )?;
4501            }
4502            Operator::I64AtomicRmw16SubU { ref memarg } => {
4503                let loc = self.pop_value_released()?.0;
4504                let target = self.pop_value_released()?.0;
4505                let ret = self.acquire_location(&WpType::I64)?;
4506                self.value_stack.push((ret, CanonicalizeType::None));
4507                self.op_memory(
4508                    MemoryIndex::from_u32(memarg.memory),
4509                    |this,
4510                     need_check,
4511                     imported_memories,
4512                     offset,
4513                     heap_access_oob,
4514                     unaligned_atomic| {
4515                        this.machine.i64_atomic_sub_16u(
4516                            loc,
4517                            target,
4518                            memarg,
4519                            ret,
4520                            need_check,
4521                            imported_memories,
4522                            offset,
4523                            heap_access_oob,
4524                            unaligned_atomic,
4525                        )
4526                    },
4527                )?;
4528            }
4529            Operator::I64AtomicRmw32SubU { ref memarg } => {
4530                let loc = self.pop_value_released()?.0;
4531                let target = self.pop_value_released()?.0;
4532                let ret = self.acquire_location(&WpType::I64)?;
4533                self.value_stack.push((ret, CanonicalizeType::None));
4534                self.op_memory(
4535                    MemoryIndex::from_u32(memarg.memory),
4536                    |this,
4537                     need_check,
4538                     imported_memories,
4539                     offset,
4540                     heap_access_oob,
4541                     unaligned_atomic| {
4542                        this.machine.i64_atomic_sub_32u(
4543                            loc,
4544                            target,
4545                            memarg,
4546                            ret,
4547                            need_check,
4548                            imported_memories,
4549                            offset,
4550                            heap_access_oob,
4551                            unaligned_atomic,
4552                        )
4553                    },
4554                )?;
4555            }
4556            Operator::I32AtomicRmwAnd { ref memarg } => {
4557                let loc = self.pop_value_released()?.0;
4558                let target = self.pop_value_released()?.0;
4559                let ret = self.acquire_location(&WpType::I32)?;
4560                self.value_stack.push((ret, CanonicalizeType::None));
4561                self.op_memory(
4562                    MemoryIndex::from_u32(memarg.memory),
4563                    |this,
4564                     need_check,
4565                     imported_memories,
4566                     offset,
4567                     heap_access_oob,
4568                     unaligned_atomic| {
4569                        this.machine.i32_atomic_and(
4570                            loc,
4571                            target,
4572                            memarg,
4573                            ret,
4574                            need_check,
4575                            imported_memories,
4576                            offset,
4577                            heap_access_oob,
4578                            unaligned_atomic,
4579                        )
4580                    },
4581                )?;
4582            }
4583            Operator::I64AtomicRmwAnd { ref memarg } => {
4584                let loc = self.pop_value_released()?.0;
4585                let target = self.pop_value_released()?.0;
4586                let ret = self.acquire_location(&WpType::I64)?;
4587                self.value_stack.push((ret, CanonicalizeType::None));
4588                self.op_memory(
4589                    MemoryIndex::from_u32(memarg.memory),
4590                    |this,
4591                     need_check,
4592                     imported_memories,
4593                     offset,
4594                     heap_access_oob,
4595                     unaligned_atomic| {
4596                        this.machine.i64_atomic_and(
4597                            loc,
4598                            target,
4599                            memarg,
4600                            ret,
4601                            need_check,
4602                            imported_memories,
4603                            offset,
4604                            heap_access_oob,
4605                            unaligned_atomic,
4606                        )
4607                    },
4608                )?;
4609            }
4610            Operator::I32AtomicRmw8AndU { ref memarg } => {
4611                let loc = self.pop_value_released()?.0;
4612                let target = self.pop_value_released()?.0;
4613                let ret = self.acquire_location(&WpType::I32)?;
4614                self.value_stack.push((ret, CanonicalizeType::None));
4615                self.op_memory(
4616                    MemoryIndex::from_u32(memarg.memory),
4617                    |this,
4618                     need_check,
4619                     imported_memories,
4620                     offset,
4621                     heap_access_oob,
4622                     unaligned_atomic| {
4623                        this.machine.i32_atomic_and_8u(
4624                            loc,
4625                            target,
4626                            memarg,
4627                            ret,
4628                            need_check,
4629                            imported_memories,
4630                            offset,
4631                            heap_access_oob,
4632                            unaligned_atomic,
4633                        )
4634                    },
4635                )?;
4636            }
4637            Operator::I32AtomicRmw16AndU { ref memarg } => {
4638                let loc = self.pop_value_released()?.0;
4639                let target = self.pop_value_released()?.0;
4640                let ret = self.acquire_location(&WpType::I32)?;
4641                self.value_stack.push((ret, CanonicalizeType::None));
4642                self.op_memory(
4643                    MemoryIndex::from_u32(memarg.memory),
4644                    |this,
4645                     need_check,
4646                     imported_memories,
4647                     offset,
4648                     heap_access_oob,
4649                     unaligned_atomic| {
4650                        this.machine.i32_atomic_and_16u(
4651                            loc,
4652                            target,
4653                            memarg,
4654                            ret,
4655                            need_check,
4656                            imported_memories,
4657                            offset,
4658                            heap_access_oob,
4659                            unaligned_atomic,
4660                        )
4661                    },
4662                )?;
4663            }
4664            Operator::I64AtomicRmw8AndU { ref memarg } => {
4665                let loc = self.pop_value_released()?.0;
4666                let target = self.pop_value_released()?.0;
4667                let ret = self.acquire_location(&WpType::I64)?;
4668                self.value_stack.push((ret, CanonicalizeType::None));
4669                self.op_memory(
4670                    MemoryIndex::from_u32(memarg.memory),
4671                    |this,
4672                     need_check,
4673                     imported_memories,
4674                     offset,
4675                     heap_access_oob,
4676                     unaligned_atomic| {
4677                        this.machine.i64_atomic_and_8u(
4678                            loc,
4679                            target,
4680                            memarg,
4681                            ret,
4682                            need_check,
4683                            imported_memories,
4684                            offset,
4685                            heap_access_oob,
4686                            unaligned_atomic,
4687                        )
4688                    },
4689                )?;
4690            }
4691            Operator::I64AtomicRmw16AndU { ref memarg } => {
4692                let loc = self.pop_value_released()?.0;
4693                let target = self.pop_value_released()?.0;
4694                let ret = self.acquire_location(&WpType::I64)?;
4695                self.value_stack.push((ret, CanonicalizeType::None));
4696                self.op_memory(
4697                    MemoryIndex::from_u32(memarg.memory),
4698                    |this,
4699                     need_check,
4700                     imported_memories,
4701                     offset,
4702                     heap_access_oob,
4703                     unaligned_atomic| {
4704                        this.machine.i64_atomic_and_16u(
4705                            loc,
4706                            target,
4707                            memarg,
4708                            ret,
4709                            need_check,
4710                            imported_memories,
4711                            offset,
4712                            heap_access_oob,
4713                            unaligned_atomic,
4714                        )
4715                    },
4716                )?;
4717            }
4718            Operator::I64AtomicRmw32AndU { ref memarg } => {
4719                let loc = self.pop_value_released()?.0;
4720                let target = self.pop_value_released()?.0;
4721                let ret = self.acquire_location(&WpType::I64)?;
4722                self.value_stack.push((ret, CanonicalizeType::None));
4723                self.op_memory(
4724                    MemoryIndex::from_u32(memarg.memory),
4725                    |this,
4726                     need_check,
4727                     imported_memories,
4728                     offset,
4729                     heap_access_oob,
4730                     unaligned_atomic| {
4731                        this.machine.i64_atomic_and_32u(
4732                            loc,
4733                            target,
4734                            memarg,
4735                            ret,
4736                            need_check,
4737                            imported_memories,
4738                            offset,
4739                            heap_access_oob,
4740                            unaligned_atomic,
4741                        )
4742                    },
4743                )?;
4744            }
4745            Operator::I32AtomicRmwOr { ref memarg } => {
4746                let loc = self.pop_value_released()?.0;
4747                let target = self.pop_value_released()?.0;
4748                let ret = self.acquire_location(&WpType::I32)?;
4749                self.value_stack.push((ret, CanonicalizeType::None));
4750                self.op_memory(
4751                    MemoryIndex::from_u32(memarg.memory),
4752                    |this,
4753                     need_check,
4754                     imported_memories,
4755                     offset,
4756                     heap_access_oob,
4757                     unaligned_atomic| {
4758                        this.machine.i32_atomic_or(
4759                            loc,
4760                            target,
4761                            memarg,
4762                            ret,
4763                            need_check,
4764                            imported_memories,
4765                            offset,
4766                            heap_access_oob,
4767                            unaligned_atomic,
4768                        )
4769                    },
4770                )?;
4771            }
4772            Operator::I64AtomicRmwOr { ref memarg } => {
4773                let loc = self.pop_value_released()?.0;
4774                let target = self.pop_value_released()?.0;
4775                let ret = self.acquire_location(&WpType::I64)?;
4776                self.value_stack.push((ret, CanonicalizeType::None));
4777                self.op_memory(
4778                    MemoryIndex::from_u32(memarg.memory),
4779                    |this,
4780                     need_check,
4781                     imported_memories,
4782                     offset,
4783                     heap_access_oob,
4784                     unaligned_atomic| {
4785                        this.machine.i64_atomic_or(
4786                            loc,
4787                            target,
4788                            memarg,
4789                            ret,
4790                            need_check,
4791                            imported_memories,
4792                            offset,
4793                            heap_access_oob,
4794                            unaligned_atomic,
4795                        )
4796                    },
4797                )?;
4798            }
4799            Operator::I32AtomicRmw8OrU { ref memarg } => {
4800                let loc = self.pop_value_released()?.0;
4801                let target = self.pop_value_released()?.0;
4802                let ret = self.acquire_location(&WpType::I32)?;
4803                self.value_stack.push((ret, CanonicalizeType::None));
4804                self.op_memory(
4805                    MemoryIndex::from_u32(memarg.memory),
4806                    |this,
4807                     need_check,
4808                     imported_memories,
4809                     offset,
4810                     heap_access_oob,
4811                     unaligned_atomic| {
4812                        this.machine.i32_atomic_or_8u(
4813                            loc,
4814                            target,
4815                            memarg,
4816                            ret,
4817                            need_check,
4818                            imported_memories,
4819                            offset,
4820                            heap_access_oob,
4821                            unaligned_atomic,
4822                        )
4823                    },
4824                )?;
4825            }
4826            Operator::I32AtomicRmw16OrU { ref memarg } => {
4827                let loc = self.pop_value_released()?.0;
4828                let target = self.pop_value_released()?.0;
4829                let ret = self.acquire_location(&WpType::I32)?;
4830                self.value_stack.push((ret, CanonicalizeType::None));
4831                self.op_memory(
4832                    MemoryIndex::from_u32(memarg.memory),
4833                    |this,
4834                     need_check,
4835                     imported_memories,
4836                     offset,
4837                     heap_access_oob,
4838                     unaligned_atomic| {
4839                        this.machine.i32_atomic_or_16u(
4840                            loc,
4841                            target,
4842                            memarg,
4843                            ret,
4844                            need_check,
4845                            imported_memories,
4846                            offset,
4847                            heap_access_oob,
4848                            unaligned_atomic,
4849                        )
4850                    },
4851                )?;
4852            }
4853            Operator::I64AtomicRmw8OrU { ref memarg } => {
4854                let loc = self.pop_value_released()?.0;
4855                let target = self.pop_value_released()?.0;
4856                let ret = self.acquire_location(&WpType::I64)?;
4857                self.value_stack.push((ret, CanonicalizeType::None));
4858                self.op_memory(
4859                    MemoryIndex::from_u32(memarg.memory),
4860                    |this,
4861                     need_check,
4862                     imported_memories,
4863                     offset,
4864                     heap_access_oob,
4865                     unaligned_atomic| {
4866                        this.machine.i64_atomic_or_8u(
4867                            loc,
4868                            target,
4869                            memarg,
4870                            ret,
4871                            need_check,
4872                            imported_memories,
4873                            offset,
4874                            heap_access_oob,
4875                            unaligned_atomic,
4876                        )
4877                    },
4878                )?;
4879            }
4880            Operator::I64AtomicRmw16OrU { ref memarg } => {
4881                let loc = self.pop_value_released()?.0;
4882                let target = self.pop_value_released()?.0;
4883                let ret = self.acquire_location(&WpType::I64)?;
4884                self.value_stack.push((ret, CanonicalizeType::None));
4885                self.op_memory(
4886                    MemoryIndex::from_u32(memarg.memory),
4887                    |this,
4888                     need_check,
4889                     imported_memories,
4890                     offset,
4891                     heap_access_oob,
4892                     unaligned_atomic| {
4893                        this.machine.i64_atomic_or_16u(
4894                            loc,
4895                            target,
4896                            memarg,
4897                            ret,
4898                            need_check,
4899                            imported_memories,
4900                            offset,
4901                            heap_access_oob,
4902                            unaligned_atomic,
4903                        )
4904                    },
4905                )?;
4906            }
4907            Operator::I64AtomicRmw32OrU { ref memarg } => {
4908                let loc = self.pop_value_released()?.0;
4909                let target = self.pop_value_released()?.0;
4910                let ret = self.acquire_location(&WpType::I64)?;
4911                self.value_stack.push((ret, CanonicalizeType::None));
4912                self.op_memory(
4913                    MemoryIndex::from_u32(memarg.memory),
4914                    |this,
4915                     need_check,
4916                     imported_memories,
4917                     offset,
4918                     heap_access_oob,
4919                     unaligned_atomic| {
4920                        this.machine.i64_atomic_or_32u(
4921                            loc,
4922                            target,
4923                            memarg,
4924                            ret,
4925                            need_check,
4926                            imported_memories,
4927                            offset,
4928                            heap_access_oob,
4929                            unaligned_atomic,
4930                        )
4931                    },
4932                )?;
4933            }
4934            Operator::I32AtomicRmwXor { ref memarg } => {
4935                let loc = self.pop_value_released()?.0;
4936                let target = self.pop_value_released()?.0;
4937                let ret = self.acquire_location(&WpType::I32)?;
4938                self.value_stack.push((ret, CanonicalizeType::None));
4939                self.op_memory(
4940                    MemoryIndex::from_u32(memarg.memory),
4941                    |this,
4942                     need_check,
4943                     imported_memories,
4944                     offset,
4945                     heap_access_oob,
4946                     unaligned_atomic| {
4947                        this.machine.i32_atomic_xor(
4948                            loc,
4949                            target,
4950                            memarg,
4951                            ret,
4952                            need_check,
4953                            imported_memories,
4954                            offset,
4955                            heap_access_oob,
4956                            unaligned_atomic,
4957                        )
4958                    },
4959                )?;
4960            }
4961            Operator::I64AtomicRmwXor { ref memarg } => {
4962                let loc = self.pop_value_released()?.0;
4963                let target = self.pop_value_released()?.0;
4964                let ret = self.acquire_location(&WpType::I64)?;
4965                self.value_stack.push((ret, CanonicalizeType::None));
4966                self.op_memory(
4967                    MemoryIndex::from_u32(memarg.memory),
4968                    |this,
4969                     need_check,
4970                     imported_memories,
4971                     offset,
4972                     heap_access_oob,
4973                     unaligned_atomic| {
4974                        this.machine.i64_atomic_xor(
4975                            loc,
4976                            target,
4977                            memarg,
4978                            ret,
4979                            need_check,
4980                            imported_memories,
4981                            offset,
4982                            heap_access_oob,
4983                            unaligned_atomic,
4984                        )
4985                    },
4986                )?;
4987            }
4988            Operator::I32AtomicRmw8XorU { ref memarg } => {
4989                let loc = self.pop_value_released()?.0;
4990                let target = self.pop_value_released()?.0;
4991                let ret = self.acquire_location(&WpType::I32)?;
4992                self.value_stack.push((ret, CanonicalizeType::None));
4993                self.op_memory(
4994                    MemoryIndex::from_u32(memarg.memory),
4995                    |this,
4996                     need_check,
4997                     imported_memories,
4998                     offset,
4999                     heap_access_oob,
5000                     unaligned_atomic| {
5001                        this.machine.i32_atomic_xor_8u(
5002                            loc,
5003                            target,
5004                            memarg,
5005                            ret,
5006                            need_check,
5007                            imported_memories,
5008                            offset,
5009                            heap_access_oob,
5010                            unaligned_atomic,
5011                        )
5012                    },
5013                )?;
5014            }
5015            Operator::I32AtomicRmw16XorU { ref memarg } => {
5016                let loc = self.pop_value_released()?.0;
5017                let target = self.pop_value_released()?.0;
5018                let ret = self.acquire_location(&WpType::I32)?;
5019                self.value_stack.push((ret, CanonicalizeType::None));
5020                self.op_memory(
5021                    MemoryIndex::from_u32(memarg.memory),
5022                    |this,
5023                     need_check,
5024                     imported_memories,
5025                     offset,
5026                     heap_access_oob,
5027                     unaligned_atomic| {
5028                        this.machine.i32_atomic_xor_16u(
5029                            loc,
5030                            target,
5031                            memarg,
5032                            ret,
5033                            need_check,
5034                            imported_memories,
5035                            offset,
5036                            heap_access_oob,
5037                            unaligned_atomic,
5038                        )
5039                    },
5040                )?;
5041            }
5042            Operator::I64AtomicRmw8XorU { ref memarg } => {
5043                let loc = self.pop_value_released()?.0;
5044                let target = self.pop_value_released()?.0;
5045                let ret = self.acquire_location(&WpType::I64)?;
5046                self.value_stack.push((ret, CanonicalizeType::None));
5047                self.op_memory(
5048                    MemoryIndex::from_u32(memarg.memory),
5049                    |this,
5050                     need_check,
5051                     imported_memories,
5052                     offset,
5053                     heap_access_oob,
5054                     unaligned_atomic| {
5055                        this.machine.i64_atomic_xor_8u(
5056                            loc,
5057                            target,
5058                            memarg,
5059                            ret,
5060                            need_check,
5061                            imported_memories,
5062                            offset,
5063                            heap_access_oob,
5064                            unaligned_atomic,
5065                        )
5066                    },
5067                )?;
5068            }
5069            Operator::I64AtomicRmw16XorU { ref memarg } => {
5070                let loc = self.pop_value_released()?.0;
5071                let target = self.pop_value_released()?.0;
5072                let ret = self.acquire_location(&WpType::I64)?;
5073                self.value_stack.push((ret, CanonicalizeType::None));
5074                self.op_memory(
5075                    MemoryIndex::from_u32(memarg.memory),
5076                    |this,
5077                     need_check,
5078                     imported_memories,
5079                     offset,
5080                     heap_access_oob,
5081                     unaligned_atomic| {
5082                        this.machine.i64_atomic_xor_16u(
5083                            loc,
5084                            target,
5085                            memarg,
5086                            ret,
5087                            need_check,
5088                            imported_memories,
5089                            offset,
5090                            heap_access_oob,
5091                            unaligned_atomic,
5092                        )
5093                    },
5094                )?;
5095            }
5096            Operator::I64AtomicRmw32XorU { ref memarg } => {
5097                let loc = self.pop_value_released()?.0;
5098                let target = self.pop_value_released()?.0;
5099                let ret = self.acquire_location(&WpType::I64)?;
5100                self.value_stack.push((ret, CanonicalizeType::None));
5101                self.op_memory(
5102                    MemoryIndex::from_u32(memarg.memory),
5103                    |this,
5104                     need_check,
5105                     imported_memories,
5106                     offset,
5107                     heap_access_oob,
5108                     unaligned_atomic| {
5109                        this.machine.i64_atomic_xor_32u(
5110                            loc,
5111                            target,
5112                            memarg,
5113                            ret,
5114                            need_check,
5115                            imported_memories,
5116                            offset,
5117                            heap_access_oob,
5118                            unaligned_atomic,
5119                        )
5120                    },
5121                )?;
5122            }
5123            Operator::I32AtomicRmwXchg { ref memarg } => {
5124                let loc = self.pop_value_released()?.0;
5125                let target = self.pop_value_released()?.0;
5126                let ret = self.acquire_location(&WpType::I32)?;
5127                self.value_stack.push((ret, CanonicalizeType::None));
5128                self.op_memory(
5129                    MemoryIndex::from_u32(memarg.memory),
5130                    |this,
5131                     need_check,
5132                     imported_memories,
5133                     offset,
5134                     heap_access_oob,
5135                     unaligned_atomic| {
5136                        this.machine.i32_atomic_xchg(
5137                            loc,
5138                            target,
5139                            memarg,
5140                            ret,
5141                            need_check,
5142                            imported_memories,
5143                            offset,
5144                            heap_access_oob,
5145                            unaligned_atomic,
5146                        )
5147                    },
5148                )?;
5149            }
5150            Operator::I64AtomicRmwXchg { ref memarg } => {
5151                let loc = self.pop_value_released()?.0;
5152                let target = self.pop_value_released()?.0;
5153                let ret = self.acquire_location(&WpType::I64)?;
5154                self.value_stack.push((ret, CanonicalizeType::None));
5155                self.op_memory(
5156                    MemoryIndex::from_u32(memarg.memory),
5157                    |this,
5158                     need_check,
5159                     imported_memories,
5160                     offset,
5161                     heap_access_oob,
5162                     unaligned_atomic| {
5163                        this.machine.i64_atomic_xchg(
5164                            loc,
5165                            target,
5166                            memarg,
5167                            ret,
5168                            need_check,
5169                            imported_memories,
5170                            offset,
5171                            heap_access_oob,
5172                            unaligned_atomic,
5173                        )
5174                    },
5175                )?;
5176            }
5177            Operator::I32AtomicRmw8XchgU { ref memarg } => {
5178                let loc = self.pop_value_released()?.0;
5179                let target = self.pop_value_released()?.0;
5180                let ret = self.acquire_location(&WpType::I32)?;
5181                self.value_stack.push((ret, CanonicalizeType::None));
5182                self.op_memory(
5183                    MemoryIndex::from_u32(memarg.memory),
5184                    |this,
5185                     need_check,
5186                     imported_memories,
5187                     offset,
5188                     heap_access_oob,
5189                     unaligned_atomic| {
5190                        this.machine.i32_atomic_xchg_8u(
5191                            loc,
5192                            target,
5193                            memarg,
5194                            ret,
5195                            need_check,
5196                            imported_memories,
5197                            offset,
5198                            heap_access_oob,
5199                            unaligned_atomic,
5200                        )
5201                    },
5202                )?;
5203            }
5204            Operator::I32AtomicRmw16XchgU { ref memarg } => {
5205                let loc = self.pop_value_released()?.0;
5206                let target = self.pop_value_released()?.0;
5207                let ret = self.acquire_location(&WpType::I32)?;
5208                self.value_stack.push((ret, CanonicalizeType::None));
5209                self.op_memory(
5210                    MemoryIndex::from_u32(memarg.memory),
5211                    |this,
5212                     need_check,
5213                     imported_memories,
5214                     offset,
5215                     heap_access_oob,
5216                     unaligned_atomic| {
5217                        this.machine.i32_atomic_xchg_16u(
5218                            loc,
5219                            target,
5220                            memarg,
5221                            ret,
5222                            need_check,
5223                            imported_memories,
5224                            offset,
5225                            heap_access_oob,
5226                            unaligned_atomic,
5227                        )
5228                    },
5229                )?;
5230            }
5231            Operator::I64AtomicRmw8XchgU { ref memarg } => {
5232                let loc = self.pop_value_released()?.0;
5233                let target = self.pop_value_released()?.0;
5234                let ret = self.acquire_location(&WpType::I64)?;
5235                self.value_stack.push((ret, CanonicalizeType::None));
5236                self.op_memory(
5237                    MemoryIndex::from_u32(memarg.memory),
5238                    |this,
5239                     need_check,
5240                     imported_memories,
5241                     offset,
5242                     heap_access_oob,
5243                     unaligned_atomic| {
5244                        this.machine.i64_atomic_xchg_8u(
5245                            loc,
5246                            target,
5247                            memarg,
5248                            ret,
5249                            need_check,
5250                            imported_memories,
5251                            offset,
5252                            heap_access_oob,
5253                            unaligned_atomic,
5254                        )
5255                    },
5256                )?;
5257            }
5258            Operator::I64AtomicRmw16XchgU { ref memarg } => {
5259                let loc = self.pop_value_released()?.0;
5260                let target = self.pop_value_released()?.0;
5261                let ret = self.acquire_location(&WpType::I64)?;
5262                self.value_stack.push((ret, CanonicalizeType::None));
5263                self.op_memory(
5264                    MemoryIndex::from_u32(memarg.memory),
5265                    |this,
5266                     need_check,
5267                     imported_memories,
5268                     offset,
5269                     heap_access_oob,
5270                     unaligned_atomic| {
5271                        this.machine.i64_atomic_xchg_16u(
5272                            loc,
5273                            target,
5274                            memarg,
5275                            ret,
5276                            need_check,
5277                            imported_memories,
5278                            offset,
5279                            heap_access_oob,
5280                            unaligned_atomic,
5281                        )
5282                    },
5283                )?;
5284            }
5285            Operator::I64AtomicRmw32XchgU { ref memarg } => {
5286                let loc = self.pop_value_released()?.0;
5287                let target = self.pop_value_released()?.0;
5288                let ret = self.acquire_location(&WpType::I64)?;
5289                self.value_stack.push((ret, CanonicalizeType::None));
5290                self.op_memory(
5291                    MemoryIndex::from_u32(memarg.memory),
5292                    |this,
5293                     need_check,
5294                     imported_memories,
5295                     offset,
5296                     heap_access_oob,
5297                     unaligned_atomic| {
5298                        this.machine.i64_atomic_xchg_32u(
5299                            loc,
5300                            target,
5301                            memarg,
5302                            ret,
5303                            need_check,
5304                            imported_memories,
5305                            offset,
5306                            heap_access_oob,
5307                            unaligned_atomic,
5308                        )
5309                    },
5310                )?;
5311            }
5312            Operator::I32AtomicRmwCmpxchg { ref memarg } => {
5313                let new = self.pop_value_released()?.0;
5314                let cmp = self.pop_value_released()?.0;
5315                let target = self.pop_value_released()?.0;
5316                let ret = self.acquire_location(&WpType::I32)?;
5317                self.value_stack.push((ret, CanonicalizeType::None));
5318                self.op_memory(
5319                    MemoryIndex::from_u32(memarg.memory),
5320                    |this,
5321                     need_check,
5322                     imported_memories,
5323                     offset,
5324                     heap_access_oob,
5325                     unaligned_atomic| {
5326                        this.machine.i32_atomic_cmpxchg(
5327                            new,
5328                            cmp,
5329                            target,
5330                            memarg,
5331                            ret,
5332                            need_check,
5333                            imported_memories,
5334                            offset,
5335                            heap_access_oob,
5336                            unaligned_atomic,
5337                        )
5338                    },
5339                )?;
5340            }
5341            Operator::I64AtomicRmwCmpxchg { ref memarg } => {
5342                let new = self.pop_value_released()?.0;
5343                let cmp = self.pop_value_released()?.0;
5344                let target = self.pop_value_released()?.0;
5345                let ret = self.acquire_location(&WpType::I64)?;
5346                self.value_stack.push((ret, CanonicalizeType::None));
5347                self.op_memory(
5348                    MemoryIndex::from_u32(memarg.memory),
5349                    |this,
5350                     need_check,
5351                     imported_memories,
5352                     offset,
5353                     heap_access_oob,
5354                     unaligned_atomic| {
5355                        this.machine.i64_atomic_cmpxchg(
5356                            new,
5357                            cmp,
5358                            target,
5359                            memarg,
5360                            ret,
5361                            need_check,
5362                            imported_memories,
5363                            offset,
5364                            heap_access_oob,
5365                            unaligned_atomic,
5366                        )
5367                    },
5368                )?;
5369            }
5370            Operator::I32AtomicRmw8CmpxchgU { ref memarg } => {
5371                let new = self.pop_value_released()?.0;
5372                let cmp = self.pop_value_released()?.0;
5373                let target = self.pop_value_released()?.0;
5374                let ret = self.acquire_location(&WpType::I32)?;
5375                self.value_stack.push((ret, CanonicalizeType::None));
5376                self.op_memory(
5377                    MemoryIndex::from_u32(memarg.memory),
5378                    |this,
5379                     need_check,
5380                     imported_memories,
5381                     offset,
5382                     heap_access_oob,
5383                     unaligned_atomic| {
5384                        this.machine.i32_atomic_cmpxchg_8u(
5385                            new,
5386                            cmp,
5387                            target,
5388                            memarg,
5389                            ret,
5390                            need_check,
5391                            imported_memories,
5392                            offset,
5393                            heap_access_oob,
5394                            unaligned_atomic,
5395                        )
5396                    },
5397                )?;
5398            }
5399            Operator::I32AtomicRmw16CmpxchgU { ref memarg } => {
5400                let new = self.pop_value_released()?.0;
5401                let cmp = self.pop_value_released()?.0;
5402                let target = self.pop_value_released()?.0;
5403                let ret = self.acquire_location(&WpType::I32)?;
5404                self.value_stack.push((ret, CanonicalizeType::None));
5405                self.op_memory(
5406                    MemoryIndex::from_u32(memarg.memory),
5407                    |this,
5408                     need_check,
5409                     imported_memories,
5410                     offset,
5411                     heap_access_oob,
5412                     unaligned_atomic| {
5413                        this.machine.i32_atomic_cmpxchg_16u(
5414                            new,
5415                            cmp,
5416                            target,
5417                            memarg,
5418                            ret,
5419                            need_check,
5420                            imported_memories,
5421                            offset,
5422                            heap_access_oob,
5423                            unaligned_atomic,
5424                        )
5425                    },
5426                )?;
5427            }
5428            Operator::I64AtomicRmw8CmpxchgU { ref memarg } => {
5429                let new = self.pop_value_released()?.0;
5430                let cmp = self.pop_value_released()?.0;
5431                let target = self.pop_value_released()?.0;
5432                let ret = self.acquire_location(&WpType::I64)?;
5433                self.value_stack.push((ret, CanonicalizeType::None));
5434                self.op_memory(
5435                    MemoryIndex::from_u32(memarg.memory),
5436                    |this,
5437                     need_check,
5438                     imported_memories,
5439                     offset,
5440                     heap_access_oob,
5441                     unaligned_atomic| {
5442                        this.machine.i64_atomic_cmpxchg_8u(
5443                            new,
5444                            cmp,
5445                            target,
5446                            memarg,
5447                            ret,
5448                            need_check,
5449                            imported_memories,
5450                            offset,
5451                            heap_access_oob,
5452                            unaligned_atomic,
5453                        )
5454                    },
5455                )?;
5456            }
5457            Operator::I64AtomicRmw16CmpxchgU { ref memarg } => {
5458                let new = self.pop_value_released()?.0;
5459                let cmp = self.pop_value_released()?.0;
5460                let target = self.pop_value_released()?.0;
5461                let ret = self.acquire_location(&WpType::I64)?;
5462                self.value_stack.push((ret, CanonicalizeType::None));
5463                self.op_memory(
5464                    MemoryIndex::from_u32(memarg.memory),
5465                    |this,
5466                     need_check,
5467                     imported_memories,
5468                     offset,
5469                     heap_access_oob,
5470                     unaligned_atomic| {
5471                        this.machine.i64_atomic_cmpxchg_16u(
5472                            new,
5473                            cmp,
5474                            target,
5475                            memarg,
5476                            ret,
5477                            need_check,
5478                            imported_memories,
5479                            offset,
5480                            heap_access_oob,
5481                            unaligned_atomic,
5482                        )
5483                    },
5484                )?;
5485            }
5486            Operator::I64AtomicRmw32CmpxchgU { ref memarg } => {
5487                let new = self.pop_value_released()?.0;
5488                let cmp = self.pop_value_released()?.0;
5489                let target = self.pop_value_released()?.0;
5490                let ret = self.acquire_location(&WpType::I64)?;
5491                self.value_stack.push((ret, CanonicalizeType::None));
5492                self.op_memory(
5493                    MemoryIndex::from_u32(memarg.memory),
5494                    |this,
5495                     need_check,
5496                     imported_memories,
5497                     offset,
5498                     heap_access_oob,
5499                     unaligned_atomic| {
5500                        this.machine.i64_atomic_cmpxchg_32u(
5501                            new,
5502                            cmp,
5503                            target,
5504                            memarg,
5505                            ret,
5506                            need_check,
5507                            imported_memories,
5508                            offset,
5509                            heap_access_oob,
5510                            unaligned_atomic,
5511                        )
5512                    },
5513                )?;
5514            }
5515
5516            Operator::RefNull { .. } => {
5517                self.value_stack
5518                    .push((Location::Imm64(0), CanonicalizeType::None));
5519            }
5520            Operator::RefFunc { function_index } => {
5521                self.machine.move_location(
5522                    Size::S64,
5523                    Location::Memory(
5524                        self.machine.get_vmctx_reg(),
5525                        vmctx_offset(
5526                            self.vmoffsets.vmctx_builtin_function(
5527                                VMBuiltinFunctionIndex::get_func_ref_index(),
5528                            ),
5529                        )?,
5530                    ),
5531                    Location::GPR(self.machine.get_gpr_for_call()),
5532                )?;
5533
5534                self.emit_call_native(
5535                    |this| {
5536                        this.machine
5537                            .emit_call_register(this.machine.get_gpr_for_call())
5538                    },
5539                    // [vmctx, func_index] -> funcref
5540                    iter::once((
5541                        Location::Imm32(function_index as u32),
5542                        CanonicalizeType::None,
5543                    )),
5544                    iter::once(WpType::I32),
5545                    iter::once(WpType::Ref(WpRefType::new(true, WpHeapType::FUNC).unwrap())),
5546                    NativeCallType::IncludeVMCtxArgument,
5547                )?;
5548            }
5549            Operator::RefIsNull => {
5550                let loc_a = self.pop_value_released()?.0;
5551                let ret = self.acquire_location(&WpType::I32)?;
5552                self.machine.i64_cmp_eq(loc_a, Location::Imm64(0), ret)?;
5553                self.value_stack.push((ret, CanonicalizeType::None));
5554            }
5555            Operator::TableSet { table: index } => {
5556                let table_index = TableIndex::new(index as _);
5557                let table_index_arg = self
5558                    .module
5559                    .local_table_index(table_index)
5560                    .map_or(table_index.index(), |index| index.index());
5561                let value = self.value_stack.pop().unwrap();
5562                let index = self.value_stack.pop().unwrap();
5563
5564                self.machine.move_location(
5565                    Size::S64,
5566                    Location::Memory(
5567                        self.machine.get_vmctx_reg(),
5568                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(
5569                            if self.module.local_table_index(table_index).is_some() {
5570                                VMBuiltinFunctionIndex::get_table_set_index()
5571                            } else {
5572                                VMBuiltinFunctionIndex::get_imported_table_set_index()
5573                            },
5574                        ))?,
5575                    ),
5576                    Location::GPR(self.machine.get_gpr_for_call()),
5577                )?;
5578
5579                self.emit_call_native(
5580                    |this| {
5581                        this.machine
5582                            .emit_call_register(this.machine.get_gpr_for_call())
5583                    },
5584                    // [vmctx, table_index, elem_index, reftype]
5585                    [
5586                        (
5587                            Location::Imm32(table_index_arg as u32),
5588                            CanonicalizeType::None,
5589                        ),
5590                        index,
5591                        value,
5592                    ]
5593                    .iter()
5594                    .cloned(),
5595                    [WpType::I32, WpType::I32, WpType::I64].iter().cloned(),
5596                    iter::empty(),
5597                    NativeCallType::IncludeVMCtxArgument,
5598                )?;
5599            }
5600            Operator::TableGet { table: index } => {
5601                let table_index = TableIndex::new(index as _);
5602                let table_index_arg = self
5603                    .module
5604                    .local_table_index(table_index)
5605                    .map_or(table_index.index(), |index| index.index());
5606                let index = self.value_stack.pop().unwrap();
5607
5608                self.machine.move_location(
5609                    Size::S64,
5610                    Location::Memory(
5611                        self.machine.get_vmctx_reg(),
5612                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(
5613                            if self.module.local_table_index(table_index).is_some() {
5614                                VMBuiltinFunctionIndex::get_table_get_index()
5615                            } else {
5616                                VMBuiltinFunctionIndex::get_imported_table_get_index()
5617                            },
5618                        ))?,
5619                    ),
5620                    Location::GPR(self.machine.get_gpr_for_call()),
5621                )?;
5622
5623                self.emit_call_native(
5624                    |this| {
5625                        this.machine
5626                            .emit_call_register(this.machine.get_gpr_for_call())
5627                    },
5628                    // [vmctx, table_index, elem_index] -> reftype
5629                    [
5630                        (
5631                            Location::Imm32(table_index_arg as u32),
5632                            CanonicalizeType::None,
5633                        ),
5634                        index,
5635                    ]
5636                    .iter()
5637                    .cloned(),
5638                    [WpType::I32, WpType::I32].iter().cloned(),
5639                    iter::once(WpType::Ref(WpRefType::new(true, WpHeapType::FUNC).unwrap())),
5640                    NativeCallType::IncludeVMCtxArgument,
5641                )?;
5642            }
5643            Operator::TableSize { table: index } => {
5644                let table_index = TableIndex::new(index as _);
5645                let table_index_arg = self
5646                    .module
5647                    .local_table_index(table_index)
5648                    .map_or(table_index.index(), |index| index.index());
5649
5650                self.machine.move_location(
5651                    Size::S64,
5652                    Location::Memory(
5653                        self.machine.get_vmctx_reg(),
5654                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(
5655                            if self.module.local_table_index(table_index).is_some() {
5656                                VMBuiltinFunctionIndex::get_table_size_index()
5657                            } else {
5658                                VMBuiltinFunctionIndex::get_imported_table_size_index()
5659                            },
5660                        ))?,
5661                    ),
5662                    Location::GPR(self.machine.get_gpr_for_call()),
5663                )?;
5664
5665                self.emit_call_native(
5666                    |this| {
5667                        this.machine
5668                            .emit_call_register(this.machine.get_gpr_for_call())
5669                    },
5670                    // [vmctx, table_index] -> i32
5671                    iter::once((
5672                        Location::Imm32(table_index_arg as u32),
5673                        CanonicalizeType::None,
5674                    )),
5675                    iter::once(WpType::I32),
5676                    iter::once(WpType::I32),
5677                    NativeCallType::IncludeVMCtxArgument,
5678                )?;
5679            }
5680            Operator::TableGrow { table: index } => {
5681                let table_index = TableIndex::new(index as _);
5682                let table_index_arg = self
5683                    .module
5684                    .local_table_index(table_index)
5685                    .map_or(table_index.index(), |index| index.index());
5686                let delta = self.value_stack.pop().unwrap();
5687                let init_value = self.value_stack.pop().unwrap();
5688
5689                self.machine.move_location(
5690                    Size::S64,
5691                    Location::Memory(
5692                        self.machine.get_vmctx_reg(),
5693                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(
5694                            if self.module.local_table_index(table_index).is_some() {
5695                                VMBuiltinFunctionIndex::get_table_grow_index()
5696                            } else {
5697                                VMBuiltinFunctionIndex::get_imported_table_grow_index()
5698                            },
5699                        ))?,
5700                    ),
5701                    Location::GPR(self.machine.get_gpr_for_call()),
5702                )?;
5703
5704                self.emit_call_native(
5705                    |this| {
5706                        this.machine
5707                            .emit_call_register(this.machine.get_gpr_for_call())
5708                    },
5709                    // [vmctx, init_value, delta, table_index] -> u32
5710                    [
5711                        init_value,
5712                        delta,
5713                        (
5714                            Location::Imm32(table_index_arg as u32),
5715                            CanonicalizeType::None,
5716                        ),
5717                    ]
5718                    .iter()
5719                    .cloned(),
5720                    [WpType::I64, WpType::I32, WpType::I32].iter().cloned(),
5721                    iter::once(WpType::I32),
5722                    NativeCallType::IncludeVMCtxArgument,
5723                )?;
5724            }
5725            Operator::TableCopy {
5726                dst_table,
5727                src_table,
5728            } => {
5729                let len = self.value_stack.pop().unwrap();
5730                let src = self.value_stack.pop().unwrap();
5731                let dest = self.value_stack.pop().unwrap();
5732
5733                self.machine.move_location(
5734                    Size::S64,
5735                    Location::Memory(
5736                        self.machine.get_vmctx_reg(),
5737                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(
5738                            VMBuiltinFunctionIndex::get_table_copy_index(),
5739                        ))?,
5740                    ),
5741                    Location::GPR(self.machine.get_gpr_for_call()),
5742                )?;
5743
5744                self.emit_call_native(
5745                    |this| {
5746                        this.machine
5747                            .emit_call_register(this.machine.get_gpr_for_call())
5748                    },
5749                    // [vmctx, dst_table_index, src_table_index, dst, src, len]
5750                    [
5751                        (Location::Imm32(dst_table), CanonicalizeType::None),
5752                        (Location::Imm32(src_table), CanonicalizeType::None),
5753                        dest,
5754                        src,
5755                        len,
5756                    ]
5757                    .iter()
5758                    .cloned(),
5759                    [
5760                        WpType::I32,
5761                        WpType::I32,
5762                        WpType::I32,
5763                        WpType::I32,
5764                        WpType::I32,
5765                    ]
5766                    .iter()
5767                    .cloned(),
5768                    iter::empty(),
5769                    NativeCallType::IncludeVMCtxArgument,
5770                )?;
5771            }
5772
5773            Operator::TableFill { table } => {
5774                let len = self.value_stack.pop().unwrap();
5775                let val = self.value_stack.pop().unwrap();
5776                let dest = self.value_stack.pop().unwrap();
5777
5778                self.machine.move_location(
5779                    Size::S64,
5780                    Location::Memory(
5781                        self.machine.get_vmctx_reg(),
5782                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(
5783                            VMBuiltinFunctionIndex::get_table_fill_index(),
5784                        ))?,
5785                    ),
5786                    Location::GPR(self.machine.get_gpr_for_call()),
5787                )?;
5788
5789                self.emit_call_native(
5790                    |this| {
5791                        this.machine
5792                            .emit_call_register(this.machine.get_gpr_for_call())
5793                    },
5794                    // [vmctx, table_index, start_idx, item, len]
5795                    [
5796                        (Location::Imm32(table), CanonicalizeType::None),
5797                        dest,
5798                        val,
5799                        len,
5800                    ]
5801                    .iter()
5802                    .cloned(),
5803                    [WpType::I32, WpType::I32, WpType::I64, WpType::I32]
5804                        .iter()
5805                        .cloned(),
5806                    iter::empty(),
5807                    NativeCallType::IncludeVMCtxArgument,
5808                )?;
5809            }
5810            Operator::TableInit { elem_index, table } => {
5811                let len = self.value_stack.pop().unwrap();
5812                let src = self.value_stack.pop().unwrap();
5813                let dest = self.value_stack.pop().unwrap();
5814
5815                self.machine.move_location(
5816                    Size::S64,
5817                    Location::Memory(
5818                        self.machine.get_vmctx_reg(),
5819                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(
5820                            VMBuiltinFunctionIndex::get_table_init_index(),
5821                        ))?,
5822                    ),
5823                    Location::GPR(self.machine.get_gpr_for_call()),
5824                )?;
5825
5826                self.emit_call_native(
5827                    |this| {
5828                        this.machine
5829                            .emit_call_register(this.machine.get_gpr_for_call())
5830                    },
5831                    // [vmctx, table_index, elem_index, dst, src, len]
5832                    [
5833                        (Location::Imm32(table), CanonicalizeType::None),
5834                        (Location::Imm32(elem_index), CanonicalizeType::None),
5835                        dest,
5836                        src,
5837                        len,
5838                    ]
5839                    .iter()
5840                    .cloned(),
5841                    [
5842                        WpType::I32,
5843                        WpType::I32,
5844                        WpType::I32,
5845                        WpType::I32,
5846                        WpType::I32,
5847                    ]
5848                    .iter()
5849                    .cloned(),
5850                    iter::empty(),
5851                    NativeCallType::IncludeVMCtxArgument,
5852                )?;
5853            }
5854            Operator::ElemDrop { elem_index } => {
5855                self.machine.move_location(
5856                    Size::S64,
5857                    Location::Memory(
5858                        self.machine.get_vmctx_reg(),
5859                        vmctx_offset(
5860                            self.vmoffsets.vmctx_builtin_function(
5861                                VMBuiltinFunctionIndex::get_elem_drop_index(),
5862                            ),
5863                        )?,
5864                    ),
5865                    Location::GPR(self.machine.get_gpr_for_call()),
5866                )?;
5867
5868                self.emit_call_native(
5869                    |this| {
5870                        this.machine
5871                            .emit_call_register(this.machine.get_gpr_for_call())
5872                    },
5873                    // [vmctx, elem_index]
5874                    iter::once((Location::Imm32(elem_index), CanonicalizeType::None)),
5875                    [WpType::I32].iter().cloned(),
5876                    iter::empty(),
5877                    NativeCallType::IncludeVMCtxArgument,
5878                )?;
5879            }
5880            Operator::MemoryAtomicWait32 { ref memarg } => {
5881                let timeout = self.value_stack.pop().unwrap();
5882                let val = self.value_stack.pop().unwrap();
5883                let dst = self.value_stack.pop().unwrap();
5884                let dst = self.fold_atomic_mem_addr(dst, memarg)?;
5885
5886                let memory_index = MemoryIndex::new(memarg.memory as usize);
5887                let (memory_atomic_wait32, index_arg) =
5888                    if let Some(local_index) = self.module.local_memory_index(memory_index) {
5889                        (
5890                            VMBuiltinFunctionIndex::get_memory_atomic_wait32_index(),
5891                            local_index.as_u32(),
5892                        )
5893                    } else {
5894                        (
5895                            VMBuiltinFunctionIndex::get_imported_memory_atomic_wait32_index(),
5896                            memory_index.as_u32(),
5897                        )
5898                    };
5899
5900                self.machine.move_location(
5901                    Size::S64,
5902                    Location::Memory(
5903                        self.machine.get_vmctx_reg(),
5904                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(memory_atomic_wait32))?,
5905                    ),
5906                    Location::GPR(self.machine.get_gpr_for_call()),
5907                )?;
5908
5909                self.emit_call_native(
5910                    |this| {
5911                        this.machine
5912                            .emit_call_register(this.machine.get_gpr_for_call())
5913                    },
5914                    // [vmctx, memory_index, dst, src, timeout]
5915                    [
5916                        (Location::Imm32(index_arg), CanonicalizeType::None),
5917                        dst,
5918                        val,
5919                        timeout,
5920                    ]
5921                    .iter()
5922                    .cloned(),
5923                    [WpType::I32, WpType::I32, WpType::I32, WpType::I64]
5924                        .iter()
5925                        .cloned(),
5926                    iter::once(WpType::I32),
5927                    NativeCallType::IncludeVMCtxArgument,
5928                )?;
5929            }
5930            Operator::MemoryAtomicWait64 { ref memarg } => {
5931                let timeout = self.value_stack.pop().unwrap();
5932                let val = self.value_stack.pop().unwrap();
5933                let dst = self.value_stack.pop().unwrap();
5934                let dst = self.fold_atomic_mem_addr(dst, memarg)?;
5935
5936                let memory_index = MemoryIndex::new(memarg.memory as usize);
5937                let (memory_atomic_wait64, index_arg) =
5938                    if let Some(local_index) = self.module.local_memory_index(memory_index) {
5939                        (
5940                            VMBuiltinFunctionIndex::get_memory_atomic_wait64_index(),
5941                            local_index.as_u32(),
5942                        )
5943                    } else {
5944                        (
5945                            VMBuiltinFunctionIndex::get_imported_memory_atomic_wait64_index(),
5946                            memory_index.as_u32(),
5947                        )
5948                    };
5949
5950                self.machine.move_location(
5951                    Size::S64,
5952                    Location::Memory(
5953                        self.machine.get_vmctx_reg(),
5954                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(memory_atomic_wait64))?,
5955                    ),
5956                    Location::GPR(self.machine.get_gpr_for_call()),
5957                )?;
5958
5959                self.emit_call_native(
5960                    |this| {
5961                        this.machine
5962                            .emit_call_register(this.machine.get_gpr_for_call())
5963                    },
5964                    // [vmctx, memory_index, dst, src, timeout]
5965                    [
5966                        (Location::Imm32(index_arg), CanonicalizeType::None),
5967                        dst,
5968                        val,
5969                        timeout,
5970                    ]
5971                    .iter()
5972                    .cloned(),
5973                    [WpType::I32, WpType::I32, WpType::I64, WpType::I64]
5974                        .iter()
5975                        .cloned(),
5976                    iter::once(WpType::I32),
5977                    NativeCallType::IncludeVMCtxArgument,
5978                )?;
5979            }
5980            Operator::MemoryAtomicNotify { ref memarg } => {
5981                let cnt = self.value_stack.pop().unwrap();
5982                let dst = self.value_stack.pop().unwrap();
5983                let dst = self.fold_atomic_mem_addr(dst, memarg)?;
5984
5985                let memory_index = MemoryIndex::new(memarg.memory as usize);
5986                let (memory_atomic_notify, index_arg) =
5987                    if let Some(local_index) = self.module.local_memory_index(memory_index) {
5988                        (
5989                            VMBuiltinFunctionIndex::get_memory_atomic_notify_index(),
5990                            local_index.as_u32(),
5991                        )
5992                    } else {
5993                        (
5994                            VMBuiltinFunctionIndex::get_imported_memory_atomic_notify_index(),
5995                            memory_index.as_u32(),
5996                        )
5997                    };
5998
5999                self.machine.move_location(
6000                    Size::S64,
6001                    Location::Memory(
6002                        self.machine.get_vmctx_reg(),
6003                        vmctx_offset(self.vmoffsets.vmctx_builtin_function(memory_atomic_notify))?,
6004                    ),
6005                    Location::GPR(self.machine.get_gpr_for_call()),
6006                )?;
6007
6008                self.emit_call_native(
6009                    |this| {
6010                        this.machine
6011                            .emit_call_register(this.machine.get_gpr_for_call())
6012                    },
6013                    // [vmctx, memory_index, dst, cnt]
6014                    [
6015                        (Location::Imm32(index_arg), CanonicalizeType::None),
6016                        dst,
6017                        cnt,
6018                    ]
6019                    .iter()
6020                    .cloned(),
6021                    [WpType::I32, WpType::I32, WpType::I32].iter().cloned(),
6022                    iter::once(WpType::I32),
6023                    NativeCallType::IncludeVMCtxArgument,
6024                )?;
6025            }
6026            _ => {
6027                return Err(CompileError::Codegen(format!(
6028                    "not yet implemented: {op:?}"
6029                )));
6030            }
6031        }
6032
6033        self.ensure_output_size_within_limit()
6034    }
6035
6036    fn add_assembly_comment(&mut self, comment: AssemblyComment) {
6037        // Collect assembly comments only if we're going to emit them.
6038        if self.config.callbacks.is_some() {
6039            self.assembly_comments
6040                .insert(self.machine.get_offset().0, comment);
6041        }
6042    }
6043
6044    pub fn finalize(
6045        mut self,
6046        data: &FunctionBodyData,
6047        arch: Architecture,
6048        target: &Target,
6049        _source_map: &WasmSourceMap,
6050    ) -> Result<CompileOutput<(CompiledFunction, Option<UnwindFrame>)>, CompileError> {
6051        self.stack_offset -= RED_ZONE_SIZE;
6052
6053        self.add_assembly_comment(AssemblyComment::TrapHandlersTable);
6054        // Generate actual code for special labels.
6055        self.machine
6056            .emit_label(self.special_labels.integer_division_by_zero)?;
6057        self.machine
6058            .emit_illegal_op(TrapCode::IntegerDivisionByZero)?;
6059
6060        self.machine
6061            .emit_label(self.special_labels.integer_overflow)?;
6062        self.machine.emit_illegal_op(TrapCode::IntegerOverflow)?;
6063
6064        self.machine
6065            .emit_label(self.special_labels.heap_access_oob)?;
6066        self.machine
6067            .emit_illegal_op(TrapCode::HeapAccessOutOfBounds)?;
6068
6069        self.machine
6070            .emit_label(self.special_labels.table_access_oob)?;
6071        self.machine
6072            .emit_illegal_op(TrapCode::TableAccessOutOfBounds)?;
6073
6074        self.machine
6075            .emit_label(self.special_labels.indirect_call_null)?;
6076        self.machine.emit_illegal_op(TrapCode::IndirectCallToNull)?;
6077
6078        self.machine.emit_label(self.special_labels.bad_signature)?;
6079        self.machine.emit_illegal_op(TrapCode::BadSignature)?;
6080
6081        self.machine
6082            .emit_label(self.special_labels.unaligned_atomic)?;
6083        self.machine.emit_illegal_op(TrapCode::UnalignedAtomic)?;
6084
6085        // Notify the assembler backend to generate necessary code at end of function.
6086        self.machine.finalize_function()?;
6087
6088        let body_len = self.machine.assembler_get_offset().0;
6089
6090        #[cfg_attr(not(feature = "unwind"), allow(unused_mut))]
6091        let mut unwind_info = None;
6092        #[cfg_attr(not(feature = "unwind"), allow(unused_mut))]
6093        let mut fde = None;
6094        #[cfg(feature = "unwind")]
6095        match self.calling_convention {
6096            CallingConvention::SystemV | CallingConvention::AppleAarch64 => {
6097                let unwind = self.machine.gen_dwarf_unwind_info(body_len);
6098                if let Some(unwind) = unwind {
6099                    fde = Some(unwind.to_fde(Address::Symbol {
6100                        symbol: WriterRelocate::FUNCTION_SYMBOL,
6101                        // In-memory compilation uses this addend to identify the
6102                        // function relocation target.
6103                        addend: if self.config.experimental_artifact {
6104                            0
6105                        } else {
6106                            self.local_func_index.index() as _
6107                        },
6108                    }));
6109                    unwind_info = Some(CompiledFunctionUnwindInfo::Dwarf);
6110                }
6111            }
6112            _ => (),
6113        };
6114
6115        let address_map =
6116            get_function_address_map(self.machine.instructions_address_map(), data, body_len);
6117        #[cfg(feature = "unwind")]
6118        if let Some(dwarf_state) = self.dwarf_state.as_mut() {
6119            for instruction in &address_map.instructions {
6120                dwarf_state.add_source_map_row(
6121                    instruction.code_offset as u64,
6122                    instruction.srcloc,
6123                    _source_map,
6124                );
6125            }
6126        }
6127        let traps = self.machine.collect_trap_information();
6128        let FinalizedAssembly {
6129            mut body,
6130            assembly_comments,
6131        } = self.machine.assembler_finalize(self.assembly_comments)?;
6132        body.shrink_to_fit();
6133
6134        self.output_reporter.finish(body.len())?;
6135
6136        if let Some(callbacks) = self.config.callbacks.as_ref() {
6137            if !self.config.experimental_artifact {
6138                callbacks.obj_memory_buffer(
6139                    &CompiledKind::Local(self.local_func_index, self.function_name.clone()),
6140                    &self.module.hash_string(),
6141                    &body,
6142                );
6143            }
6144            callbacks.asm_memory_buffer(
6145                &CompiledKind::Local(self.local_func_index, self.function_name.clone()),
6146                &self.module.hash_string(),
6147                arch,
6148                &body,
6149                assembly_comments,
6150            )?;
6151        }
6152
6153        let function = CompiledFunction {
6154            body: FunctionBody { body, unwind_info },
6155            relocations: self.relocations.clone(),
6156            frame_info: CompiledFunctionFrameInfo { traps, address_map },
6157            maximum_stack_usage: Some(self.stack_offset.maximum_offset),
6158        };
6159        if self.config.experimental_artifact {
6160            let maximum_stack_usage = function.maximum_stack_usage;
6161            let object = elf::emit_local_function(
6162                target,
6163                self.local_func_index,
6164                function,
6165                fde,
6166                #[cfg(feature = "unwind")]
6167                self.dwarf_state,
6168            )?;
6169            if let Some(callbacks) = self.config.callbacks.as_ref() {
6170                callbacks.obj_memory_buffer(
6171                    &CompiledKind::Local(self.local_func_index, self.function_name.clone()),
6172                    &self.module.hash_string(),
6173                    &object,
6174                );
6175            }
6176            Ok(CompileOutput::Object(object, maximum_stack_usage))
6177        } else {
6178            Ok(CompileOutput::InMemory((function, fde)))
6179        }
6180    }
6181    // FIXME: This implementation seems to be not enough to resolve all kinds of register dependencies
6182    // at call place.
6183    #[allow(clippy::type_complexity)]
6184    fn sort_call_movs(movs: &mut [(Location<M::GPR, M::SIMD>, M::GPR, Size)]) {
6185        for i in 0..movs.len() {
6186            for j in (i + 1)..movs.len() {
6187                if let Location::GPR(src_gpr) = movs[j].0
6188                    && src_gpr == movs[i].1
6189                {
6190                    movs.swap(i, j);
6191                }
6192            }
6193        }
6194    }
6195
6196    // Cycle detector. Uncomment this to debug possibly incorrect call-mov sequences.
6197    /*
6198    {
6199        use std::collections::{HashMap, HashSet, VecDeque};
6200        let mut mov_map: HashMap<GPR, HashSet<GPR>> = HashMap::new();
6201        for mov in movs.iter() {
6202            if let Location::GPR(src_gpr) = mov.0 {
6203                if src_gpr != mov.1 {
6204                    mov_map.entry(src_gpr).or_insert_with(|| HashSet::new()).insert(mov.1);
6205                }
6206            }
6207        }
6208
6209        for (start, _) in mov_map.iter() {
6210            let mut q: VecDeque<GPR> = VecDeque::new();
6211            let mut black: HashSet<GPR> = HashSet::new();
6212
6213            q.push_back(*start);
6214            black.insert(*start);
6215
6216            while q.len() > 0 {
6217                let reg = q.pop_front().unwrap();
6218                let empty_set = HashSet::new();
6219                for x in mov_map.get(&reg).unwrap_or(&empty_set).iter() {
6220                    if black.contains(x) {
6221                        panic!("cycle detected");
6222                    }
6223                    q.push_back(*x);
6224                    black.insert(*x);
6225                }
6226            }
6227        }
6228    }
6229    */
6230}