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