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