Skip to main content

wasmer_compiler_cranelift/
func_environ.rs

1// This file contains code from external sources.
2// Attributions: https://github.com/wasmerio/wasmer/blob/main/docs/ATTRIBUTIONS.md
3
4use crate::{
5    HashMap,
6    abi::{self},
7    heap::{Heap, HeapData, HeapStyle},
8    table::{TableData, TableSize},
9    translator::{EXN_REF_TYPE, LandingPad, TAG_TYPE, materialize_global_value},
10};
11use cranelift_codegen::{
12    cursor::FuncCursor,
13    ir::{
14        self, AbiParam, ArgumentPurpose, BlockArg, Endianness, ExceptionTableData,
15        ExceptionTableItem, ExceptionTag, Function, InstBuilder, MemFlagsData, Signature,
16        UserExternalName,
17        condcodes::IntCC,
18        immediates::{Offset32, Uimm64},
19        types::*,
20    },
21    isa::TargetFrontendConfig,
22};
23use cranelift_frontend::FunctionBuilder;
24use smallvec::SmallVec;
25use std::convert::TryFrom;
26use target_lexicon::Architecture;
27use wasmer_compiler::abi::ReturnAbi;
28use wasmer_compiler::wasmparser::HeapType;
29use wasmer_types::{
30    CompileError, FunctionIndex, GlobalIndex, LocalFunctionIndex, MemoryIndex, MemoryStyle,
31    ModuleInfo, SignatureHash, SignatureIndex, TableIndex, TableStyle, TagIndex,
32    Type as WasmerType, VMBuiltinFunctionIndex, VMOffsets, WasmError, WasmResult,
33    entity::{EntityRef, PrimaryMap, SecondaryMap},
34    vmctx_offset,
35};
36
37fn insert_mem_flags(func: &mut Function, flags: ir::MemFlagsData) -> ir::MemFlags {
38    func.dfg.mem_flags.insert(flags).unwrap()
39}
40
41/// Compute an `ir::ExternalName` for a given wasm function index.
42pub fn get_function_name(func: &mut Function, func_index: FunctionIndex) -> ir::ExternalName {
43    ir::ExternalName::user(
44        func.params
45            .ensure_user_func_name(UserExternalName::new(0, func_index.as_u32())),
46    )
47}
48
49/// The type of the `current_elements` field.
50#[allow(unused)]
51pub fn type_of_vmtable_definition_current_elements(vmoffsets: &VMOffsets) -> ir::Type {
52    ir::Type::int(u16::from(vmoffsets.size_of_vmtable_definition_current_elements()) * 8).unwrap()
53}
54
55#[derive(Clone)]
56struct ExceptionFieldLayout {
57    offset: u32,
58    ty: ir::Type,
59}
60
61#[derive(Clone)]
62struct ExceptionTypeLayout {
63    fields: SmallVec<[ExceptionFieldLayout; 4]>,
64}
65
66/// The value of a WebAssembly global variable.
67#[derive(Clone, Copy)]
68pub enum GlobalVariable {
69    #[allow(dead_code)]
70    /// This is a constant global with a value known at compile time.
71    Const(ir::Value),
72
73    /// This is a variable in memory that should be referenced through a `GlobalValue`.
74    Memory {
75        /// The address of the global variable storage.
76        gv: ir::GlobalValue,
77        /// An offset to add to the address.
78        offset: Offset32,
79        /// The global variable's type.
80        ty: ir::Type,
81    },
82
83    #[allow(dead_code)]
84    /// This is a global variable that needs to be handled by the environment.
85    Custom,
86}
87
88/// The `FuncEnvironment` implementation for use by the `ModuleEnvironment`.
89pub struct FuncEnvironment<'module_environment> {
90    /// Target-specified configuration.
91    target_config: TargetFrontendConfig,
92
93    /// Target architecture used for native ABI classification.
94    architecture: Architecture,
95
96    /// Results of the function currently being translated.
97    return_types: Vec<WasmerType>,
98
99    /// The module-level environment which this function-level environment belongs to.
100    module: &'module_environment ModuleInfo,
101
102    /// A stack tracking the type of local variables.
103    type_stack: Vec<WasmerType>,
104
105    /// The module function signatures
106    signatures: &'module_environment PrimaryMap<SignatureIndex, ir::Signature>,
107
108    /// Cached stable hashes for module signatures.
109    signature_hashes: &'module_environment PrimaryMap<SignatureIndex, SignatureHash>,
110
111    /// Heaps implementing WebAssembly linear memories.
112    heaps: PrimaryMap<Heap, HeapData>,
113
114    /// The Cranelift global holding the vmctx address.
115    vmctx: Option<ir::GlobalValue>,
116
117    /// The external function signature for implementing wasm's `memory.size`
118    /// for locally-defined 32-bit memories.
119    memory32_size_sig: Option<ir::SigRef>,
120
121    /// The external function signature for implementing wasm's `table.size`
122    /// for locally-defined tables.
123    table_size_sig: Option<ir::SigRef>,
124
125    /// The external function signature for implementing wasm's `memory.grow`
126    /// for locally-defined memories.
127    memory_grow_sig: Option<ir::SigRef>,
128
129    /// The external function signature for implementing wasm's `table.grow`
130    /// for locally-defined tables.
131    table_grow_sig: Option<ir::SigRef>,
132
133    /// The external function signature for implementing wasm's `table.copy`
134    /// (it's the same for both local and imported tables).
135    table_copy_sig: Option<ir::SigRef>,
136
137    /// The external function signature for implementing wasm's `table.init`.
138    table_init_sig: Option<ir::SigRef>,
139
140    /// The external function signature for implementing wasm's `elem.drop`.
141    elem_drop_sig: Option<ir::SigRef>,
142
143    /// The external function signature for implementing wasm's `memory.copy`
144    /// (it's the same for both local and imported memories).
145    memory_copy_sig: Option<ir::SigRef>,
146
147    /// The external function signature for implementing wasm's `memory.fill`
148    /// (it's the same for both local and imported memories).
149    memory_fill_sig: Option<ir::SigRef>,
150
151    /// The external function signature for implementing wasm's `memory.init`.
152    memory_init_sig: Option<ir::SigRef>,
153
154    /// The external function signature for implementing wasm's `data.drop`.
155    data_drop_sig: Option<ir::SigRef>,
156
157    /// The external function signature for implementing wasm's `table.get`.
158    table_get_sig: Option<ir::SigRef>,
159
160    /// The external function signature for implementing wasm's `table.set`.
161    table_set_sig: Option<ir::SigRef>,
162
163    /// The external function signature for implementing wasm's `func.ref`.
164    func_ref_sig: Option<ir::SigRef>,
165
166    /// The external function signature for implementing wasm's `table.fill`.
167    table_fill_sig: Option<ir::SigRef>,
168
169    /// The external function signature for implementing wasm's `memory32.atomic.wait32`.
170    memory32_atomic_wait32_sig: Option<ir::SigRef>,
171
172    /// The external function signature for implementing wasm's `memory32.atomic.wait64`.
173    memory32_atomic_wait64_sig: Option<ir::SigRef>,
174
175    /// The external function signature for implementing wasm's `memory32.atomic.notify`.
176    memory32_atomic_notify_sig: Option<ir::SigRef>,
177
178    /// Cached signatures for exception helper builtins.
179    raise_trap_sig: Option<ir::SigRef>,
180    personality2_sig: Option<ir::SigRef>,
181    throw_sig: Option<ir::SigRef>,
182    alloc_exception_sig: Option<ir::SigRef>,
183    read_exception_sig: Option<ir::SigRef>,
184    read_exnref_sig: Option<ir::SigRef>,
185
186    /// Cached payload layouts for exception tags.
187    exception_type_layouts: HashMap<u32, ExceptionTypeLayout>,
188
189    /// Offsets to struct fields accessed by JIT code.
190    offsets: VMOffsets,
191
192    /// The memory styles
193    memory_styles: &'module_environment PrimaryMap<MemoryIndex, MemoryStyle>,
194
195    /// Cranelift tables we have created to implement Wasm tables.
196    tables: SecondaryMap<TableIndex, Option<TableData>>,
197
198    table_styles: &'module_environment PrimaryMap<TableIndex, TableStyle>,
199}
200
201impl<'module_environment> FuncEnvironment<'module_environment> {
202    pub fn new(
203        target_config: TargetFrontendConfig,
204        architecture: Architecture,
205        module: &'module_environment ModuleInfo,
206        signatures: &'module_environment PrimaryMap<SignatureIndex, ir::Signature>,
207        signature_hashes: &'module_environment PrimaryMap<SignatureIndex, SignatureHash>,
208        memory_styles: &'module_environment PrimaryMap<MemoryIndex, MemoryStyle>,
209        table_styles: &'module_environment PrimaryMap<TableIndex, TableStyle>,
210    ) -> Result<Self, CompileError> {
211        Ok(Self {
212            target_config,
213            architecture,
214            return_types: Vec::new(),
215            module,
216            signatures,
217            signature_hashes,
218            type_stack: vec![],
219            heaps: PrimaryMap::new(),
220            vmctx: None,
221            memory32_size_sig: None,
222            table_size_sig: None,
223            memory_grow_sig: None,
224            table_grow_sig: None,
225            table_copy_sig: None,
226            table_init_sig: None,
227            elem_drop_sig: None,
228            memory_copy_sig: None,
229            memory_fill_sig: None,
230            memory_init_sig: None,
231            table_get_sig: None,
232            table_set_sig: None,
233            data_drop_sig: None,
234            func_ref_sig: None,
235            table_fill_sig: None,
236            memory32_atomic_wait32_sig: None,
237            memory32_atomic_wait64_sig: None,
238            memory32_atomic_notify_sig: None,
239            raise_trap_sig: None,
240            personality2_sig: None,
241            throw_sig: None,
242            alloc_exception_sig: None,
243            read_exception_sig: None,
244            read_exnref_sig: None,
245            exception_type_layouts: HashMap::new(),
246            offsets: VMOffsets::try_new(target_config.pointer_bytes(), module)
247                .map_err(CompileError::Resource)?,
248            memory_styles,
249            tables: Default::default(),
250            table_styles,
251        })
252    }
253
254    pub(crate) fn target_config(&self) -> TargetFrontendConfig {
255        self.target_config
256    }
257
258    pub(crate) fn pointer_type(&self) -> ir::Type {
259        self.target_config.pointer_type()
260    }
261
262    pub(crate) fn reference_type(&self) -> ir::Type {
263        self.target_config.pointer_type()
264    }
265
266    fn ensure_table_exists(
267        &mut self,
268        func: &mut ir::Function,
269        index: TableIndex,
270    ) -> WasmResult<()> {
271        if self.tables[index].is_some() {
272            return Ok(());
273        }
274
275        let pointer_type = self.pointer_type();
276        let table = &self.module.tables[index];
277
278        let (base_gv, table_base_offset, bound, element_size, inline_anyfunc) =
279            if let Some(def_index) = self.module.local_table_index(index)
280                && table.is_fixed_funcref_table()
281            {
282                (
283                    self.vmctx(func),
284                    vmctx_offset(
285                        self.offsets
286                            .vmctx_fixed_funcref_table_anyfuncs(def_index)
287                            .expect("fixed funcref table must have inline VMContext storage"),
288                    )?,
289                    TableSize::Static {
290                        bound: table.minimum,
291                    },
292                    u32::from(self.offsets.size_of_vmcaller_checked_anyfunc()),
293                    true,
294                )
295            } else {
296                let (ptr, base_offset, current_elements_offset) = {
297                    let vmctx = self.vmctx(func);
298                    if let Some(def_index) = self.module.local_table_index(index) {
299                        let base_offset =
300                            vmctx_offset(self.offsets.vmctx_vmtable_definition_base(def_index))?;
301                        let current_elements_offset = vmctx_offset(
302                            self.offsets
303                                .vmctx_vmtable_definition_current_elements(def_index),
304                        )?;
305                        (vmctx, base_offset, current_elements_offset)
306                    } else {
307                        let from_offset = self.offsets.vmctx_vmtable_import(index);
308                        let flags = insert_mem_flags(func, MemFlagsData::trusted().with_readonly());
309                        let table = func.create_global_value(ir::GlobalValueData::Load {
310                            base: vmctx,
311                            offset: Offset32::new(vmctx_offset(from_offset)?),
312                            global_type: pointer_type,
313                            flags,
314                        });
315                        let base_offset = i32::from(self.offsets.vmtable_definition_base());
316                        let current_elements_offset =
317                            i32::from(self.offsets.vmtable_definition_current_elements());
318                        (table, base_offset, current_elements_offset)
319                    }
320                };
321
322                let flags = if Some(table.minimum) == table.maximum {
323                    // A fixed-size table can't be resized so its base address won't
324                    // change.
325                    insert_mem_flags(func, MemFlagsData::trusted().with_readonly())
326                } else {
327                    insert_mem_flags(func, MemFlagsData::trusted())
328                };
329                let base_gv = func.create_global_value(ir::GlobalValueData::Load {
330                    base: ptr,
331                    offset: Offset32::new(base_offset),
332                    global_type: pointer_type,
333                    flags,
334                });
335
336                let bound = if Some(table.minimum) == table.maximum {
337                    TableSize::Static {
338                        bound: table.minimum,
339                    }
340                } else {
341                    let flags = insert_mem_flags(func, MemFlagsData::trusted());
342                    TableSize::Dynamic {
343                        bound_gv: func.create_global_value(ir::GlobalValueData::Load {
344                            base: ptr,
345                            offset: Offset32::new(current_elements_offset),
346                            global_type: ir::Type::int(
347                                u16::from(
348                                    self.offsets.size_of_vmtable_definition_current_elements(),
349                                ) * 8,
350                            )
351                            .unwrap(),
352                            flags,
353                        }),
354                    }
355                };
356
357                (base_gv, 0, bound, self.reference_type().bytes(), false)
358            };
359
360        self.tables[index] = Some(TableData {
361            base_gv,
362            base_offset: table_base_offset,
363            bound,
364            element_size,
365            inline_anyfunc,
366        });
367        Ok(())
368    }
369
370    fn vmctx(&mut self, func: &mut Function) -> ir::GlobalValue {
371        self.vmctx.unwrap_or_else(|| {
372            let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
373            self.vmctx = Some(vmctx);
374            vmctx
375        })
376    }
377
378    fn get_table_fill_sig(&mut self, func: &mut Function) -> ir::SigRef {
379        let sig = self.table_fill_sig.unwrap_or_else(|| {
380            func.import_signature(Signature {
381                params: vec![
382                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
383                    // table index
384                    AbiParam::new(I32),
385                    // dst
386                    AbiParam::new(I32),
387                    // value
388                    AbiParam::new(self.reference_type()),
389                    // len
390                    AbiParam::new(I32),
391                ],
392                returns: vec![],
393                call_conv: self.target_config.default_call_conv,
394            })
395        });
396        self.table_fill_sig = Some(sig);
397        sig
398    }
399
400    fn get_table_fill_func(
401        &mut self,
402        func: &mut Function,
403        table_index: TableIndex,
404    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
405        (
406            self.get_table_fill_sig(func),
407            table_index.index(),
408            VMBuiltinFunctionIndex::get_table_fill_index(),
409        )
410    }
411
412    fn get_func_ref_sig(&mut self, func: &mut Function) -> ir::SigRef {
413        let sig = self.func_ref_sig.unwrap_or_else(|| {
414            func.import_signature(Signature {
415                params: vec![
416                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
417                    AbiParam::new(I32),
418                ],
419                returns: vec![AbiParam::new(self.reference_type())],
420                call_conv: self.target_config.default_call_conv,
421            })
422        });
423        self.func_ref_sig = Some(sig);
424        sig
425    }
426
427    fn get_func_ref_func(
428        &mut self,
429        func: &mut Function,
430        function_index: FunctionIndex,
431    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
432        (
433            self.get_func_ref_sig(func),
434            function_index.index(),
435            VMBuiltinFunctionIndex::get_func_ref_index(),
436        )
437    }
438
439    fn get_table_get_sig(&mut self, func: &mut Function) -> ir::SigRef {
440        let sig = self.table_get_sig.unwrap_or_else(|| {
441            func.import_signature(Signature {
442                params: vec![
443                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
444                    AbiParam::new(I32),
445                    AbiParam::new(I32),
446                ],
447                returns: vec![AbiParam::new(self.reference_type())],
448                call_conv: self.target_config.default_call_conv,
449            })
450        });
451        self.table_get_sig = Some(sig);
452        sig
453    }
454
455    fn get_table_get_func(
456        &mut self,
457        func: &mut Function,
458        table_index: TableIndex,
459    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
460        if self.module.is_imported_table(table_index) {
461            (
462                self.get_table_get_sig(func),
463                table_index.index(),
464                VMBuiltinFunctionIndex::get_imported_table_get_index(),
465            )
466        } else {
467            (
468                self.get_table_get_sig(func),
469                self.module.local_table_index(table_index).unwrap().index(),
470                VMBuiltinFunctionIndex::get_table_get_index(),
471            )
472        }
473    }
474
475    fn get_table_set_sig(&mut self, func: &mut Function) -> ir::SigRef {
476        let sig = self.table_set_sig.unwrap_or_else(|| {
477            func.import_signature(Signature {
478                params: vec![
479                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
480                    AbiParam::new(I32),
481                    AbiParam::new(I32),
482                    AbiParam::new(self.reference_type()),
483                ],
484                returns: vec![],
485                call_conv: self.target_config.default_call_conv,
486            })
487        });
488        self.table_set_sig = Some(sig);
489        sig
490    }
491
492    fn get_table_set_func(
493        &mut self,
494        func: &mut Function,
495        table_index: TableIndex,
496    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
497        if self.module.is_imported_table(table_index) {
498            (
499                self.get_table_set_sig(func),
500                table_index.index(),
501                VMBuiltinFunctionIndex::get_imported_table_set_index(),
502            )
503        } else {
504            (
505                self.get_table_set_sig(func),
506                self.module.local_table_index(table_index).unwrap().index(),
507                VMBuiltinFunctionIndex::get_table_set_index(),
508            )
509        }
510    }
511
512    fn get_table_grow_sig(&mut self, func: &mut Function) -> ir::SigRef {
513        let sig = self.table_grow_sig.unwrap_or_else(|| {
514            func.import_signature(Signature {
515                params: vec![
516                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
517                    // TODO: figure out what the representation of a Wasm value is
518                    AbiParam::new(self.reference_type()),
519                    AbiParam::new(I32),
520                    AbiParam::new(I32),
521                ],
522                returns: vec![AbiParam::new(I32)],
523                call_conv: self.target_config.default_call_conv,
524            })
525        });
526        self.table_grow_sig = Some(sig);
527        sig
528    }
529
530    /// Return the table.grow function signature to call for the given index, along with the
531    /// translated index value to pass to it and its index in `VMBuiltinFunctionsArray`.
532    fn get_table_grow_func(
533        &mut self,
534        func: &mut Function,
535        index: TableIndex,
536    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
537        if self.module.is_imported_table(index) {
538            (
539                self.get_table_grow_sig(func),
540                index.index(),
541                VMBuiltinFunctionIndex::get_imported_table_grow_index(),
542            )
543        } else {
544            (
545                self.get_table_grow_sig(func),
546                self.module.local_table_index(index).unwrap().index(),
547                VMBuiltinFunctionIndex::get_table_grow_index(),
548            )
549        }
550    }
551
552    fn get_memory_grow_sig(&mut self, func: &mut Function) -> ir::SigRef {
553        let sig = self.memory_grow_sig.unwrap_or_else(|| {
554            func.import_signature(Signature {
555                params: vec![
556                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
557                    AbiParam::new(I32),
558                    AbiParam::new(I32),
559                ],
560                returns: vec![AbiParam::new(I32)],
561                call_conv: self.target_config.default_call_conv,
562            })
563        });
564        self.memory_grow_sig = Some(sig);
565        sig
566    }
567
568    /// Return the memory.grow function signature to call for the given index, along with the
569    /// translated index value to pass to it and its index in `VMBuiltinFunctionsArray`.
570    fn get_memory_grow_func(
571        &mut self,
572        func: &mut Function,
573        index: MemoryIndex,
574    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
575        if self.module.is_imported_memory(index) {
576            (
577                self.get_memory_grow_sig(func),
578                index.index(),
579                VMBuiltinFunctionIndex::get_imported_memory32_grow_index(),
580            )
581        } else {
582            (
583                self.get_memory_grow_sig(func),
584                self.module.local_memory_index(index).unwrap().index(),
585                VMBuiltinFunctionIndex::get_memory32_grow_index(),
586            )
587        }
588    }
589
590    fn get_table_size_sig(&mut self, func: &mut Function) -> ir::SigRef {
591        let sig = self.table_size_sig.unwrap_or_else(|| {
592            func.import_signature(Signature {
593                params: vec![
594                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
595                    AbiParam::new(I32),
596                ],
597                returns: vec![AbiParam::new(I32)],
598                call_conv: self.target_config.default_call_conv,
599            })
600        });
601        self.table_size_sig = Some(sig);
602        sig
603    }
604
605    /// Return the memory.size function signature to call for the given index, along with the
606    /// translated index value to pass to it and its index in `VMBuiltinFunctionsArray`.
607    fn get_table_size_func(
608        &mut self,
609        func: &mut Function,
610        index: TableIndex,
611    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
612        if self.module.is_imported_table(index) {
613            (
614                self.get_table_size_sig(func),
615                index.index(),
616                VMBuiltinFunctionIndex::get_imported_table_size_index(),
617            )
618        } else {
619            (
620                self.get_table_size_sig(func),
621                self.module.local_table_index(index).unwrap().index(),
622                VMBuiltinFunctionIndex::get_table_size_index(),
623            )
624        }
625    }
626
627    fn get_memory32_size_sig(&mut self, func: &mut Function) -> ir::SigRef {
628        let sig = self.memory32_size_sig.unwrap_or_else(|| {
629            func.import_signature(Signature {
630                params: vec![
631                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
632                    AbiParam::new(I32),
633                ],
634                returns: vec![AbiParam::new(I32)],
635                call_conv: self.target_config.default_call_conv,
636            })
637        });
638        self.memory32_size_sig = Some(sig);
639        sig
640    }
641
642    /// Return the memory.size function signature to call for the given index, along with the
643    /// translated index value to pass to it and its index in `VMBuiltinFunctionsArray`.
644    fn get_memory_size_func(
645        &mut self,
646        func: &mut Function,
647        index: MemoryIndex,
648    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
649        if self.module.is_imported_memory(index) {
650            (
651                self.get_memory32_size_sig(func),
652                index.index(),
653                VMBuiltinFunctionIndex::get_imported_memory32_size_index(),
654            )
655        } else {
656            (
657                self.get_memory32_size_sig(func),
658                self.module.local_memory_index(index).unwrap().index(),
659                VMBuiltinFunctionIndex::get_memory32_size_index(),
660            )
661        }
662    }
663
664    fn get_table_copy_sig(&mut self, func: &mut Function) -> ir::SigRef {
665        let sig = self.table_copy_sig.unwrap_or_else(|| {
666            func.import_signature(Signature {
667                params: vec![
668                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
669                    // Destination table index.
670                    AbiParam::new(I32),
671                    // Source table index.
672                    AbiParam::new(I32),
673                    // Index within destination table.
674                    AbiParam::new(I32),
675                    // Index within source table.
676                    AbiParam::new(I32),
677                    // Number of elements to copy.
678                    AbiParam::new(I32),
679                ],
680                returns: vec![],
681                call_conv: self.target_config.default_call_conv,
682            })
683        });
684        self.table_copy_sig = Some(sig);
685        sig
686    }
687
688    fn get_table_copy_func(
689        &mut self,
690        func: &mut Function,
691        dst_table_index: TableIndex,
692        src_table_index: TableIndex,
693    ) -> (ir::SigRef, usize, usize, VMBuiltinFunctionIndex) {
694        let sig = self.get_table_copy_sig(func);
695        (
696            sig,
697            dst_table_index.as_u32() as usize,
698            src_table_index.as_u32() as usize,
699            VMBuiltinFunctionIndex::get_table_copy_index(),
700        )
701    }
702
703    fn get_table_init_sig(&mut self, func: &mut Function) -> ir::SigRef {
704        let sig = self.table_init_sig.unwrap_or_else(|| {
705            func.import_signature(Signature {
706                params: vec![
707                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
708                    // Table index.
709                    AbiParam::new(I32),
710                    // Segment index.
711                    AbiParam::new(I32),
712                    // Destination index within table.
713                    AbiParam::new(I32),
714                    // Source index within segment.
715                    AbiParam::new(I32),
716                    // Number of elements to initialize.
717                    AbiParam::new(I32),
718                ],
719                returns: vec![],
720                call_conv: self.target_config.default_call_conv,
721            })
722        });
723        self.table_init_sig = Some(sig);
724        sig
725    }
726
727    fn get_table_init_func(
728        &mut self,
729        func: &mut Function,
730        table_index: TableIndex,
731    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
732        let sig = self.get_table_init_sig(func);
733        let table_index = table_index.as_u32() as usize;
734        (
735            sig,
736            table_index,
737            VMBuiltinFunctionIndex::get_table_init_index(),
738        )
739    }
740
741    fn get_elem_drop_sig(&mut self, func: &mut Function) -> ir::SigRef {
742        let sig = self.elem_drop_sig.unwrap_or_else(|| {
743            func.import_signature(Signature {
744                params: vec![
745                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
746                    // Element index.
747                    AbiParam::new(I32),
748                ],
749                returns: vec![],
750                call_conv: self.target_config.default_call_conv,
751            })
752        });
753        self.elem_drop_sig = Some(sig);
754        sig
755    }
756
757    fn get_elem_drop_func(&mut self, func: &mut Function) -> (ir::SigRef, VMBuiltinFunctionIndex) {
758        let sig = self.get_elem_drop_sig(func);
759        (sig, VMBuiltinFunctionIndex::get_elem_drop_index())
760    }
761
762    fn get_memory_copy_sig(&mut self, func: &mut Function) -> ir::SigRef {
763        let sig = self.memory_copy_sig.unwrap_or_else(|| {
764            func.import_signature(Signature {
765                params: vec![
766                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
767                    // Destination memory index.
768                    AbiParam::new(I32),
769                    // Source memory index.
770                    AbiParam::new(I32),
771                    // Destination address.
772                    AbiParam::new(I32),
773                    // Source address.
774                    AbiParam::new(I32),
775                    // Length.
776                    AbiParam::new(I32),
777                ],
778                returns: vec![],
779                call_conv: self.target_config.default_call_conv,
780            })
781        });
782        self.memory_copy_sig = Some(sig);
783        sig
784    }
785
786    fn get_memory_copy_func(
787        &mut self,
788        func: &mut Function,
789    ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
790        (
791            self.get_memory_copy_sig(func),
792            VMBuiltinFunctionIndex::get_memory_copy_index(),
793        )
794    }
795
796    fn get_memory_fill_sig(&mut self, func: &mut Function) -> ir::SigRef {
797        let sig = self.memory_fill_sig.unwrap_or_else(|| {
798            func.import_signature(Signature {
799                params: vec![
800                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
801                    // Memory index.
802                    AbiParam::new(I32),
803                    // Destination address.
804                    AbiParam::new(I32),
805                    // Value.
806                    AbiParam::new(I32),
807                    // Length.
808                    AbiParam::new(I32),
809                ],
810                returns: vec![],
811                call_conv: self.target_config.default_call_conv,
812            })
813        });
814        self.memory_fill_sig = Some(sig);
815        sig
816    }
817
818    fn get_memory_fill_func(
819        &mut self,
820        func: &mut Function,
821        memory_index: MemoryIndex,
822    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
823        let sig = self.get_memory_fill_sig(func);
824        if let Some(local_memory_index) = self.module.local_memory_index(memory_index) {
825            (
826                sig,
827                local_memory_index.index(),
828                VMBuiltinFunctionIndex::get_memory_fill_index(),
829            )
830        } else {
831            (
832                sig,
833                memory_index.index(),
834                VMBuiltinFunctionIndex::get_imported_memory_fill_index(),
835            )
836        }
837    }
838
839    fn get_memory_init_sig(&mut self, func: &mut Function) -> ir::SigRef {
840        let sig = self.memory_init_sig.unwrap_or_else(|| {
841            func.import_signature(Signature {
842                params: vec![
843                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
844                    // Memory index.
845                    AbiParam::new(I32),
846                    // Data index.
847                    AbiParam::new(I32),
848                    // Destination address.
849                    AbiParam::new(I32),
850                    // Source index within the data segment.
851                    AbiParam::new(I32),
852                    // Length.
853                    AbiParam::new(I32),
854                ],
855                returns: vec![],
856                call_conv: self.target_config.default_call_conv,
857            })
858        });
859        self.memory_init_sig = Some(sig);
860        sig
861    }
862
863    fn get_memory_init_func(
864        &mut self,
865        func: &mut Function,
866    ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
867        let sig = self.get_memory_init_sig(func);
868        (sig, VMBuiltinFunctionIndex::get_memory_init_index())
869    }
870
871    fn get_data_drop_sig(&mut self, func: &mut Function) -> ir::SigRef {
872        let sig = self.data_drop_sig.unwrap_or_else(|| {
873            func.import_signature(Signature {
874                params: vec![
875                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
876                    // Data index.
877                    AbiParam::new(I32),
878                ],
879                returns: vec![],
880                call_conv: self.target_config.default_call_conv,
881            })
882        });
883        self.data_drop_sig = Some(sig);
884        sig
885    }
886
887    fn get_data_drop_func(&mut self, func: &mut Function) -> (ir::SigRef, VMBuiltinFunctionIndex) {
888        let sig = self.get_data_drop_sig(func);
889        (sig, VMBuiltinFunctionIndex::get_data_drop_index())
890    }
891
892    fn get_memory32_atomic_wait32_sig(&mut self, func: &mut Function) -> ir::SigRef {
893        let sig = self.memory32_atomic_wait32_sig.unwrap_or_else(|| {
894            func.import_signature(Signature {
895                params: vec![
896                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
897                    // Memory Index
898                    AbiParam::new(I32),
899                    // Dst
900                    AbiParam::new(I32),
901                    // Val
902                    AbiParam::new(I32),
903                    // Timeout
904                    AbiParam::new(I64),
905                ],
906                returns: vec![AbiParam::new(I32)],
907                call_conv: self.target_config.default_call_conv,
908            })
909        });
910        self.memory32_atomic_wait32_sig = Some(sig);
911        sig
912    }
913
914    /// Return the memory.atomic.wait32 function signature to call for the given index,
915    /// along with the translated index value to pass to it
916    /// and its index in `VMBuiltinFunctionsArray`.
917    fn get_memory_atomic_wait32_func(
918        &mut self,
919        func: &mut Function,
920        index: MemoryIndex,
921    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
922        if self.module.is_imported_memory(index) {
923            (
924                self.get_memory32_atomic_wait32_sig(func),
925                index.index(),
926                VMBuiltinFunctionIndex::get_imported_memory_atomic_wait32_index(),
927            )
928        } else {
929            (
930                self.get_memory32_atomic_wait32_sig(func),
931                self.module.local_memory_index(index).unwrap().index(),
932                VMBuiltinFunctionIndex::get_memory_atomic_wait32_index(),
933            )
934        }
935    }
936
937    fn get_memory32_atomic_wait64_sig(&mut self, func: &mut Function) -> ir::SigRef {
938        let sig = self.memory32_atomic_wait64_sig.unwrap_or_else(|| {
939            func.import_signature(Signature {
940                params: vec![
941                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
942                    // Memory Index
943                    AbiParam::new(I32),
944                    // Dst
945                    AbiParam::new(I32),
946                    // Val
947                    AbiParam::new(I64),
948                    // Timeout
949                    AbiParam::new(I64),
950                ],
951                returns: vec![AbiParam::new(I32)],
952                call_conv: self.target_config.default_call_conv,
953            })
954        });
955        self.memory32_atomic_wait64_sig = Some(sig);
956        sig
957    }
958
959    /// Return the memory.atomic.wait64 function signature to call for the given index,
960    /// along with the translated index value to pass to it
961    /// and its index in `VMBuiltinFunctionsArray`.
962    fn get_memory_atomic_wait64_func(
963        &mut self,
964        func: &mut Function,
965        index: MemoryIndex,
966    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
967        if self.module.is_imported_memory(index) {
968            (
969                self.get_memory32_atomic_wait64_sig(func),
970                index.index(),
971                VMBuiltinFunctionIndex::get_imported_memory_atomic_wait64_index(),
972            )
973        } else {
974            (
975                self.get_memory32_atomic_wait64_sig(func),
976                self.module.local_memory_index(index).unwrap().index(),
977                VMBuiltinFunctionIndex::get_memory_atomic_wait64_index(),
978            )
979        }
980    }
981
982    fn get_memory32_atomic_notify_sig(&mut self, func: &mut Function) -> ir::SigRef {
983        let sig = self.memory32_atomic_notify_sig.unwrap_or_else(|| {
984            func.import_signature(Signature {
985                params: vec![
986                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
987                    // Memory Index
988                    AbiParam::new(I32),
989                    // Dst
990                    AbiParam::new(I32),
991                    // Count
992                    AbiParam::new(I32),
993                ],
994                returns: vec![AbiParam::new(I32)],
995                call_conv: self.target_config.default_call_conv,
996            })
997        });
998        self.memory32_atomic_notify_sig = Some(sig);
999        sig
1000    }
1001
1002    /// Return the memory.atomic.notify function signature to call for the given index,
1003    /// along with the translated index value to pass to it
1004    /// and its index in `VMBuiltinFunctionsArray`.
1005    fn get_memory_atomic_notify_func(
1006        &mut self,
1007        func: &mut Function,
1008        index: MemoryIndex,
1009    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
1010        if self.module.is_imported_memory(index) {
1011            (
1012                self.get_memory32_atomic_notify_sig(func),
1013                index.index(),
1014                VMBuiltinFunctionIndex::get_imported_memory_atomic_notify_index(),
1015            )
1016        } else {
1017            (
1018                self.get_memory32_atomic_notify_sig(func),
1019                self.module.local_memory_index(index).unwrap().index(),
1020                VMBuiltinFunctionIndex::get_memory_atomic_notify_index(),
1021            )
1022        }
1023    }
1024
1025    fn get_personality2_func(
1026        &mut self,
1027        func: &mut Function,
1028    ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1029        let sig = self.personality2_sig.unwrap_or_else(|| {
1030            let mut signature = Signature::new(self.target_config.default_call_conv);
1031            signature.params.push(AbiParam::new(self.pointer_type()));
1032            signature.params.push(AbiParam::new(self.pointer_type()));
1033            signature.returns.push(AbiParam::new(TAG_TYPE));
1034            let sig = func.import_signature(signature);
1035            self.personality2_sig = Some(sig);
1036            sig
1037        });
1038        (
1039            sig,
1040            VMBuiltinFunctionIndex::get_imported_personality2_index(),
1041        )
1042    }
1043
1044    fn get_throw_func(&mut self, func: &mut Function) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1045        let sig = self.throw_sig.unwrap_or_else(|| {
1046            let mut signature = Signature::new(self.target_config.default_call_conv);
1047            signature.params.push(AbiParam::special(
1048                self.pointer_type(),
1049                ArgumentPurpose::VMContext,
1050            ));
1051            signature.params.push(AbiParam::new(EXN_REF_TYPE));
1052            let sig = func.import_signature(signature);
1053            self.throw_sig = Some(sig);
1054            sig
1055        });
1056        (sig, VMBuiltinFunctionIndex::get_imported_throw_index())
1057    }
1058
1059    fn get_raise_trap_func(&mut self, func: &mut Function) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1060        let sig = self.raise_trap_sig.unwrap_or_else(|| {
1061            let mut signature = Signature::new(self.target_config.default_call_conv);
1062            signature.params.push(AbiParam::new(I32));
1063            let sig = func.import_signature(signature);
1064            self.raise_trap_sig = Some(sig);
1065            sig
1066        });
1067        (sig, VMBuiltinFunctionIndex::get_raise_trap_index())
1068    }
1069
1070    fn get_alloc_exception_func(
1071        &mut self,
1072        func: &mut Function,
1073    ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1074        let sig = self.alloc_exception_sig.unwrap_or_else(|| {
1075            let mut signature = Signature::new(self.target_config.default_call_conv);
1076            signature.params.push(AbiParam::special(
1077                self.pointer_type(),
1078                ArgumentPurpose::VMContext,
1079            ));
1080            signature.params.push(AbiParam::new(TAG_TYPE));
1081            signature.returns.push(AbiParam::new(EXN_REF_TYPE));
1082            let sig = func.import_signature(signature);
1083            self.alloc_exception_sig = Some(sig);
1084            sig
1085        });
1086        (
1087            sig,
1088            VMBuiltinFunctionIndex::get_imported_alloc_exception_index(),
1089        )
1090    }
1091
1092    fn get_read_exnref_func(
1093        &mut self,
1094        func: &mut Function,
1095    ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1096        let sig = self.read_exnref_sig.unwrap_or_else(|| {
1097            let mut signature = Signature::new(self.target_config.default_call_conv);
1098            signature.params.push(AbiParam::special(
1099                self.pointer_type(),
1100                ArgumentPurpose::VMContext,
1101            ));
1102            signature.params.push(AbiParam::new(EXN_REF_TYPE));
1103            signature.returns.push(AbiParam::new(self.pointer_type()));
1104            let sig = func.import_signature(signature);
1105            self.read_exnref_sig = Some(sig);
1106            sig
1107        });
1108        (
1109            sig,
1110            VMBuiltinFunctionIndex::get_imported_read_exnref_index(),
1111        )
1112    }
1113
1114    fn get_read_exception_func(
1115        &mut self,
1116        func: &mut Function,
1117    ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1118        let sig = self.read_exception_sig.unwrap_or_else(|| {
1119            let mut signature = Signature::new(self.target_config.default_call_conv);
1120            signature.params.push(AbiParam::new(self.pointer_type()));
1121            signature.returns.push(AbiParam::new(EXN_REF_TYPE));
1122            let sig = func.import_signature(signature);
1123            self.read_exception_sig = Some(sig);
1124            sig
1125        });
1126        (
1127            sig,
1128            VMBuiltinFunctionIndex::get_imported_exception_into_exnref_index(),
1129        )
1130    }
1131
1132    fn exception_type_layout(&mut self, tag_index: TagIndex) -> WasmResult<&ExceptionTypeLayout> {
1133        let key = tag_index.as_u32();
1134        if !self.exception_type_layouts.contains_key(&key) {
1135            let layout = self.compute_exception_type_layout(tag_index)?;
1136            self.exception_type_layouts.insert(key, layout);
1137        }
1138        Ok(self.exception_type_layouts.get(&key).unwrap())
1139    }
1140
1141    fn compute_exception_type_layout(
1142        &self,
1143        tag_index: TagIndex,
1144    ) -> WasmResult<ExceptionTypeLayout> {
1145        let sig_index = self.module.tags[tag_index];
1146        let func_type = &self.module.signatures[sig_index];
1147        let mut offset = 0u32;
1148        let mut max_align = 1u32;
1149        let mut fields = SmallVec::<[ExceptionFieldLayout; 4]>::new();
1150
1151        for wasm_ty in func_type.params() {
1152            let ir_ty = self.map_wasmer_type_to_ir(*wasm_ty)?;
1153            let field_size = ir_ty.bytes();
1154            let align = field_size.max(1);
1155            max_align = max_align.max(align);
1156            offset = offset.next_multiple_of(align);
1157            fields.push(ExceptionFieldLayout { offset, ty: ir_ty });
1158            offset = offset
1159                .checked_add(field_size)
1160                .ok_or_else(|| WasmError::Unsupported("exception payload too large".to_string()))?;
1161        }
1162
1163        Ok(ExceptionTypeLayout { fields })
1164    }
1165
1166    fn map_wasmer_type_to_ir(&self, ty: WasmerType) -> WasmResult<ir::Type> {
1167        Ok(match ty {
1168            WasmerType::I32 => ir::types::I32,
1169            WasmerType::I64 => ir::types::I64,
1170            WasmerType::F32 => ir::types::F32,
1171            WasmerType::F64 => ir::types::F64,
1172            WasmerType::V128 => ir::types::I8X16,
1173            WasmerType::FuncRef | WasmerType::ExternRef => self.reference_type(),
1174            WasmerType::ExceptionRef => EXN_REF_TYPE,
1175        })
1176    }
1177
1178    fn call_with_handlers(
1179        &mut self,
1180        builder: &mut FunctionBuilder,
1181        callee: ir::FuncRef,
1182        args: &[ir::Value],
1183        context: Option<ir::Value>,
1184        landing_pad: Option<LandingPad>,
1185        unreachable_on_return: bool,
1186    ) -> SmallVec<[ir::Value; 4]> {
1187        let sig_ref = builder.func.dfg.ext_funcs[callee].signature;
1188        let return_types: SmallVec<[ir::Type; 4]> = builder.func.dfg.signatures[sig_ref]
1189            .returns
1190            .iter()
1191            .map(|ret| ret.value_type)
1192            .collect();
1193
1194        if landing_pad.is_none() {
1195            let inst = builder.ins().call(callee, args);
1196            let results: SmallVec<[ir::Value; 4]> =
1197                builder.inst_results(inst).iter().copied().collect();
1198            if unreachable_on_return {
1199                builder.ins().trap(crate::TRAP_UNREACHABLE);
1200            }
1201            return results;
1202        }
1203
1204        let continuation = builder.create_block();
1205        let mut normal_args = SmallVec::<[BlockArg; 4]>::with_capacity(return_types.len());
1206        let mut result_values = SmallVec::<[ir::Value; 4]>::with_capacity(return_types.len());
1207        for (i, ty) in return_types.iter().enumerate() {
1208            let val = builder.append_block_param(continuation, *ty);
1209            result_values.push(val);
1210            normal_args.push(BlockArg::TryCallRet(u32::try_from(i).unwrap()));
1211        }
1212        let continuation_call = builder
1213            .func
1214            .dfg
1215            .block_call(continuation, normal_args.iter());
1216
1217        let mut table_items = Vec::new();
1218        if let Some(ctx) = context {
1219            table_items.push(ExceptionTableItem::Context(ctx));
1220        }
1221        if let Some(landing_pad) = landing_pad {
1222            for tag in landing_pad.clauses {
1223                let block_call = builder.func.dfg.block_call(
1224                    landing_pad.block,
1225                    &[BlockArg::TryCallExn(0), BlockArg::TryCallExn(1)],
1226                );
1227                table_items.push(match tag.wasm_tag {
1228                    Some(tag) => ExceptionTableItem::Tag(ExceptionTag::from_u32(tag), block_call),
1229                    None => ExceptionTableItem::Default(block_call),
1230                });
1231            }
1232        }
1233        let etd = ExceptionTableData::new(sig_ref, continuation_call, table_items);
1234        let et = builder.func.dfg.exception_tables.push(etd);
1235        builder.ins().try_call(callee, args, et);
1236        builder.switch_to_block(continuation);
1237        builder.seal_block(continuation);
1238        if unreachable_on_return {
1239            builder.ins().trap(crate::TRAP_UNREACHABLE);
1240        }
1241        result_values
1242    }
1243
1244    #[allow(clippy::too_many_arguments)]
1245    fn call_indirect_with_handlers(
1246        &mut self,
1247        builder: &mut FunctionBuilder,
1248        sig: ir::SigRef,
1249        func_addr: ir::Value,
1250        args: &[ir::Value],
1251        context: Option<ir::Value>,
1252        landing_pad: Option<LandingPad>,
1253        unreachable_on_return: bool,
1254    ) -> SmallVec<[ir::Value; 4]> {
1255        let return_types: SmallVec<[ir::Type; 4]> = builder.func.dfg.signatures[sig]
1256            .returns
1257            .iter()
1258            .map(|ret| ret.value_type)
1259            .collect();
1260
1261        if landing_pad.is_none() {
1262            let inst = builder.ins().call_indirect(sig, func_addr, args);
1263            let results: SmallVec<[ir::Value; 4]> =
1264                builder.inst_results(inst).iter().copied().collect();
1265            if unreachable_on_return {
1266                builder.ins().trap(crate::TRAP_UNREACHABLE);
1267            }
1268            return results;
1269        }
1270
1271        let continuation = builder.create_block();
1272        let current_block = builder.current_block().expect("current block");
1273        builder.insert_block_after(continuation, current_block);
1274
1275        let mut normal_args = SmallVec::<[BlockArg; 4]>::with_capacity(return_types.len());
1276        let mut result_values = SmallVec::<[ir::Value; 4]>::with_capacity(return_types.len());
1277        for (i, ty) in return_types.iter().enumerate() {
1278            let val = builder.append_block_param(continuation, *ty);
1279            result_values.push(val);
1280            normal_args.push(BlockArg::TryCallRet(u32::try_from(i).unwrap()));
1281        }
1282        let continuation_call = builder
1283            .func
1284            .dfg
1285            .block_call(continuation, normal_args.iter());
1286
1287        let mut table_items = Vec::new();
1288        if let Some(ctx) = context {
1289            table_items.push(ExceptionTableItem::Context(ctx));
1290        }
1291        if let Some(landing_pad) = landing_pad {
1292            for tag in landing_pad.clauses {
1293                let block_call = builder.func.dfg.block_call(
1294                    landing_pad.block,
1295                    &[BlockArg::TryCallExn(0), BlockArg::TryCallExn(1)],
1296                );
1297                table_items.push(match tag.wasm_tag {
1298                    Some(tag) => ExceptionTableItem::Tag(ExceptionTag::from_u32(tag), block_call),
1299                    None => ExceptionTableItem::Default(block_call),
1300                });
1301            }
1302        }
1303
1304        let etd = ExceptionTableData::new(sig, continuation_call, table_items);
1305        let et = builder.func.dfg.exception_tables.push(etd);
1306        builder.ins().try_call_indirect(func_addr, args, et);
1307        builder.switch_to_block(continuation);
1308        builder.seal_block(continuation);
1309        if unreachable_on_return {
1310            builder.ins().trap(crate::TRAP_UNREACHABLE);
1311        }
1312
1313        result_values
1314    }
1315
1316    /// Translates load of builtin function and returns a pair of values `vmctx`
1317    /// and address of the loaded function.
1318    fn translate_load_builtin_function_address(
1319        &mut self,
1320        pos: &mut FuncCursor<'_>,
1321        callee_func_idx: VMBuiltinFunctionIndex,
1322    ) -> WasmResult<(ir::Value, ir::Value)> {
1323        // We use an indirect call so that we don't have to patch the code at runtime.
1324        let pointer_type = self.pointer_type();
1325        let vmctx = self.vmctx(pos.func);
1326        let base = materialize_global_value(pos, pointer_type, vmctx);
1327
1328        let mut mem_flags = ir::MemFlagsData::trusted();
1329        mem_flags.set_readonly();
1330
1331        // Load the callee address.
1332        let body_offset = vmctx_offset(self.offsets.vmctx_builtin_function(callee_func_idx))?;
1333        let func_addr = pos.ins().load(pointer_type, mem_flags, base, body_offset);
1334
1335        Ok((base, func_addr))
1336    }
1337
1338    fn get_or_init_funcref_table_elem(
1339        &mut self,
1340        builder: &mut FunctionBuilder,
1341        table_index: TableIndex,
1342        index: ir::Value,
1343    ) -> WasmResult<(ir::Value, bool)> {
1344        let pointer_type = self.pointer_type();
1345        self.ensure_table_exists(builder.func, table_index)?;
1346        let table_data = self.tables[table_index].as_ref().unwrap();
1347
1348        let (table_entry_addr, flags) =
1349            table_data.prepare_table_addr(builder, index, pointer_type, false);
1350        Ok(if table_data.inline_anyfunc {
1351            (table_entry_addr, true)
1352        } else {
1353            (
1354                builder.ins().load(pointer_type, flags, table_entry_addr, 0),
1355                false,
1356            )
1357        })
1358    }
1359}
1360
1361impl FuncEnvironment<'_> {
1362    pub(crate) fn is_wasm_parameter(&self, signature: &ir::Signature, index: usize) -> bool {
1363        signature.params[index].purpose == ArgumentPurpose::Normal
1364    }
1365
1366    pub(crate) fn translate_unreachable(
1367        &mut self,
1368        builder: &mut FunctionBuilder,
1369    ) -> WasmResult<()> {
1370        let (func_sig, func_idx) = self.get_raise_trap_func(builder.func);
1371        let mut pos = builder.cursor();
1372        let (_, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx)?;
1373        let trap_code = pos
1374            .ins()
1375            .iconst(I32, wasmer_types::TrapCode::UnreachableCodeReached as i64);
1376        builder
1377            .ins()
1378            .call_indirect(func_sig, func_addr, &[trap_code]);
1379        // Emit the terminator through `FunctionBuilder` so its block state is
1380        // updated before later control-flow translation switches blocks.
1381        builder.ins().trap(crate::TRAP_UNREACHABLE);
1382        Ok(())
1383    }
1384
1385    pub(crate) fn translate_table_grow(
1386        &mut self,
1387        mut pos: cranelift_codegen::cursor::FuncCursor<'_>,
1388        table_index: TableIndex,
1389        delta: ir::Value,
1390        init_value: ir::Value,
1391    ) -> WasmResult<ir::Value> {
1392        self.ensure_table_exists(pos.func, table_index)?;
1393        let (func_sig, index_arg, func_idx) = self.get_table_grow_func(pos.func, table_index);
1394        let table_index = pos.ins().iconst(I32, index_arg as i64);
1395        let (vmctx, func_addr) =
1396            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
1397        let call_inst = pos.ins().call_indirect(
1398            func_sig,
1399            func_addr,
1400            &[vmctx, init_value, delta, table_index],
1401        );
1402        Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
1403    }
1404
1405    pub(crate) fn translate_table_get(
1406        &mut self,
1407        builder: &mut FunctionBuilder,
1408        table_index: TableIndex,
1409        index: ir::Value,
1410    ) -> WasmResult<ir::Value> {
1411        self.ensure_table_exists(builder.func, table_index)?;
1412        let mut pos = builder.cursor();
1413
1414        let (func_sig, table_index_arg, func_idx) = self.get_table_get_func(pos.func, table_index);
1415        let table_index = pos.ins().iconst(I32, table_index_arg as i64);
1416        let (vmctx, func_addr) =
1417            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
1418        let call_inst = pos
1419            .ins()
1420            .call_indirect(func_sig, func_addr, &[vmctx, table_index, index]);
1421        Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
1422    }
1423
1424    pub(crate) fn translate_table_set(
1425        &mut self,
1426        builder: &mut FunctionBuilder,
1427        table_index: TableIndex,
1428        value: ir::Value,
1429        index: ir::Value,
1430    ) -> WasmResult<()> {
1431        self.ensure_table_exists(builder.func, table_index)?;
1432        let mut pos = builder.cursor();
1433
1434        let (func_sig, table_index_arg, func_idx) = self.get_table_set_func(pos.func, table_index);
1435        let n_table_index = pos.ins().iconst(I32, table_index_arg as i64);
1436        let (vmctx, func_addr) =
1437            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
1438        pos.ins()
1439            .call_indirect(func_sig, func_addr, &[vmctx, n_table_index, index, value]);
1440        Ok(())
1441    }
1442
1443    pub(crate) fn translate_table_fill(
1444        &mut self,
1445        mut pos: cranelift_codegen::cursor::FuncCursor<'_>,
1446        table_index: TableIndex,
1447        dst: ir::Value,
1448        val: ir::Value,
1449        len: ir::Value,
1450    ) -> WasmResult<()> {
1451        self.ensure_table_exists(pos.func, table_index)?;
1452        let (func_sig, table_index_arg, func_idx) = self.get_table_fill_func(pos.func, table_index);
1453        let (vmctx, func_addr) =
1454            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
1455
1456        let table_index_arg = pos.ins().iconst(I32, table_index_arg as i64);
1457        pos.ins().call_indirect(
1458            func_sig,
1459            func_addr,
1460            &[vmctx, table_index_arg, dst, val, len],
1461        );
1462
1463        Ok(())
1464    }
1465
1466    pub(crate) fn translate_ref_null(
1467        &mut self,
1468        mut pos: cranelift_codegen::cursor::FuncCursor,
1469        ty: HeapType,
1470    ) -> WasmResult<ir::Value> {
1471        Ok(match ty {
1472            HeapType::Abstract { ty, .. } => match ty {
1473                wasmer_compiler::wasmparser::AbstractHeapType::Func
1474                | wasmer_compiler::wasmparser::AbstractHeapType::Extern
1475                | wasmer_compiler::wasmparser::AbstractHeapType::Exn => pos.ins().iconst(
1476                    if matches!(ty, wasmer_compiler::wasmparser::AbstractHeapType::Exn) {
1477                        I32
1478                    } else {
1479                        self.reference_type()
1480                    },
1481                    0,
1482                ),
1483                _ => {
1484                    return Err(WasmError::Unsupported(format!(
1485                        "`ref.null T` that is not a `funcref`, an `externref` or an `exn`: {ty:?}"
1486                    )));
1487                }
1488            },
1489            HeapType::Concrete(_) => {
1490                return Err(WasmError::Unsupported(
1491                    "`ref.null T` that is not a `funcref` or an `externref`".into(),
1492                ));
1493            }
1494            HeapType::Exact(_) => {
1495                return Err(WasmError::Unsupported(
1496                    "custom-descriptors not supported yet".into(),
1497                ));
1498            }
1499        })
1500    }
1501
1502    pub(crate) fn translate_ref_is_null(
1503        &mut self,
1504        mut pos: cranelift_codegen::cursor::FuncCursor,
1505        value: ir::Value,
1506    ) -> WasmResult<ir::Value> {
1507        let bool_is_null =
1508            pos.ins()
1509                .icmp_imm_s(cranelift_codegen::ir::condcodes::IntCC::Equal, value, 0);
1510        Ok(pos.ins().uextend(ir::types::I32, bool_is_null))
1511    }
1512
1513    pub(crate) fn translate_ref_func(
1514        &mut self,
1515        mut pos: cranelift_codegen::cursor::FuncCursor<'_>,
1516        func_index: FunctionIndex,
1517    ) -> WasmResult<ir::Value> {
1518        let (func_sig, func_index_arg, func_idx) = self.get_func_ref_func(pos.func, func_index);
1519        let (vmctx, func_addr) =
1520            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
1521
1522        let func_index_arg = pos.ins().iconst(I32, func_index_arg as i64);
1523        let call_inst = pos
1524            .ins()
1525            .call_indirect(func_sig, func_addr, &[vmctx, func_index_arg]);
1526
1527        Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
1528    }
1529
1530    pub(crate) fn translate_custom_global_get(
1531        &mut self,
1532        mut _pos: cranelift_codegen::cursor::FuncCursor<'_>,
1533        _index: GlobalIndex,
1534    ) -> WasmResult<ir::Value> {
1535        unreachable!("we don't make any custom globals")
1536    }
1537
1538    pub(crate) fn translate_custom_global_set(
1539        &mut self,
1540        mut _pos: cranelift_codegen::cursor::FuncCursor<'_>,
1541        _index: GlobalIndex,
1542        _value: ir::Value,
1543    ) -> WasmResult<()> {
1544        unreachable!("we don't make any custom globals")
1545    }
1546
1547    pub(crate) fn make_heap(
1548        &mut self,
1549        func: &mut ir::Function,
1550        index: MemoryIndex,
1551    ) -> WasmResult<Heap> {
1552        let pointer_type = self.pointer_type();
1553
1554        let (ptr, base_offset, current_length_offset) = {
1555            let vmctx = self.vmctx(func);
1556            if let Some(def_index) = self.module.local_memory_index(index) {
1557                let base_offset =
1558                    vmctx_offset(self.offsets.vmctx_vmmemory_definition_base(def_index))?;
1559                let current_length_offset = vmctx_offset(
1560                    self.offsets
1561                        .vmctx_vmmemory_definition_current_length(def_index),
1562                )?;
1563                (vmctx, base_offset, current_length_offset)
1564            } else {
1565                let from_offset = self.offsets.vmctx_vmmemory_import_definition(index);
1566                let flags = insert_mem_flags(func, ir::MemFlagsData::trusted().with_readonly());
1567                let memory = func.create_global_value(ir::GlobalValueData::Load {
1568                    base: vmctx,
1569                    offset: Offset32::new(vmctx_offset(from_offset)?),
1570                    global_type: pointer_type,
1571                    flags,
1572                });
1573                let base_offset = i32::from(self.offsets.vmmemory_definition_base());
1574                let current_length_offset =
1575                    i32::from(self.offsets.vmmemory_definition_current_length());
1576                (memory, base_offset, current_length_offset)
1577            }
1578        };
1579
1580        // If we have a declared maximum, we can make this a "static" heap, which is
1581        // allocated up front and never moved.
1582        let (offset_guard_size, heap_style, readonly_base) = match self.memory_styles[index] {
1583            MemoryStyle::Dynamic { offset_guard_size } => {
1584                let flags = insert_mem_flags(func, ir::MemFlagsData::trusted());
1585                let heap_bound = func.create_global_value(ir::GlobalValueData::Load {
1586                    base: ptr,
1587                    offset: Offset32::new(current_length_offset),
1588                    global_type: pointer_type,
1589                    flags,
1590                });
1591                (
1592                    Uimm64::new(offset_guard_size),
1593                    HeapStyle::Dynamic {
1594                        bound_gv: heap_bound,
1595                    },
1596                    false,
1597                )
1598            }
1599            MemoryStyle::Static => (
1600                Uimm64::new(MemoryStyle::static_offset_guard_size()),
1601                HeapStyle::Static,
1602                true,
1603            ),
1604        };
1605
1606        let flags = if readonly_base {
1607            insert_mem_flags(func, ir::MemFlagsData::trusted().with_readonly())
1608        } else {
1609            insert_mem_flags(func, ir::MemFlagsData::trusted())
1610        };
1611        let heap_base = func.create_global_value(ir::GlobalValueData::Load {
1612            base: ptr,
1613            offset: Offset32::new(base_offset),
1614            global_type: pointer_type,
1615            flags,
1616        });
1617        Ok(self.heaps.push(HeapData {
1618            base: heap_base,
1619            min_size: 0,
1620            max_size: None,
1621            offset_guard_size: offset_guard_size.into(),
1622            style: heap_style,
1623            index_type: I32,
1624            page_size_log2: self.target_config.page_size_align_log2,
1625        }))
1626    }
1627
1628    pub(crate) fn make_global(
1629        &mut self,
1630        func: &mut ir::Function,
1631        index: GlobalIndex,
1632    ) -> WasmResult<GlobalVariable> {
1633        let pointer_type = self.pointer_type();
1634
1635        let (ptr, offset) = {
1636            let vmctx = self.vmctx(func);
1637
1638            if let Some(def_index) = self.module.local_global_index(index) {
1639                let from_offset = self.offsets.vmctx_vmglobal_definition(def_index);
1640                let global = func.create_global_value(ir::GlobalValueData::VMContext);
1641                (global, vmctx_offset(from_offset)?)
1642            } else {
1643                let from_offset = self.offsets.vmctx_vmglobal_import_definition(index);
1644                let flags = insert_mem_flags(func, MemFlagsData::trusted());
1645                let global = func.create_global_value(ir::GlobalValueData::Load {
1646                    base: vmctx,
1647                    offset: Offset32::new(vmctx_offset(from_offset)?),
1648                    global_type: pointer_type,
1649                    flags,
1650                });
1651                (global, 0)
1652            }
1653        };
1654
1655        Ok(GlobalVariable::Memory {
1656            gv: ptr,
1657            offset: offset.into(),
1658            ty: match self.module.globals[index].ty {
1659                WasmerType::I32 => ir::types::I32,
1660                WasmerType::I64 => ir::types::I64,
1661                WasmerType::F32 => ir::types::F32,
1662                WasmerType::F64 => ir::types::F64,
1663                WasmerType::V128 => ir::types::I8X16,
1664                WasmerType::FuncRef | WasmerType::ExternRef => self.reference_type(),
1665                WasmerType::ExceptionRef => EXN_REF_TYPE,
1666            },
1667        })
1668    }
1669
1670    pub(crate) fn make_indirect_sig(
1671        &mut self,
1672        func: &mut ir::Function,
1673        index: SignatureIndex,
1674    ) -> WasmResult<ir::SigRef> {
1675        Ok(func.import_signature(self.signatures[index].clone()))
1676    }
1677
1678    pub(crate) fn make_direct_func(
1679        &mut self,
1680        func: &mut ir::Function,
1681        index: FunctionIndex,
1682    ) -> WasmResult<ir::FuncRef> {
1683        let sigidx = self.module.functions[index];
1684        let signature = func.import_signature(self.signatures[sigidx].clone());
1685        let name = get_function_name(func, index);
1686
1687        Ok(func.import_function(ir::ExtFuncData {
1688            name,
1689            signature,
1690            colocated: true,
1691            patchable: false,
1692        }))
1693    }
1694
1695    fn prepare_wasm_call(
1696        &self,
1697        builder: &mut FunctionBuilder,
1698        result_types: &[WasmerType],
1699    ) -> (ReturnAbi, Option<(ir::Value, abi::ReturnAreaLayout)>) {
1700        let return_abi = abi::classify_returns(self.architecture, result_types);
1701        let sret = match &return_abi {
1702            ReturnAbi::Sret(types) => Some(abi::allocate_return_area(
1703                builder,
1704                types,
1705                self.target_config,
1706            )),
1707            _ => None,
1708        };
1709        (return_abi, sret)
1710    }
1711
1712    fn finish_wasm_call(
1713        &self,
1714        builder: &mut FunctionBuilder,
1715        return_abi: &ReturnAbi,
1716        carriers: &[ir::Value],
1717        sret: Option<(ir::Value, abi::ReturnAreaLayout)>,
1718    ) -> SmallVec<[ir::Value; 4]> {
1719        match return_abi {
1720            ReturnAbi::Sret(types) => {
1721                let (ptr, layout) = sret.expect("sret call has a return area");
1722                abi::load_sret(builder, ptr, &layout, types, self.target_config)
1723            }
1724            _ => abi::unpack_register_returns(builder, return_abi, carriers, self.target_config),
1725        }
1726    }
1727
1728    #[allow(clippy::too_many_arguments)]
1729    pub(crate) fn translate_call_indirect(
1730        &mut self,
1731        builder: &mut FunctionBuilder,
1732        table_index: TableIndex,
1733        sig_index: SignatureIndex,
1734        sig_ref: ir::SigRef,
1735        callee: ir::Value,
1736        call_args: &[ir::Value],
1737        landing_pad: Option<LandingPad>,
1738    ) -> WasmResult<SmallVec<[ir::Value; 4]>> {
1739        let pointer_type = self.pointer_type();
1740
1741        // Get the anyfunc pointer (the funcref) from the table.
1742        let (anyfunc_ptr, inline_anyfunc) =
1743            self.get_or_init_funcref_table_elem(builder, table_index, callee)?;
1744
1745        // Dereference table_entry_addr to get the function address.
1746        let mem_flags = ir::MemFlagsData::trusted();
1747
1748        // check if the funcref is null
1749        if !inline_anyfunc {
1750            builder
1751                .ins()
1752                .trapz(anyfunc_ptr, crate::TRAP_INDIRECT_CALL_TO_NULL);
1753        }
1754
1755        let func_addr = builder.ins().load(
1756            pointer_type,
1757            mem_flags,
1758            anyfunc_ptr,
1759            i32::from(self.offsets.vmcaller_checked_anyfunc_func_ptr()),
1760        );
1761
1762        if inline_anyfunc {
1763            builder
1764                .ins()
1765                .trapz(func_addr, crate::TRAP_INDIRECT_CALL_TO_NULL);
1766        }
1767
1768        // If necessary, check the signature.
1769        match self.table_styles[table_index] {
1770            TableStyle::CallerChecksSignature => {
1771                let sig_hash_type = ir::types::I32;
1772                let expected_sig_hash = builder.ins().iconst(
1773                    sig_hash_type,
1774                    i64::from(self.signature_hashes[sig_index].as_u32()),
1775                );
1776
1777                // Load the callee ID.
1778                let mem_flags = ir::MemFlagsData::trusted();
1779                let callee_sig_hash = builder.ins().load(
1780                    sig_hash_type,
1781                    mem_flags,
1782                    anyfunc_ptr,
1783                    i32::from(self.offsets.vmcaller_checked_anyfunc_signature_hash()),
1784                );
1785
1786                // Check that they match.
1787                let cmp = builder
1788                    .ins()
1789                    .icmp(IntCC::Equal, callee_sig_hash, expected_sig_hash);
1790                builder.ins().trapz(cmp, crate::TRAP_BAD_SIGNATURE);
1791            }
1792        }
1793
1794        let (return_abi, sret) =
1795            self.prepare_wasm_call(builder, self.module.signatures[sig_index].results());
1796        let mut real_call_args = Vec::with_capacity(call_args.len() + 2);
1797        if let Some((ptr, _)) = &sret {
1798            real_call_args.push(*ptr);
1799        }
1800
1801        // First append the callee vmctx address.
1802        let vmctx = builder.ins().load(
1803            pointer_type,
1804            mem_flags,
1805            anyfunc_ptr,
1806            i32::from(self.offsets.vmcaller_checked_anyfunc_vmctx()),
1807        );
1808        real_call_args.push(vmctx);
1809
1810        // Then append the regular call arguments.
1811        real_call_args.extend_from_slice(call_args);
1812
1813        let results = self.call_indirect_with_handlers(
1814            builder,
1815            sig_ref,
1816            func_addr,
1817            &real_call_args,
1818            Some(vmctx),
1819            landing_pad,
1820            false,
1821        );
1822        Ok(self.finish_wasm_call(builder, &return_abi, &results, sret))
1823    }
1824
1825    pub(crate) fn translate_call(
1826        &mut self,
1827        builder: &mut FunctionBuilder,
1828        callee_index: FunctionIndex,
1829        callee: ir::FuncRef,
1830        call_args: &[ir::Value],
1831        landing_pad: Option<LandingPad>,
1832    ) -> WasmResult<SmallVec<[ir::Value; 4]>> {
1833        let sig_index = self.module.functions[callee_index];
1834        let (return_abi, sret) =
1835            self.prepare_wasm_call(builder, self.module.signatures[sig_index].results());
1836        let mut real_call_args = Vec::with_capacity(call_args.len() + 2);
1837        if let Some((ptr, _)) = &sret {
1838            real_call_args.push(*ptr);
1839        }
1840
1841        // Handle direct calls to locally-defined functions.
1842        if !self.module.is_imported_function(callee_index) {
1843            // Let's get the caller vmctx
1844            let caller_vmctx = builder
1845                .func
1846                .special_param(ArgumentPurpose::VMContext)
1847                .unwrap();
1848            // First append the callee vmctx address, which is the same as the caller vmctx in
1849            // this case.
1850            real_call_args.push(caller_vmctx);
1851
1852            // Then append the regular call arguments.
1853            real_call_args.extend_from_slice(call_args);
1854
1855            let results = self.call_with_handlers(
1856                builder,
1857                callee,
1858                &real_call_args,
1859                Some(caller_vmctx),
1860                landing_pad,
1861                false,
1862            );
1863            return Ok(self.finish_wasm_call(builder, &return_abi, &results, sret));
1864        }
1865
1866        // Handle direct calls to imported functions. We use an indirect call
1867        // so that we don't have to patch the code at runtime.
1868        let pointer_type = self.pointer_type();
1869        let sig_ref = builder.func.dfg.ext_funcs[callee].signature;
1870        let vmctx = self.vmctx(builder.func);
1871        let base = materialize_global_value(&mut builder.cursor(), pointer_type, vmctx);
1872
1873        let mem_flags = ir::MemFlagsData::trusted();
1874
1875        // Load the callee address.
1876        let body_offset = vmctx_offset(self.offsets.vmctx_vmfunction_import_body(callee_index))?;
1877        let func_addr = builder
1878            .ins()
1879            .load(pointer_type, mem_flags, base, body_offset);
1880
1881        // First append the callee vmctx address.
1882        let vmctx_arg_offset =
1883            vmctx_offset(self.offsets.vmctx_vmfunction_import_vmctx(callee_index))?;
1884        let vmctx = builder
1885            .ins()
1886            .load(pointer_type, mem_flags, base, vmctx_arg_offset);
1887        real_call_args.push(vmctx);
1888
1889        // Then append the regular call arguments.
1890        real_call_args.extend_from_slice(call_args);
1891
1892        let results = self.call_indirect_with_handlers(
1893            builder,
1894            sig_ref,
1895            func_addr,
1896            &real_call_args,
1897            Some(vmctx),
1898            landing_pad,
1899            false,
1900        );
1901        Ok(self.finish_wasm_call(builder, &return_abi, &results, sret))
1902    }
1903
1904    pub(crate) fn tag_param_arity(&self, tag_index: TagIndex) -> usize {
1905        let sig_index = self.module.tags[tag_index];
1906        let signature = &self.module.signatures[sig_index];
1907        signature.params().len()
1908    }
1909
1910    pub(crate) fn translate_exn_pointer_to_ref(
1911        &mut self,
1912        builder: &mut FunctionBuilder,
1913        exn_ptr: ir::Value,
1914    ) -> WasmResult<ir::Value> {
1915        let (read_sig, read_idx) = self.get_read_exception_func(builder.func);
1916        let mut pos = builder.cursor();
1917        let (_, read_addr) = self.translate_load_builtin_function_address(&mut pos, read_idx)?;
1918        let read_call = builder.ins().call_indirect(read_sig, read_addr, &[exn_ptr]);
1919        Ok(builder.inst_results(read_call)[0])
1920    }
1921
1922    pub(crate) fn translate_exn_unbox(
1923        &mut self,
1924        builder: &mut FunctionBuilder,
1925        tag_index: TagIndex,
1926        exnref: ir::Value,
1927    ) -> WasmResult<SmallVec<[ir::Value; 4]>> {
1928        let layout = self.exception_type_layout(tag_index)?.clone();
1929
1930        let (read_exnref_sig, read_exnref_idx) = self.get_read_exnref_func(builder.func);
1931        let mut pos = builder.cursor();
1932        let (vmctx, read_exnref_addr) =
1933            self.translate_load_builtin_function_address(&mut pos, read_exnref_idx)?;
1934        let read_exnref_call =
1935            builder
1936                .ins()
1937                .call_indirect(read_exnref_sig, read_exnref_addr, &[vmctx, exnref]);
1938        let payload_ptr = builder.inst_results(read_exnref_call)[0];
1939
1940        let mut values = SmallVec::<[ir::Value; 4]>::with_capacity(layout.fields.len());
1941        let data_flags = ir::MemFlagsData::trusted();
1942        for field in &layout.fields {
1943            let value = builder.ins().load(
1944                field.ty,
1945                data_flags,
1946                payload_ptr,
1947                Offset32::new(field.offset as i32),
1948            );
1949            values.push(value);
1950        }
1951
1952        Ok(values)
1953    }
1954
1955    pub(crate) fn translate_exn_throw(
1956        &mut self,
1957        builder: &mut FunctionBuilder,
1958        tag_index: TagIndex,
1959        args: &[ir::Value],
1960        landing_pad: Option<LandingPad>,
1961    ) -> WasmResult<()> {
1962        let layout = self.exception_type_layout(tag_index)?.clone();
1963        if layout.fields.len() != args.len() {
1964            return Err(WasmError::Generic(format!(
1965                "exception payload arity mismatch: expected {}, got {}",
1966                layout.fields.len(),
1967                args.len()
1968            )));
1969        }
1970
1971        let (alloc_sig, alloc_idx) = self.get_alloc_exception_func(builder.func);
1972        let mut pos = builder.cursor();
1973        let (vmctx, alloc_addr) =
1974            self.translate_load_builtin_function_address(&mut pos, alloc_idx)?;
1975        let tag_value = builder
1976            .ins()
1977            .iconst(TAG_TYPE, i64::from(tag_index.as_u32()));
1978        let alloc_call = builder
1979            .ins()
1980            .call_indirect(alloc_sig, alloc_addr, &[vmctx, tag_value]);
1981        let exnref = builder.inst_results(alloc_call)[0];
1982
1983        let (read_exnref_sig, read_exnref_idx) = self.get_read_exnref_func(builder.func);
1984        let mut pos = builder.cursor();
1985        let (vmctx, read_exnref_addr) =
1986            self.translate_load_builtin_function_address(&mut pos, read_exnref_idx)?;
1987        let read_exnref_call =
1988            builder
1989                .ins()
1990                .call_indirect(read_exnref_sig, read_exnref_addr, &[vmctx, exnref]);
1991        let payload_ptr = builder.inst_results(read_exnref_call)[0];
1992
1993        let store_flags = ir::MemFlagsData::trusted();
1994        for (field, value) in layout.fields.iter().zip(args.iter()) {
1995            debug_assert_eq!(
1996                builder.func.dfg.value_type(*value),
1997                field.ty,
1998                "exception payload type mismatch"
1999            );
2000            builder.ins().store(
2001                store_flags,
2002                *value,
2003                payload_ptr,
2004                Offset32::new(field.offset as i32),
2005            );
2006        }
2007
2008        let (throw_sig, throw_idx) = self.get_throw_func(builder.func);
2009        let mut pos = builder.cursor();
2010        let (vmctx_value, throw_addr) =
2011            self.translate_load_builtin_function_address(&mut pos, throw_idx)?;
2012        let call_args = [vmctx_value, exnref];
2013
2014        let _ = self.call_indirect_with_handlers(
2015            builder,
2016            throw_sig,
2017            throw_addr,
2018            &call_args,
2019            Some(vmctx_value),
2020            landing_pad,
2021            true,
2022        );
2023
2024        Ok(())
2025    }
2026
2027    pub(crate) fn translate_exn_throw_ref(
2028        &mut self,
2029        builder: &mut FunctionBuilder,
2030        exnref: ir::Value,
2031        landing_pad: Option<LandingPad>,
2032    ) -> WasmResult<()> {
2033        let (throw_sig, throw_idx) = self.get_throw_func(builder.func);
2034        let mut pos = builder.cursor();
2035        let (vmctx_value, throw_addr) =
2036            self.translate_load_builtin_function_address(&mut pos, throw_idx)?;
2037        let call_args = [vmctx_value, exnref];
2038
2039        let _ = self.call_indirect_with_handlers(
2040            builder,
2041            throw_sig,
2042            throw_addr,
2043            &call_args,
2044            Some(vmctx_value),
2045            landing_pad,
2046            true,
2047        );
2048
2049        Ok(())
2050    }
2051
2052    pub(crate) fn translate_exn_personality_selector(
2053        &mut self,
2054        builder: &mut FunctionBuilder,
2055        exn_ptr: ir::Value,
2056    ) -> WasmResult<ir::Value> {
2057        let (sig, idx) = self.get_personality2_func(builder.func);
2058        let pointer_type = self.pointer_type();
2059        let exn_ty = builder.func.dfg.value_type(exn_ptr);
2060        let exn_arg = if exn_ty == pointer_type {
2061            exn_ptr
2062        } else {
2063            let mut flags = MemFlagsData::new();
2064            flags.set_endianness(Endianness::Little);
2065            builder.ins().bitcast(pointer_type, flags, exn_ptr)
2066        };
2067
2068        let mut pos = builder.cursor();
2069        let (vmctx_value, func_addr) =
2070            self.translate_load_builtin_function_address(&mut pos, idx)?;
2071        let call = builder
2072            .ins()
2073            .call_indirect(sig, func_addr, &[vmctx_value, exn_arg]);
2074        Ok(builder.inst_results(call)[0])
2075    }
2076
2077    pub(crate) fn translate_exn_reraise_unmatched(
2078        &mut self,
2079        builder: &mut FunctionBuilder,
2080        exnref: ir::Value,
2081    ) -> WasmResult<()> {
2082        let (throw_sig, throw_idx) = self.get_throw_func(builder.func);
2083        let mut pos = builder.cursor();
2084        let (vmctx_value, throw_addr) =
2085            self.translate_load_builtin_function_address(&mut pos, throw_idx)?;
2086        builder
2087            .ins()
2088            .call_indirect(throw_sig, throw_addr, &[vmctx_value, exnref]);
2089        builder.ins().trap(crate::TRAP_UNREACHABLE);
2090        Ok(())
2091    }
2092
2093    pub(crate) fn translate_memory_grow(
2094        &mut self,
2095        mut pos: FuncCursor<'_>,
2096        index: MemoryIndex,
2097        _heap: Heap,
2098        val: ir::Value,
2099    ) -> WasmResult<ir::Value> {
2100        let (func_sig, index_arg, func_idx) = self.get_memory_grow_func(pos.func, index);
2101        let memory_index = pos.ins().iconst(I32, index_arg as i64);
2102        let (vmctx, func_addr) =
2103            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2104        let call_inst = pos
2105            .ins()
2106            .call_indirect(func_sig, func_addr, &[vmctx, val, memory_index]);
2107        Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
2108    }
2109
2110    pub(crate) fn translate_memory_size(
2111        &mut self,
2112        mut pos: FuncCursor<'_>,
2113        index: MemoryIndex,
2114        _heap: Heap,
2115    ) -> WasmResult<ir::Value> {
2116        let (func_sig, index_arg, func_idx) = self.get_memory_size_func(pos.func, index);
2117        let memory_index = pos.ins().iconst(I32, index_arg as i64);
2118        let (vmctx, func_addr) =
2119            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2120        let call_inst = pos
2121            .ins()
2122            .call_indirect(func_sig, func_addr, &[vmctx, memory_index]);
2123        Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
2124    }
2125
2126    #[allow(clippy::too_many_arguments)]
2127    pub(crate) fn translate_memory_copy(
2128        &mut self,
2129        mut pos: FuncCursor,
2130        src_index: MemoryIndex,
2131        _src_heap: Heap,
2132        dst_index: MemoryIndex,
2133        _dst_heap: Heap,
2134        dst: ir::Value,
2135        src: ir::Value,
2136        len: ir::Value,
2137    ) -> WasmResult<()> {
2138        let (func_sig, func_idx) = self.get_memory_copy_func(pos.func);
2139
2140        let dst_index_arg = pos.ins().iconst(I32, dst_index.index() as i64);
2141        let src_index_arg = pos.ins().iconst(I32, src_index.index() as i64);
2142
2143        let (vmctx, func_addr) =
2144            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2145
2146        pos.ins().call_indirect(
2147            func_sig,
2148            func_addr,
2149            &[vmctx, dst_index_arg, src_index_arg, dst, src, len],
2150        );
2151
2152        Ok(())
2153    }
2154
2155    pub(crate) fn translate_memory_fill(
2156        &mut self,
2157        mut pos: FuncCursor,
2158        memory_index: MemoryIndex,
2159        _heap: Heap,
2160        dst: ir::Value,
2161        val: ir::Value,
2162        len: ir::Value,
2163    ) -> WasmResult<()> {
2164        let (func_sig, memory_index, func_idx) = self.get_memory_fill_func(pos.func, memory_index);
2165
2166        let memory_index_arg = pos.ins().iconst(I32, memory_index as i64);
2167
2168        let (vmctx, func_addr) =
2169            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2170
2171        pos.ins().call_indirect(
2172            func_sig,
2173            func_addr,
2174            &[vmctx, memory_index_arg, dst, val, len],
2175        );
2176
2177        Ok(())
2178    }
2179
2180    #[allow(clippy::too_many_arguments)]
2181    pub(crate) fn translate_memory_init(
2182        &mut self,
2183        mut pos: FuncCursor,
2184        memory_index: MemoryIndex,
2185        _heap: Heap,
2186        seg_index: u32,
2187        dst: ir::Value,
2188        src: ir::Value,
2189        len: ir::Value,
2190    ) -> WasmResult<()> {
2191        let (func_sig, func_idx) = self.get_memory_init_func(pos.func);
2192
2193        let memory_index_arg = pos.ins().iconst(I32, memory_index.index() as i64);
2194        let seg_index_arg = pos.ins().iconst(I32, seg_index as i64);
2195
2196        let (vmctx, func_addr) =
2197            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2198
2199        pos.ins().call_indirect(
2200            func_sig,
2201            func_addr,
2202            &[vmctx, memory_index_arg, seg_index_arg, dst, src, len],
2203        );
2204
2205        Ok(())
2206    }
2207
2208    pub(crate) fn translate_data_drop(
2209        &mut self,
2210        mut pos: FuncCursor,
2211        seg_index: u32,
2212    ) -> WasmResult<()> {
2213        let (func_sig, func_idx) = self.get_data_drop_func(pos.func);
2214        let seg_index_arg = pos.ins().iconst(I32, seg_index as i64);
2215        let (vmctx, func_addr) =
2216            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2217        pos.ins()
2218            .call_indirect(func_sig, func_addr, &[vmctx, seg_index_arg]);
2219        Ok(())
2220    }
2221
2222    pub(crate) fn translate_table_size(
2223        &mut self,
2224        mut pos: FuncCursor,
2225        table_index: TableIndex,
2226    ) -> WasmResult<ir::Value> {
2227        self.ensure_table_exists(pos.func, table_index)?;
2228        let (func_sig, index_arg, func_idx) = self.get_table_size_func(pos.func, table_index);
2229        let table_index = pos.ins().iconst(I32, index_arg as i64);
2230        let (vmctx, func_addr) =
2231            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2232        let call_inst = pos
2233            .ins()
2234            .call_indirect(func_sig, func_addr, &[vmctx, table_index]);
2235        Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
2236    }
2237
2238    pub(crate) fn translate_table_copy(
2239        &mut self,
2240        mut pos: FuncCursor,
2241        dst_table_index: TableIndex,
2242        src_table_index: TableIndex,
2243        dst: ir::Value,
2244        src: ir::Value,
2245        len: ir::Value,
2246    ) -> WasmResult<()> {
2247        self.ensure_table_exists(pos.func, src_table_index)?;
2248        self.ensure_table_exists(pos.func, dst_table_index)?;
2249        let (func_sig, dst_table_index_arg, src_table_index_arg, func_idx) =
2250            self.get_table_copy_func(pos.func, dst_table_index, src_table_index);
2251
2252        let dst_table_index_arg = pos.ins().iconst(I32, dst_table_index_arg as i64);
2253        let src_table_index_arg = pos.ins().iconst(I32, src_table_index_arg as i64);
2254
2255        let (vmctx, func_addr) =
2256            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2257
2258        pos.ins().call_indirect(
2259            func_sig,
2260            func_addr,
2261            &[
2262                vmctx,
2263                dst_table_index_arg,
2264                src_table_index_arg,
2265                dst,
2266                src,
2267                len,
2268            ],
2269        );
2270
2271        Ok(())
2272    }
2273
2274    pub(crate) fn translate_table_init(
2275        &mut self,
2276        mut pos: FuncCursor,
2277        seg_index: u32,
2278        table_index: TableIndex,
2279        dst: ir::Value,
2280        src: ir::Value,
2281        len: ir::Value,
2282    ) -> WasmResult<()> {
2283        self.ensure_table_exists(pos.func, table_index)?;
2284        let (func_sig, table_index_arg, func_idx) = self.get_table_init_func(pos.func, table_index);
2285
2286        let table_index_arg = pos.ins().iconst(I32, table_index_arg as i64);
2287        let seg_index_arg = pos.ins().iconst(I32, seg_index as i64);
2288
2289        let (vmctx, func_addr) =
2290            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2291
2292        pos.ins().call_indirect(
2293            func_sig,
2294            func_addr,
2295            &[vmctx, table_index_arg, seg_index_arg, dst, src, len],
2296        );
2297
2298        Ok(())
2299    }
2300
2301    pub(crate) fn translate_elem_drop(
2302        &mut self,
2303        mut pos: FuncCursor,
2304        elem_index: u32,
2305    ) -> WasmResult<()> {
2306        let (func_sig, func_idx) = self.get_elem_drop_func(pos.func);
2307
2308        let elem_index_arg = pos.ins().iconst(I32, elem_index as i64);
2309
2310        let (vmctx, func_addr) =
2311            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2312
2313        pos.ins()
2314            .call_indirect(func_sig, func_addr, &[vmctx, elem_index_arg]);
2315
2316        Ok(())
2317    }
2318
2319    pub(crate) fn translate_atomic_wait(
2320        &mut self,
2321        mut pos: FuncCursor,
2322        index: MemoryIndex,
2323        _heap: Heap,
2324        addr: ir::Value,
2325        expected: ir::Value,
2326        timeout: ir::Value,
2327    ) -> WasmResult<ir::Value> {
2328        let (func_sig, index_arg, func_idx) = if pos.func.dfg.value_type(expected) == I64 {
2329            self.get_memory_atomic_wait64_func(pos.func, index)
2330        } else {
2331            self.get_memory_atomic_wait32_func(pos.func, index)
2332        };
2333        let memory_index = pos.ins().iconst(I32, index_arg as i64);
2334        let (vmctx, func_addr) =
2335            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2336        let call_inst = pos.ins().call_indirect(
2337            func_sig,
2338            func_addr,
2339            &[vmctx, memory_index, addr, expected, timeout],
2340        );
2341        Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
2342    }
2343
2344    pub(crate) fn translate_atomic_notify(
2345        &mut self,
2346        mut pos: FuncCursor,
2347        index: MemoryIndex,
2348        _heap: Heap,
2349        addr: ir::Value,
2350        count: ir::Value,
2351    ) -> WasmResult<ir::Value> {
2352        let (func_sig, index_arg, func_idx) = self.get_memory_atomic_notify_func(pos.func, index);
2353        let memory_index = pos.ins().iconst(I32, index_arg as i64);
2354        let (vmctx, func_addr) =
2355            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2356        let call_inst =
2357            pos.ins()
2358                .call_indirect(func_sig, func_addr, &[vmctx, memory_index, addr, count]);
2359        Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
2360    }
2361
2362    pub(crate) fn push_local_decl_on_stack(&mut self, ty: WasmerType) {
2363        self.type_stack.push(ty);
2364    }
2365
2366    pub(crate) fn push_params_on_stack(&mut self, function_index: LocalFunctionIndex) {
2367        let func_index = self.module.func_index(function_index);
2368        let sig_idx = self.module.functions[func_index];
2369        let signature = &self.module.signatures[sig_idx];
2370        self.return_types = signature.results().to_vec();
2371        for param in signature.params() {
2372            self.type_stack.push(*param);
2373        }
2374    }
2375
2376    pub(crate) fn return_types(&self) -> &[WasmerType] {
2377        &self.return_types
2378    }
2379
2380    pub(crate) fn emit_wasm_return(&mut self, builder: &mut FunctionBuilder, values: &[ir::Value]) {
2381        let return_abi = abi::classify_returns(self.architecture, &self.return_types);
2382        match &return_abi {
2383            ReturnAbi::Sret(types) => {
2384                let ptr = builder
2385                    .func
2386                    .special_param(ArgumentPurpose::StructReturn)
2387                    .expect("sret function has a StructReturn parameter");
2388                let layout = abi::return_area_layout(types);
2389                abi::store_sret(builder, ptr, &layout, values);
2390                builder.ins().return_(&[]);
2391            }
2392            _ => {
2393                let packed = abi::pack_register_returns(builder, &return_abi, values);
2394                builder.ins().return_(&packed);
2395            }
2396        }
2397    }
2398
2399    pub(crate) fn heap_access_spectre_mitigation(&self) -> bool {
2400        false
2401    }
2402
2403    pub(crate) fn heaps(&self) -> &PrimaryMap<Heap, HeapData> {
2404        &self.heaps
2405    }
2406}