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