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