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