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