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