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