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    FunctionIndex, GlobalIndex, LocalFunctionIndex, MemoryIndex, MemoryStyle, ModuleInfo,
31    SignatureHash, SignatureIndex, TableIndex, TableStyle, TagIndex, Type as WasmerType,
32    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    ) -> Self {
211        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::new(target_config.pointer_bytes(), module),
247            memory_styles,
248            tables: Default::default(),
249            table_styles,
250        }
251    }
252
253    pub(crate) fn target_config(&self) -> TargetFrontendConfig {
254        self.target_config
255    }
256
257    pub(crate) fn pointer_type(&self) -> ir::Type {
258        self.target_config.pointer_type()
259    }
260
261    pub(crate) fn reference_type(&self) -> ir::Type {
262        self.target_config.pointer_type()
263    }
264
265    fn ensure_table_exists(
266        &mut self,
267        func: &mut ir::Function,
268        index: TableIndex,
269    ) -> WasmResult<()> {
270        if self.tables[index].is_some() {
271            return Ok(());
272        }
273
274        let pointer_type = self.pointer_type();
275        let table = &self.module.tables[index];
276
277        let (base_gv, table_base_offset, bound, element_size, inline_anyfunc) =
278            if let Some(def_index) = self.module.local_table_index(index)
279                && table.is_fixed_funcref_table()
280            {
281                (
282                    self.vmctx(func),
283                    vmctx_offset(
284                        self.offsets
285                            .vmctx_fixed_funcref_table_anyfuncs(def_index)
286                            .expect("fixed funcref table must have inline VMContext storage"),
287                    )?,
288                    TableSize::Static {
289                        bound: table.minimum,
290                    },
291                    u32::from(self.offsets.size_of_vmcaller_checked_anyfunc()),
292                    true,
293                )
294            } else {
295                let (ptr, base_offset, current_elements_offset) = {
296                    let vmctx = self.vmctx(func);
297                    if let Some(def_index) = self.module.local_table_index(index) {
298                        let base_offset =
299                            vmctx_offset(self.offsets.vmctx_vmtable_definition_base(def_index))?;
300                        let current_elements_offset = vmctx_offset(
301                            self.offsets
302                                .vmctx_vmtable_definition_current_elements(def_index),
303                        )?;
304                        (vmctx, base_offset, current_elements_offset)
305                    } else {
306                        let from_offset = self.offsets.vmctx_vmtable_import(index);
307                        let flags = insert_mem_flags(func, MemFlagsData::trusted().with_readonly());
308                        let table = func.create_global_value(ir::GlobalValueData::Load {
309                            base: vmctx,
310                            offset: Offset32::new(vmctx_offset(from_offset)?),
311                            global_type: pointer_type,
312                            flags,
313                        });
314                        let base_offset = i32::from(self.offsets.vmtable_definition_base());
315                        let current_elements_offset =
316                            i32::from(self.offsets.vmtable_definition_current_elements());
317                        (table, base_offset, current_elements_offset)
318                    }
319                };
320
321                let flags = if Some(table.minimum) == table.maximum {
322                    // A fixed-size table can't be resized so its base address won't
323                    // change.
324                    insert_mem_flags(func, MemFlagsData::trusted().with_readonly())
325                } else {
326                    insert_mem_flags(func, MemFlagsData::trusted())
327                };
328                let base_gv = func.create_global_value(ir::GlobalValueData::Load {
329                    base: ptr,
330                    offset: Offset32::new(base_offset),
331                    global_type: pointer_type,
332                    flags,
333                });
334
335                let bound = if Some(table.minimum) == table.maximum {
336                    TableSize::Static {
337                        bound: table.minimum,
338                    }
339                } else {
340                    let flags = insert_mem_flags(func, MemFlagsData::trusted());
341                    TableSize::Dynamic {
342                        bound_gv: func.create_global_value(ir::GlobalValueData::Load {
343                            base: ptr,
344                            offset: Offset32::new(current_elements_offset),
345                            global_type: ir::Type::int(
346                                u16::from(
347                                    self.offsets.size_of_vmtable_definition_current_elements(),
348                                ) * 8,
349                            )
350                            .unwrap(),
351                            flags,
352                        }),
353                    }
354                };
355
356                (base_gv, 0, bound, self.reference_type().bytes(), false)
357            };
358
359        self.tables[index] = Some(TableData {
360            base_gv,
361            base_offset: table_base_offset,
362            bound,
363            element_size,
364            inline_anyfunc,
365        });
366        Ok(())
367    }
368
369    fn vmctx(&mut self, func: &mut Function) -> ir::GlobalValue {
370        self.vmctx.unwrap_or_else(|| {
371            let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
372            self.vmctx = Some(vmctx);
373            vmctx
374        })
375    }
376
377    fn get_table_fill_sig(&mut self, func: &mut Function) -> ir::SigRef {
378        let sig = self.table_fill_sig.unwrap_or_else(|| {
379            func.import_signature(Signature {
380                params: vec![
381                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
382                    // table index
383                    AbiParam::new(I32),
384                    // dst
385                    AbiParam::new(I32),
386                    // value
387                    AbiParam::new(self.reference_type()),
388                    // len
389                    AbiParam::new(I32),
390                ],
391                returns: vec![],
392                call_conv: self.target_config.default_call_conv,
393            })
394        });
395        self.table_fill_sig = Some(sig);
396        sig
397    }
398
399    fn get_table_fill_func(
400        &mut self,
401        func: &mut Function,
402        table_index: TableIndex,
403    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
404        (
405            self.get_table_fill_sig(func),
406            table_index.index(),
407            VMBuiltinFunctionIndex::get_table_fill_index(),
408        )
409    }
410
411    fn get_func_ref_sig(&mut self, func: &mut Function) -> ir::SigRef {
412        let sig = self.func_ref_sig.unwrap_or_else(|| {
413            func.import_signature(Signature {
414                params: vec![
415                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
416                    AbiParam::new(I32),
417                ],
418                returns: vec![AbiParam::new(self.reference_type())],
419                call_conv: self.target_config.default_call_conv,
420            })
421        });
422        self.func_ref_sig = Some(sig);
423        sig
424    }
425
426    fn get_func_ref_func(
427        &mut self,
428        func: &mut Function,
429        function_index: FunctionIndex,
430    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
431        (
432            self.get_func_ref_sig(func),
433            function_index.index(),
434            VMBuiltinFunctionIndex::get_func_ref_index(),
435        )
436    }
437
438    fn get_table_get_sig(&mut self, func: &mut Function) -> ir::SigRef {
439        let sig = self.table_get_sig.unwrap_or_else(|| {
440            func.import_signature(Signature {
441                params: vec![
442                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
443                    AbiParam::new(I32),
444                    AbiParam::new(I32),
445                ],
446                returns: vec![AbiParam::new(self.reference_type())],
447                call_conv: self.target_config.default_call_conv,
448            })
449        });
450        self.table_get_sig = Some(sig);
451        sig
452    }
453
454    fn get_table_get_func(
455        &mut self,
456        func: &mut Function,
457        table_index: TableIndex,
458    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
459        if self.module.is_imported_table(table_index) {
460            (
461                self.get_table_get_sig(func),
462                table_index.index(),
463                VMBuiltinFunctionIndex::get_imported_table_get_index(),
464            )
465        } else {
466            (
467                self.get_table_get_sig(func),
468                self.module.local_table_index(table_index).unwrap().index(),
469                VMBuiltinFunctionIndex::get_table_get_index(),
470            )
471        }
472    }
473
474    fn get_table_set_sig(&mut self, func: &mut Function) -> ir::SigRef {
475        let sig = self.table_set_sig.unwrap_or_else(|| {
476            func.import_signature(Signature {
477                params: vec![
478                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
479                    AbiParam::new(I32),
480                    AbiParam::new(I32),
481                    AbiParam::new(self.reference_type()),
482                ],
483                returns: vec![],
484                call_conv: self.target_config.default_call_conv,
485            })
486        });
487        self.table_set_sig = Some(sig);
488        sig
489    }
490
491    fn get_table_set_func(
492        &mut self,
493        func: &mut Function,
494        table_index: TableIndex,
495    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
496        if self.module.is_imported_table(table_index) {
497            (
498                self.get_table_set_sig(func),
499                table_index.index(),
500                VMBuiltinFunctionIndex::get_imported_table_set_index(),
501            )
502        } else {
503            (
504                self.get_table_set_sig(func),
505                self.module.local_table_index(table_index).unwrap().index(),
506                VMBuiltinFunctionIndex::get_table_set_index(),
507            )
508        }
509    }
510
511    fn get_table_grow_sig(&mut self, func: &mut Function) -> ir::SigRef {
512        let sig = self.table_grow_sig.unwrap_or_else(|| {
513            func.import_signature(Signature {
514                params: vec![
515                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
516                    // TODO: figure out what the representation of a Wasm value is
517                    AbiParam::new(self.reference_type()),
518                    AbiParam::new(I32),
519                    AbiParam::new(I32),
520                ],
521                returns: vec![AbiParam::new(I32)],
522                call_conv: self.target_config.default_call_conv,
523            })
524        });
525        self.table_grow_sig = Some(sig);
526        sig
527    }
528
529    /// Return the table.grow function signature to call for the given index, along with the
530    /// translated index value to pass to it and its index in `VMBuiltinFunctionsArray`.
531    fn get_table_grow_func(
532        &mut self,
533        func: &mut Function,
534        index: TableIndex,
535    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
536        if self.module.is_imported_table(index) {
537            (
538                self.get_table_grow_sig(func),
539                index.index(),
540                VMBuiltinFunctionIndex::get_imported_table_grow_index(),
541            )
542        } else {
543            (
544                self.get_table_grow_sig(func),
545                self.module.local_table_index(index).unwrap().index(),
546                VMBuiltinFunctionIndex::get_table_grow_index(),
547            )
548        }
549    }
550
551    fn get_memory_grow_sig(&mut self, func: &mut Function) -> ir::SigRef {
552        let sig = self.memory_grow_sig.unwrap_or_else(|| {
553            func.import_signature(Signature {
554                params: vec![
555                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
556                    AbiParam::new(I32),
557                    AbiParam::new(I32),
558                ],
559                returns: vec![AbiParam::new(I32)],
560                call_conv: self.target_config.default_call_conv,
561            })
562        });
563        self.memory_grow_sig = Some(sig);
564        sig
565    }
566
567    /// Return the memory.grow function signature to call for the given index, along with the
568    /// translated index value to pass to it and its index in `VMBuiltinFunctionsArray`.
569    fn get_memory_grow_func(
570        &mut self,
571        func: &mut Function,
572        index: MemoryIndex,
573    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
574        if self.module.is_imported_memory(index) {
575            (
576                self.get_memory_grow_sig(func),
577                index.index(),
578                VMBuiltinFunctionIndex::get_imported_memory32_grow_index(),
579            )
580        } else {
581            (
582                self.get_memory_grow_sig(func),
583                self.module.local_memory_index(index).unwrap().index(),
584                VMBuiltinFunctionIndex::get_memory32_grow_index(),
585            )
586        }
587    }
588
589    fn get_table_size_sig(&mut self, func: &mut Function) -> ir::SigRef {
590        let sig = self.table_size_sig.unwrap_or_else(|| {
591            func.import_signature(Signature {
592                params: vec![
593                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
594                    AbiParam::new(I32),
595                ],
596                returns: vec![AbiParam::new(I32)],
597                call_conv: self.target_config.default_call_conv,
598            })
599        });
600        self.table_size_sig = Some(sig);
601        sig
602    }
603
604    /// Return the memory.size function signature to call for the given index, along with the
605    /// translated index value to pass to it and its index in `VMBuiltinFunctionsArray`.
606    fn get_table_size_func(
607        &mut self,
608        func: &mut Function,
609        index: TableIndex,
610    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
611        if self.module.is_imported_table(index) {
612            (
613                self.get_table_size_sig(func),
614                index.index(),
615                VMBuiltinFunctionIndex::get_imported_table_size_index(),
616            )
617        } else {
618            (
619                self.get_table_size_sig(func),
620                self.module.local_table_index(index).unwrap().index(),
621                VMBuiltinFunctionIndex::get_table_size_index(),
622            )
623        }
624    }
625
626    fn get_memory32_size_sig(&mut self, func: &mut Function) -> ir::SigRef {
627        let sig = self.memory32_size_sig.unwrap_or_else(|| {
628            func.import_signature(Signature {
629                params: vec![
630                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
631                    AbiParam::new(I32),
632                ],
633                returns: vec![AbiParam::new(I32)],
634                call_conv: self.target_config.default_call_conv,
635            })
636        });
637        self.memory32_size_sig = Some(sig);
638        sig
639    }
640
641    /// Return the memory.size function signature to call for the given index, along with the
642    /// translated index value to pass to it and its index in `VMBuiltinFunctionsArray`.
643    fn get_memory_size_func(
644        &mut self,
645        func: &mut Function,
646        index: MemoryIndex,
647    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
648        if self.module.is_imported_memory(index) {
649            (
650                self.get_memory32_size_sig(func),
651                index.index(),
652                VMBuiltinFunctionIndex::get_imported_memory32_size_index(),
653            )
654        } else {
655            (
656                self.get_memory32_size_sig(func),
657                self.module.local_memory_index(index).unwrap().index(),
658                VMBuiltinFunctionIndex::get_memory32_size_index(),
659            )
660        }
661    }
662
663    fn get_table_copy_sig(&mut self, func: &mut Function) -> ir::SigRef {
664        let sig = self.table_copy_sig.unwrap_or_else(|| {
665            func.import_signature(Signature {
666                params: vec![
667                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
668                    // Destination table index.
669                    AbiParam::new(I32),
670                    // Source table index.
671                    AbiParam::new(I32),
672                    // Index within destination table.
673                    AbiParam::new(I32),
674                    // Index within source table.
675                    AbiParam::new(I32),
676                    // Number of elements to copy.
677                    AbiParam::new(I32),
678                ],
679                returns: vec![],
680                call_conv: self.target_config.default_call_conv,
681            })
682        });
683        self.table_copy_sig = Some(sig);
684        sig
685    }
686
687    fn get_table_copy_func(
688        &mut self,
689        func: &mut Function,
690        dst_table_index: TableIndex,
691        src_table_index: TableIndex,
692    ) -> (ir::SigRef, usize, usize, VMBuiltinFunctionIndex) {
693        let sig = self.get_table_copy_sig(func);
694        (
695            sig,
696            dst_table_index.as_u32() as usize,
697            src_table_index.as_u32() as usize,
698            VMBuiltinFunctionIndex::get_table_copy_index(),
699        )
700    }
701
702    fn get_table_init_sig(&mut self, func: &mut Function) -> ir::SigRef {
703        let sig = self.table_init_sig.unwrap_or_else(|| {
704            func.import_signature(Signature {
705                params: vec![
706                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
707                    // Table index.
708                    AbiParam::new(I32),
709                    // Segment index.
710                    AbiParam::new(I32),
711                    // Destination index within table.
712                    AbiParam::new(I32),
713                    // Source index within segment.
714                    AbiParam::new(I32),
715                    // Number of elements to initialize.
716                    AbiParam::new(I32),
717                ],
718                returns: vec![],
719                call_conv: self.target_config.default_call_conv,
720            })
721        });
722        self.table_init_sig = Some(sig);
723        sig
724    }
725
726    fn get_table_init_func(
727        &mut self,
728        func: &mut Function,
729        table_index: TableIndex,
730    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
731        let sig = self.get_table_init_sig(func);
732        let table_index = table_index.as_u32() as usize;
733        (
734            sig,
735            table_index,
736            VMBuiltinFunctionIndex::get_table_init_index(),
737        )
738    }
739
740    fn get_elem_drop_sig(&mut self, func: &mut Function) -> ir::SigRef {
741        let sig = self.elem_drop_sig.unwrap_or_else(|| {
742            func.import_signature(Signature {
743                params: vec![
744                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
745                    // Element index.
746                    AbiParam::new(I32),
747                ],
748                returns: vec![],
749                call_conv: self.target_config.default_call_conv,
750            })
751        });
752        self.elem_drop_sig = Some(sig);
753        sig
754    }
755
756    fn get_elem_drop_func(&mut self, func: &mut Function) -> (ir::SigRef, VMBuiltinFunctionIndex) {
757        let sig = self.get_elem_drop_sig(func);
758        (sig, VMBuiltinFunctionIndex::get_elem_drop_index())
759    }
760
761    fn get_memory_copy_sig(&mut self, func: &mut Function) -> ir::SigRef {
762        let sig = self.memory_copy_sig.unwrap_or_else(|| {
763            func.import_signature(Signature {
764                params: vec![
765                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
766                    // Destination memory index.
767                    AbiParam::new(I32),
768                    // Source memory index.
769                    AbiParam::new(I32),
770                    // Destination address.
771                    AbiParam::new(I32),
772                    // Source address.
773                    AbiParam::new(I32),
774                    // Length.
775                    AbiParam::new(I32),
776                ],
777                returns: vec![],
778                call_conv: self.target_config.default_call_conv,
779            })
780        });
781        self.memory_copy_sig = Some(sig);
782        sig
783    }
784
785    fn get_memory_copy_func(
786        &mut self,
787        func: &mut Function,
788    ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
789        (
790            self.get_memory_copy_sig(func),
791            VMBuiltinFunctionIndex::get_memory_copy_index(),
792        )
793    }
794
795    fn get_memory_fill_sig(&mut self, func: &mut Function) -> ir::SigRef {
796        let sig = self.memory_fill_sig.unwrap_or_else(|| {
797            func.import_signature(Signature {
798                params: vec![
799                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
800                    // Memory index.
801                    AbiParam::new(I32),
802                    // Destination address.
803                    AbiParam::new(I32),
804                    // Value.
805                    AbiParam::new(I32),
806                    // Length.
807                    AbiParam::new(I32),
808                ],
809                returns: vec![],
810                call_conv: self.target_config.default_call_conv,
811            })
812        });
813        self.memory_fill_sig = Some(sig);
814        sig
815    }
816
817    fn get_memory_fill_func(
818        &mut self,
819        func: &mut Function,
820        memory_index: MemoryIndex,
821    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
822        let sig = self.get_memory_fill_sig(func);
823        if let Some(local_memory_index) = self.module.local_memory_index(memory_index) {
824            (
825                sig,
826                local_memory_index.index(),
827                VMBuiltinFunctionIndex::get_memory_fill_index(),
828            )
829        } else {
830            (
831                sig,
832                memory_index.index(),
833                VMBuiltinFunctionIndex::get_imported_memory_fill_index(),
834            )
835        }
836    }
837
838    fn get_memory_init_sig(&mut self, func: &mut Function) -> ir::SigRef {
839        let sig = self.memory_init_sig.unwrap_or_else(|| {
840            func.import_signature(Signature {
841                params: vec![
842                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
843                    // Memory index.
844                    AbiParam::new(I32),
845                    // Data index.
846                    AbiParam::new(I32),
847                    // Destination address.
848                    AbiParam::new(I32),
849                    // Source index within the data segment.
850                    AbiParam::new(I32),
851                    // Length.
852                    AbiParam::new(I32),
853                ],
854                returns: vec![],
855                call_conv: self.target_config.default_call_conv,
856            })
857        });
858        self.memory_init_sig = Some(sig);
859        sig
860    }
861
862    fn get_memory_init_func(
863        &mut self,
864        func: &mut Function,
865    ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
866        let sig = self.get_memory_init_sig(func);
867        (sig, VMBuiltinFunctionIndex::get_memory_init_index())
868    }
869
870    fn get_data_drop_sig(&mut self, func: &mut Function) -> ir::SigRef {
871        let sig = self.data_drop_sig.unwrap_or_else(|| {
872            func.import_signature(Signature {
873                params: vec![
874                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
875                    // Data index.
876                    AbiParam::new(I32),
877                ],
878                returns: vec![],
879                call_conv: self.target_config.default_call_conv,
880            })
881        });
882        self.data_drop_sig = Some(sig);
883        sig
884    }
885
886    fn get_data_drop_func(&mut self, func: &mut Function) -> (ir::SigRef, VMBuiltinFunctionIndex) {
887        let sig = self.get_data_drop_sig(func);
888        (sig, VMBuiltinFunctionIndex::get_data_drop_index())
889    }
890
891    fn get_memory32_atomic_wait32_sig(&mut self, func: &mut Function) -> ir::SigRef {
892        let sig = self.memory32_atomic_wait32_sig.unwrap_or_else(|| {
893            func.import_signature(Signature {
894                params: vec![
895                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
896                    // Memory Index
897                    AbiParam::new(I32),
898                    // Dst
899                    AbiParam::new(I32),
900                    // Val
901                    AbiParam::new(I32),
902                    // Timeout
903                    AbiParam::new(I64),
904                ],
905                returns: vec![AbiParam::new(I32)],
906                call_conv: self.target_config.default_call_conv,
907            })
908        });
909        self.memory32_atomic_wait32_sig = Some(sig);
910        sig
911    }
912
913    /// Return the memory.atomic.wait32 function signature to call for the given index,
914    /// along with the translated index value to pass to it
915    /// and its index in `VMBuiltinFunctionsArray`.
916    fn get_memory_atomic_wait32_func(
917        &mut self,
918        func: &mut Function,
919        index: MemoryIndex,
920    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
921        if self.module.is_imported_memory(index) {
922            (
923                self.get_memory32_atomic_wait32_sig(func),
924                index.index(),
925                VMBuiltinFunctionIndex::get_imported_memory_atomic_wait32_index(),
926            )
927        } else {
928            (
929                self.get_memory32_atomic_wait32_sig(func),
930                self.module.local_memory_index(index).unwrap().index(),
931                VMBuiltinFunctionIndex::get_memory_atomic_wait32_index(),
932            )
933        }
934    }
935
936    fn get_memory32_atomic_wait64_sig(&mut self, func: &mut Function) -> ir::SigRef {
937        let sig = self.memory32_atomic_wait64_sig.unwrap_or_else(|| {
938            func.import_signature(Signature {
939                params: vec![
940                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
941                    // Memory Index
942                    AbiParam::new(I32),
943                    // Dst
944                    AbiParam::new(I32),
945                    // Val
946                    AbiParam::new(I64),
947                    // Timeout
948                    AbiParam::new(I64),
949                ],
950                returns: vec![AbiParam::new(I32)],
951                call_conv: self.target_config.default_call_conv,
952            })
953        });
954        self.memory32_atomic_wait64_sig = Some(sig);
955        sig
956    }
957
958    /// Return the memory.atomic.wait64 function signature to call for the given index,
959    /// along with the translated index value to pass to it
960    /// and its index in `VMBuiltinFunctionsArray`.
961    fn get_memory_atomic_wait64_func(
962        &mut self,
963        func: &mut Function,
964        index: MemoryIndex,
965    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
966        if self.module.is_imported_memory(index) {
967            (
968                self.get_memory32_atomic_wait64_sig(func),
969                index.index(),
970                VMBuiltinFunctionIndex::get_imported_memory_atomic_wait64_index(),
971            )
972        } else {
973            (
974                self.get_memory32_atomic_wait64_sig(func),
975                self.module.local_memory_index(index).unwrap().index(),
976                VMBuiltinFunctionIndex::get_memory_atomic_wait64_index(),
977            )
978        }
979    }
980
981    fn get_memory32_atomic_notify_sig(&mut self, func: &mut Function) -> ir::SigRef {
982        let sig = self.memory32_atomic_notify_sig.unwrap_or_else(|| {
983            func.import_signature(Signature {
984                params: vec![
985                    AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
986                    // Memory Index
987                    AbiParam::new(I32),
988                    // Dst
989                    AbiParam::new(I32),
990                    // Count
991                    AbiParam::new(I32),
992                ],
993                returns: vec![AbiParam::new(I32)],
994                call_conv: self.target_config.default_call_conv,
995            })
996        });
997        self.memory32_atomic_notify_sig = Some(sig);
998        sig
999    }
1000
1001    /// Return the memory.atomic.notify function signature to call for the given index,
1002    /// along with the translated index value to pass to it
1003    /// and its index in `VMBuiltinFunctionsArray`.
1004    fn get_memory_atomic_notify_func(
1005        &mut self,
1006        func: &mut Function,
1007        index: MemoryIndex,
1008    ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
1009        if self.module.is_imported_memory(index) {
1010            (
1011                self.get_memory32_atomic_notify_sig(func),
1012                index.index(),
1013                VMBuiltinFunctionIndex::get_imported_memory_atomic_notify_index(),
1014            )
1015        } else {
1016            (
1017                self.get_memory32_atomic_notify_sig(func),
1018                self.module.local_memory_index(index).unwrap().index(),
1019                VMBuiltinFunctionIndex::get_memory_atomic_notify_index(),
1020            )
1021        }
1022    }
1023
1024    fn get_personality2_func(
1025        &mut self,
1026        func: &mut Function,
1027    ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1028        let sig = self.personality2_sig.unwrap_or_else(|| {
1029            let mut signature = Signature::new(self.target_config.default_call_conv);
1030            signature.params.push(AbiParam::new(self.pointer_type()));
1031            signature.params.push(AbiParam::new(self.pointer_type()));
1032            signature.returns.push(AbiParam::new(TAG_TYPE));
1033            let sig = func.import_signature(signature);
1034            self.personality2_sig = Some(sig);
1035            sig
1036        });
1037        (
1038            sig,
1039            VMBuiltinFunctionIndex::get_imported_personality2_index(),
1040        )
1041    }
1042
1043    fn get_throw_func(&mut self, func: &mut Function) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1044        let sig = self.throw_sig.unwrap_or_else(|| {
1045            let mut signature = Signature::new(self.target_config.default_call_conv);
1046            signature.params.push(AbiParam::special(
1047                self.pointer_type(),
1048                ArgumentPurpose::VMContext,
1049            ));
1050            signature.params.push(AbiParam::new(EXN_REF_TYPE));
1051            let sig = func.import_signature(signature);
1052            self.throw_sig = Some(sig);
1053            sig
1054        });
1055        (sig, VMBuiltinFunctionIndex::get_imported_throw_index())
1056    }
1057
1058    fn get_raise_trap_func(&mut self, func: &mut Function) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1059        let sig = self.raise_trap_sig.unwrap_or_else(|| {
1060            let mut signature = Signature::new(self.target_config.default_call_conv);
1061            signature.params.push(AbiParam::new(I32));
1062            let sig = func.import_signature(signature);
1063            self.raise_trap_sig = Some(sig);
1064            sig
1065        });
1066        (sig, VMBuiltinFunctionIndex::get_raise_trap_index())
1067    }
1068
1069    fn get_alloc_exception_func(
1070        &mut self,
1071        func: &mut Function,
1072    ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1073        let sig = self.alloc_exception_sig.unwrap_or_else(|| {
1074            let mut signature = Signature::new(self.target_config.default_call_conv);
1075            signature.params.push(AbiParam::special(
1076                self.pointer_type(),
1077                ArgumentPurpose::VMContext,
1078            ));
1079            signature.params.push(AbiParam::new(TAG_TYPE));
1080            signature.returns.push(AbiParam::new(EXN_REF_TYPE));
1081            let sig = func.import_signature(signature);
1082            self.alloc_exception_sig = Some(sig);
1083            sig
1084        });
1085        (
1086            sig,
1087            VMBuiltinFunctionIndex::get_imported_alloc_exception_index(),
1088        )
1089    }
1090
1091    fn get_read_exnref_func(
1092        &mut self,
1093        func: &mut Function,
1094    ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1095        let sig = self.read_exnref_sig.unwrap_or_else(|| {
1096            let mut signature = Signature::new(self.target_config.default_call_conv);
1097            signature.params.push(AbiParam::special(
1098                self.pointer_type(),
1099                ArgumentPurpose::VMContext,
1100            ));
1101            signature.params.push(AbiParam::new(EXN_REF_TYPE));
1102            signature.returns.push(AbiParam::new(self.pointer_type()));
1103            let sig = func.import_signature(signature);
1104            self.read_exnref_sig = Some(sig);
1105            sig
1106        });
1107        (
1108            sig,
1109            VMBuiltinFunctionIndex::get_imported_read_exnref_index(),
1110        )
1111    }
1112
1113    fn get_read_exception_func(
1114        &mut self,
1115        func: &mut Function,
1116    ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1117        let sig = self.read_exception_sig.unwrap_or_else(|| {
1118            let mut signature = Signature::new(self.target_config.default_call_conv);
1119            signature.params.push(AbiParam::new(self.pointer_type()));
1120            signature.returns.push(AbiParam::new(EXN_REF_TYPE));
1121            let sig = func.import_signature(signature);
1122            self.read_exception_sig = Some(sig);
1123            sig
1124        });
1125        (
1126            sig,
1127            VMBuiltinFunctionIndex::get_imported_exception_into_exnref_index(),
1128        )
1129    }
1130
1131    fn exception_type_layout(&mut self, tag_index: TagIndex) -> WasmResult<&ExceptionTypeLayout> {
1132        let key = tag_index.as_u32();
1133        if !self.exception_type_layouts.contains_key(&key) {
1134            let layout = self.compute_exception_type_layout(tag_index)?;
1135            self.exception_type_layouts.insert(key, layout);
1136        }
1137        Ok(self.exception_type_layouts.get(&key).unwrap())
1138    }
1139
1140    fn compute_exception_type_layout(
1141        &self,
1142        tag_index: TagIndex,
1143    ) -> WasmResult<ExceptionTypeLayout> {
1144        let sig_index = self.module.tags[tag_index];
1145        let func_type = &self.module.signatures[sig_index];
1146        let mut offset = 0u32;
1147        let mut max_align = 1u32;
1148        let mut fields = SmallVec::<[ExceptionFieldLayout; 4]>::new();
1149
1150        for wasm_ty in func_type.params() {
1151            let ir_ty = self.map_wasmer_type_to_ir(*wasm_ty)?;
1152            let field_size = ir_ty.bytes();
1153            let align = field_size.max(1);
1154            max_align = max_align.max(align);
1155            offset = offset.next_multiple_of(align);
1156            fields.push(ExceptionFieldLayout { offset, ty: ir_ty });
1157            offset = offset
1158                .checked_add(field_size)
1159                .ok_or_else(|| WasmError::Unsupported("exception payload too large".to_string()))?;
1160        }
1161
1162        Ok(ExceptionTypeLayout { fields })
1163    }
1164
1165    fn map_wasmer_type_to_ir(&self, ty: WasmerType) -> WasmResult<ir::Type> {
1166        Ok(match ty {
1167            WasmerType::I32 => ir::types::I32,
1168            WasmerType::I64 => ir::types::I64,
1169            WasmerType::F32 => ir::types::F32,
1170            WasmerType::F64 => ir::types::F64,
1171            WasmerType::V128 => ir::types::I8X16,
1172            WasmerType::FuncRef | WasmerType::ExternRef | WasmerType::ExceptionRef => {
1173                self.reference_type()
1174            }
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 | WasmerType::ExceptionRef => {
1665                    self.reference_type()
1666                }
1667            },
1668        })
1669    }
1670
1671    pub(crate) fn make_indirect_sig(
1672        &mut self,
1673        func: &mut ir::Function,
1674        index: SignatureIndex,
1675    ) -> WasmResult<ir::SigRef> {
1676        Ok(func.import_signature(self.signatures[index].clone()))
1677    }
1678
1679    pub(crate) fn make_direct_func(
1680        &mut self,
1681        func: &mut ir::Function,
1682        index: FunctionIndex,
1683    ) -> WasmResult<ir::FuncRef> {
1684        let sigidx = self.module.functions[index];
1685        let signature = func.import_signature(self.signatures[sigidx].clone());
1686        let name = get_function_name(func, index);
1687
1688        Ok(func.import_function(ir::ExtFuncData {
1689            name,
1690            signature,
1691            colocated: true,
1692            patchable: false,
1693        }))
1694    }
1695
1696    fn prepare_wasm_call(
1697        &self,
1698        builder: &mut FunctionBuilder,
1699        result_types: &[WasmerType],
1700    ) -> (ReturnAbi, Option<(ir::Value, abi::ReturnAreaLayout)>) {
1701        let return_abi = abi::classify_returns(self.architecture, result_types);
1702        let sret = match &return_abi {
1703            ReturnAbi::Sret(types) => Some(abi::allocate_return_area(
1704                builder,
1705                types,
1706                self.target_config,
1707            )),
1708            _ => None,
1709        };
1710        (return_abi, sret)
1711    }
1712
1713    fn finish_wasm_call(
1714        &self,
1715        builder: &mut FunctionBuilder,
1716        return_abi: &ReturnAbi,
1717        carriers: &[ir::Value],
1718        sret: Option<(ir::Value, abi::ReturnAreaLayout)>,
1719    ) -> SmallVec<[ir::Value; 4]> {
1720        match return_abi {
1721            ReturnAbi::Sret(types) => {
1722                let (ptr, layout) = sret.expect("sret call has a return area");
1723                abi::load_sret(builder, ptr, &layout, types, self.target_config)
1724            }
1725            _ => abi::unpack_register_returns(builder, return_abi, carriers, self.target_config),
1726        }
1727    }
1728
1729    #[allow(clippy::too_many_arguments)]
1730    pub(crate) fn translate_call_indirect(
1731        &mut self,
1732        builder: &mut FunctionBuilder,
1733        table_index: TableIndex,
1734        sig_index: SignatureIndex,
1735        sig_ref: ir::SigRef,
1736        callee: ir::Value,
1737        call_args: &[ir::Value],
1738        landing_pad: Option<LandingPad>,
1739    ) -> WasmResult<SmallVec<[ir::Value; 4]>> {
1740        let pointer_type = self.pointer_type();
1741
1742        // Get the anyfunc pointer (the funcref) from the table.
1743        let (anyfunc_ptr, inline_anyfunc) =
1744            self.get_or_init_funcref_table_elem(builder, table_index, callee)?;
1745
1746        // Dereference table_entry_addr to get the function address.
1747        let mem_flags = ir::MemFlagsData::trusted();
1748
1749        // check if the funcref is null
1750        if !inline_anyfunc {
1751            builder
1752                .ins()
1753                .trapz(anyfunc_ptr, crate::TRAP_INDIRECT_CALL_TO_NULL);
1754        }
1755
1756        let func_addr = builder.ins().load(
1757            pointer_type,
1758            mem_flags,
1759            anyfunc_ptr,
1760            i32::from(self.offsets.vmcaller_checked_anyfunc_func_ptr()),
1761        );
1762
1763        if inline_anyfunc {
1764            builder
1765                .ins()
1766                .trapz(func_addr, crate::TRAP_INDIRECT_CALL_TO_NULL);
1767        }
1768
1769        // If necessary, check the signature.
1770        match self.table_styles[table_index] {
1771            TableStyle::CallerChecksSignature => {
1772                let sig_hash_type = ir::types::I32;
1773                let expected_sig_hash = builder.ins().iconst(
1774                    sig_hash_type,
1775                    i64::from(self.signature_hashes[sig_index].as_u32()),
1776                );
1777
1778                // Load the callee ID.
1779                let mem_flags = ir::MemFlagsData::trusted();
1780                let callee_sig_hash = builder.ins().load(
1781                    sig_hash_type,
1782                    mem_flags,
1783                    anyfunc_ptr,
1784                    i32::from(self.offsets.vmcaller_checked_anyfunc_signature_hash()),
1785                );
1786
1787                // Check that they match.
1788                let cmp = builder
1789                    .ins()
1790                    .icmp(IntCC::Equal, callee_sig_hash, expected_sig_hash);
1791                builder.ins().trapz(cmp, crate::TRAP_BAD_SIGNATURE);
1792            }
1793        }
1794
1795        let (return_abi, sret) =
1796            self.prepare_wasm_call(builder, self.module.signatures[sig_index].results());
1797        let mut real_call_args = Vec::with_capacity(call_args.len() + 2);
1798        if let Some((ptr, _)) = &sret {
1799            real_call_args.push(*ptr);
1800        }
1801
1802        // First append the callee vmctx address.
1803        let vmctx = builder.ins().load(
1804            pointer_type,
1805            mem_flags,
1806            anyfunc_ptr,
1807            i32::from(self.offsets.vmcaller_checked_anyfunc_vmctx()),
1808        );
1809        real_call_args.push(vmctx);
1810
1811        // Then append the regular call arguments.
1812        real_call_args.extend_from_slice(call_args);
1813
1814        let results = self.call_indirect_with_handlers(
1815            builder,
1816            sig_ref,
1817            func_addr,
1818            &real_call_args,
1819            Some(vmctx),
1820            landing_pad,
1821            false,
1822        );
1823        Ok(self.finish_wasm_call(builder, &return_abi, &results, sret))
1824    }
1825
1826    pub(crate) fn translate_call(
1827        &mut self,
1828        builder: &mut FunctionBuilder,
1829        callee_index: FunctionIndex,
1830        callee: ir::FuncRef,
1831        call_args: &[ir::Value],
1832        landing_pad: Option<LandingPad>,
1833    ) -> WasmResult<SmallVec<[ir::Value; 4]>> {
1834        let sig_index = self.module.functions[callee_index];
1835        let (return_abi, sret) =
1836            self.prepare_wasm_call(builder, self.module.signatures[sig_index].results());
1837        let mut real_call_args = Vec::with_capacity(call_args.len() + 2);
1838        if let Some((ptr, _)) = &sret {
1839            real_call_args.push(*ptr);
1840        }
1841
1842        // Handle direct calls to locally-defined functions.
1843        if !self.module.is_imported_function(callee_index) {
1844            // Let's get the caller vmctx
1845            let caller_vmctx = builder
1846                .func
1847                .special_param(ArgumentPurpose::VMContext)
1848                .unwrap();
1849            // First append the callee vmctx address, which is the same as the caller vmctx in
1850            // this case.
1851            real_call_args.push(caller_vmctx);
1852
1853            // Then append the regular call arguments.
1854            real_call_args.extend_from_slice(call_args);
1855
1856            let results = self.call_with_handlers(
1857                builder,
1858                callee,
1859                &real_call_args,
1860                Some(caller_vmctx),
1861                landing_pad,
1862                false,
1863            );
1864            return Ok(self.finish_wasm_call(builder, &return_abi, &results, sret));
1865        }
1866
1867        // Handle direct calls to imported functions. We use an indirect call
1868        // so that we don't have to patch the code at runtime.
1869        let pointer_type = self.pointer_type();
1870        let sig_ref = builder.func.dfg.ext_funcs[callee].signature;
1871        let vmctx = self.vmctx(builder.func);
1872        let base = materialize_global_value(&mut builder.cursor(), pointer_type, vmctx);
1873
1874        let mem_flags = ir::MemFlagsData::trusted();
1875
1876        // Load the callee address.
1877        let body_offset = vmctx_offset(self.offsets.vmctx_vmfunction_import_body(callee_index))?;
1878        let func_addr = builder
1879            .ins()
1880            .load(pointer_type, mem_flags, base, body_offset);
1881
1882        // First append the callee vmctx address.
1883        let vmctx_arg_offset =
1884            vmctx_offset(self.offsets.vmctx_vmfunction_import_vmctx(callee_index))?;
1885        let vmctx = builder
1886            .ins()
1887            .load(pointer_type, mem_flags, base, vmctx_arg_offset);
1888        real_call_args.push(vmctx);
1889
1890        // Then append the regular call arguments.
1891        real_call_args.extend_from_slice(call_args);
1892
1893        let results = self.call_indirect_with_handlers(
1894            builder,
1895            sig_ref,
1896            func_addr,
1897            &real_call_args,
1898            Some(vmctx),
1899            landing_pad,
1900            false,
1901        );
1902        Ok(self.finish_wasm_call(builder, &return_abi, &results, sret))
1903    }
1904
1905    pub(crate) fn tag_param_arity(&self, tag_index: TagIndex) -> usize {
1906        let sig_index = self.module.tags[tag_index];
1907        let signature = &self.module.signatures[sig_index];
1908        signature.params().len()
1909    }
1910
1911    pub(crate) fn translate_exn_pointer_to_ref(
1912        &mut self,
1913        builder: &mut FunctionBuilder,
1914        exn_ptr: ir::Value,
1915    ) -> WasmResult<ir::Value> {
1916        let (read_sig, read_idx) = self.get_read_exception_func(builder.func);
1917        let mut pos = builder.cursor();
1918        let (_, read_addr) = self.translate_load_builtin_function_address(&mut pos, read_idx)?;
1919        let read_call = builder.ins().call_indirect(read_sig, read_addr, &[exn_ptr]);
1920        Ok(builder.inst_results(read_call)[0])
1921    }
1922
1923    pub(crate) fn translate_exn_unbox(
1924        &mut self,
1925        builder: &mut FunctionBuilder,
1926        tag_index: TagIndex,
1927        exnref: ir::Value,
1928    ) -> WasmResult<SmallVec<[ir::Value; 4]>> {
1929        let layout = self.exception_type_layout(tag_index)?.clone();
1930
1931        let (read_exnref_sig, read_exnref_idx) = self.get_read_exnref_func(builder.func);
1932        let mut pos = builder.cursor();
1933        let (vmctx, read_exnref_addr) =
1934            self.translate_load_builtin_function_address(&mut pos, read_exnref_idx)?;
1935        let read_exnref_call =
1936            builder
1937                .ins()
1938                .call_indirect(read_exnref_sig, read_exnref_addr, &[vmctx, exnref]);
1939        let payload_ptr = builder.inst_results(read_exnref_call)[0];
1940
1941        let mut values = SmallVec::<[ir::Value; 4]>::with_capacity(layout.fields.len());
1942        let data_flags = ir::MemFlagsData::trusted();
1943        for field in &layout.fields {
1944            let value = builder.ins().load(
1945                field.ty,
1946                data_flags,
1947                payload_ptr,
1948                Offset32::new(field.offset as i32),
1949            );
1950            values.push(value);
1951        }
1952
1953        Ok(values)
1954    }
1955
1956    pub(crate) fn translate_exn_throw(
1957        &mut self,
1958        builder: &mut FunctionBuilder,
1959        tag_index: TagIndex,
1960        args: &[ir::Value],
1961        landing_pad: Option<LandingPad>,
1962    ) -> WasmResult<()> {
1963        let layout = self.exception_type_layout(tag_index)?.clone();
1964        if layout.fields.len() != args.len() {
1965            return Err(WasmError::Generic(format!(
1966                "exception payload arity mismatch: expected {}, got {}",
1967                layout.fields.len(),
1968                args.len()
1969            )));
1970        }
1971
1972        let (alloc_sig, alloc_idx) = self.get_alloc_exception_func(builder.func);
1973        let mut pos = builder.cursor();
1974        let (vmctx, alloc_addr) =
1975            self.translate_load_builtin_function_address(&mut pos, alloc_idx)?;
1976        let tag_value = builder
1977            .ins()
1978            .iconst(TAG_TYPE, i64::from(tag_index.as_u32()));
1979        let alloc_call = builder
1980            .ins()
1981            .call_indirect(alloc_sig, alloc_addr, &[vmctx, tag_value]);
1982        let exnref = builder.inst_results(alloc_call)[0];
1983
1984        let (read_exnref_sig, read_exnref_idx) = self.get_read_exnref_func(builder.func);
1985        let mut pos = builder.cursor();
1986        let (vmctx, read_exnref_addr) =
1987            self.translate_load_builtin_function_address(&mut pos, read_exnref_idx)?;
1988        let read_exnref_call =
1989            builder
1990                .ins()
1991                .call_indirect(read_exnref_sig, read_exnref_addr, &[vmctx, exnref]);
1992        let payload_ptr = builder.inst_results(read_exnref_call)[0];
1993
1994        let store_flags = ir::MemFlagsData::trusted();
1995        for (field, value) in layout.fields.iter().zip(args.iter()) {
1996            debug_assert_eq!(
1997                builder.func.dfg.value_type(*value),
1998                field.ty,
1999                "exception payload type mismatch"
2000            );
2001            builder.ins().store(
2002                store_flags,
2003                *value,
2004                payload_ptr,
2005                Offset32::new(field.offset as i32),
2006            );
2007        }
2008
2009        let (throw_sig, throw_idx) = self.get_throw_func(builder.func);
2010        let mut pos = builder.cursor();
2011        let (vmctx_value, throw_addr) =
2012            self.translate_load_builtin_function_address(&mut pos, throw_idx)?;
2013        let call_args = [vmctx_value, exnref];
2014
2015        let _ = self.call_indirect_with_handlers(
2016            builder,
2017            throw_sig,
2018            throw_addr,
2019            &call_args,
2020            Some(vmctx_value),
2021            landing_pad,
2022            true,
2023        );
2024
2025        Ok(())
2026    }
2027
2028    pub(crate) fn translate_exn_throw_ref(
2029        &mut self,
2030        builder: &mut FunctionBuilder,
2031        exnref: ir::Value,
2032        landing_pad: Option<LandingPad>,
2033    ) -> WasmResult<()> {
2034        let (throw_sig, throw_idx) = self.get_throw_func(builder.func);
2035        let mut pos = builder.cursor();
2036        let (vmctx_value, throw_addr) =
2037            self.translate_load_builtin_function_address(&mut pos, throw_idx)?;
2038        let call_args = [vmctx_value, exnref];
2039
2040        let _ = self.call_indirect_with_handlers(
2041            builder,
2042            throw_sig,
2043            throw_addr,
2044            &call_args,
2045            Some(vmctx_value),
2046            landing_pad,
2047            true,
2048        );
2049
2050        Ok(())
2051    }
2052
2053    pub(crate) fn translate_exn_personality_selector(
2054        &mut self,
2055        builder: &mut FunctionBuilder,
2056        exn_ptr: ir::Value,
2057    ) -> WasmResult<ir::Value> {
2058        let (sig, idx) = self.get_personality2_func(builder.func);
2059        let pointer_type = self.pointer_type();
2060        let exn_ty = builder.func.dfg.value_type(exn_ptr);
2061        let exn_arg = if exn_ty == pointer_type {
2062            exn_ptr
2063        } else {
2064            let mut flags = MemFlagsData::new();
2065            flags.set_endianness(Endianness::Little);
2066            builder.ins().bitcast(pointer_type, flags, exn_ptr)
2067        };
2068
2069        let mut pos = builder.cursor();
2070        let (vmctx_value, func_addr) =
2071            self.translate_load_builtin_function_address(&mut pos, idx)?;
2072        let call = builder
2073            .ins()
2074            .call_indirect(sig, func_addr, &[vmctx_value, exn_arg]);
2075        Ok(builder.inst_results(call)[0])
2076    }
2077
2078    pub(crate) fn translate_exn_reraise_unmatched(
2079        &mut self,
2080        builder: &mut FunctionBuilder,
2081        exnref: ir::Value,
2082    ) -> WasmResult<()> {
2083        let (throw_sig, throw_idx) = self.get_throw_func(builder.func);
2084        let mut pos = builder.cursor();
2085        let (vmctx_value, throw_addr) =
2086            self.translate_load_builtin_function_address(&mut pos, throw_idx)?;
2087        builder
2088            .ins()
2089            .call_indirect(throw_sig, throw_addr, &[vmctx_value, exnref]);
2090        builder.ins().trap(crate::TRAP_UNREACHABLE);
2091        Ok(())
2092    }
2093
2094    pub(crate) fn translate_memory_grow(
2095        &mut self,
2096        mut pos: FuncCursor<'_>,
2097        index: MemoryIndex,
2098        _heap: Heap,
2099        val: ir::Value,
2100    ) -> WasmResult<ir::Value> {
2101        let (func_sig, index_arg, func_idx) = self.get_memory_grow_func(pos.func, index);
2102        let memory_index = pos.ins().iconst(I32, index_arg as i64);
2103        let (vmctx, func_addr) =
2104            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2105        let call_inst = pos
2106            .ins()
2107            .call_indirect(func_sig, func_addr, &[vmctx, val, memory_index]);
2108        Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
2109    }
2110
2111    pub(crate) fn translate_memory_size(
2112        &mut self,
2113        mut pos: FuncCursor<'_>,
2114        index: MemoryIndex,
2115        _heap: Heap,
2116    ) -> WasmResult<ir::Value> {
2117        let (func_sig, index_arg, func_idx) = self.get_memory_size_func(pos.func, index);
2118        let memory_index = pos.ins().iconst(I32, index_arg as i64);
2119        let (vmctx, func_addr) =
2120            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2121        let call_inst = pos
2122            .ins()
2123            .call_indirect(func_sig, func_addr, &[vmctx, memory_index]);
2124        Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
2125    }
2126
2127    #[allow(clippy::too_many_arguments)]
2128    pub(crate) fn translate_memory_copy(
2129        &mut self,
2130        mut pos: FuncCursor,
2131        src_index: MemoryIndex,
2132        _src_heap: Heap,
2133        dst_index: MemoryIndex,
2134        _dst_heap: Heap,
2135        dst: ir::Value,
2136        src: ir::Value,
2137        len: ir::Value,
2138    ) -> WasmResult<()> {
2139        let (func_sig, func_idx) = self.get_memory_copy_func(pos.func);
2140
2141        let dst_index_arg = pos.ins().iconst(I32, dst_index.index() as i64);
2142        let src_index_arg = pos.ins().iconst(I32, src_index.index() as i64);
2143
2144        let (vmctx, func_addr) =
2145            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2146
2147        pos.ins().call_indirect(
2148            func_sig,
2149            func_addr,
2150            &[vmctx, dst_index_arg, src_index_arg, dst, src, len],
2151        );
2152
2153        Ok(())
2154    }
2155
2156    pub(crate) fn translate_memory_fill(
2157        &mut self,
2158        mut pos: FuncCursor,
2159        memory_index: MemoryIndex,
2160        _heap: Heap,
2161        dst: ir::Value,
2162        val: ir::Value,
2163        len: ir::Value,
2164    ) -> WasmResult<()> {
2165        let (func_sig, memory_index, func_idx) = self.get_memory_fill_func(pos.func, memory_index);
2166
2167        let memory_index_arg = pos.ins().iconst(I32, memory_index as i64);
2168
2169        let (vmctx, func_addr) =
2170            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2171
2172        pos.ins().call_indirect(
2173            func_sig,
2174            func_addr,
2175            &[vmctx, memory_index_arg, dst, val, len],
2176        );
2177
2178        Ok(())
2179    }
2180
2181    #[allow(clippy::too_many_arguments)]
2182    pub(crate) fn translate_memory_init(
2183        &mut self,
2184        mut pos: FuncCursor,
2185        memory_index: MemoryIndex,
2186        _heap: Heap,
2187        seg_index: u32,
2188        dst: ir::Value,
2189        src: ir::Value,
2190        len: ir::Value,
2191    ) -> WasmResult<()> {
2192        let (func_sig, func_idx) = self.get_memory_init_func(pos.func);
2193
2194        let memory_index_arg = pos.ins().iconst(I32, memory_index.index() as i64);
2195        let seg_index_arg = pos.ins().iconst(I32, seg_index as i64);
2196
2197        let (vmctx, func_addr) =
2198            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2199
2200        pos.ins().call_indirect(
2201            func_sig,
2202            func_addr,
2203            &[vmctx, memory_index_arg, seg_index_arg, dst, src, len],
2204        );
2205
2206        Ok(())
2207    }
2208
2209    pub(crate) fn translate_data_drop(
2210        &mut self,
2211        mut pos: FuncCursor,
2212        seg_index: u32,
2213    ) -> WasmResult<()> {
2214        let (func_sig, func_idx) = self.get_data_drop_func(pos.func);
2215        let seg_index_arg = pos.ins().iconst(I32, seg_index as i64);
2216        let (vmctx, func_addr) =
2217            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2218        pos.ins()
2219            .call_indirect(func_sig, func_addr, &[vmctx, seg_index_arg]);
2220        Ok(())
2221    }
2222
2223    pub(crate) fn translate_table_size(
2224        &mut self,
2225        mut pos: FuncCursor,
2226        table_index: TableIndex,
2227    ) -> WasmResult<ir::Value> {
2228        self.ensure_table_exists(pos.func, table_index)?;
2229        let (func_sig, index_arg, func_idx) = self.get_table_size_func(pos.func, table_index);
2230        let table_index = pos.ins().iconst(I32, index_arg as i64);
2231        let (vmctx, func_addr) =
2232            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2233        let call_inst = pos
2234            .ins()
2235            .call_indirect(func_sig, func_addr, &[vmctx, table_index]);
2236        Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
2237    }
2238
2239    pub(crate) fn translate_table_copy(
2240        &mut self,
2241        mut pos: FuncCursor,
2242        dst_table_index: TableIndex,
2243        src_table_index: TableIndex,
2244        dst: ir::Value,
2245        src: ir::Value,
2246        len: ir::Value,
2247    ) -> WasmResult<()> {
2248        self.ensure_table_exists(pos.func, src_table_index)?;
2249        self.ensure_table_exists(pos.func, dst_table_index)?;
2250        let (func_sig, dst_table_index_arg, src_table_index_arg, func_idx) =
2251            self.get_table_copy_func(pos.func, dst_table_index, src_table_index);
2252
2253        let dst_table_index_arg = pos.ins().iconst(I32, dst_table_index_arg as i64);
2254        let src_table_index_arg = pos.ins().iconst(I32, src_table_index_arg as i64);
2255
2256        let (vmctx, func_addr) =
2257            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2258
2259        pos.ins().call_indirect(
2260            func_sig,
2261            func_addr,
2262            &[
2263                vmctx,
2264                dst_table_index_arg,
2265                src_table_index_arg,
2266                dst,
2267                src,
2268                len,
2269            ],
2270        );
2271
2272        Ok(())
2273    }
2274
2275    pub(crate) fn translate_table_init(
2276        &mut self,
2277        mut pos: FuncCursor,
2278        seg_index: u32,
2279        table_index: TableIndex,
2280        dst: ir::Value,
2281        src: ir::Value,
2282        len: ir::Value,
2283    ) -> WasmResult<()> {
2284        self.ensure_table_exists(pos.func, table_index)?;
2285        let (func_sig, table_index_arg, func_idx) = self.get_table_init_func(pos.func, table_index);
2286
2287        let table_index_arg = pos.ins().iconst(I32, table_index_arg as i64);
2288        let seg_index_arg = pos.ins().iconst(I32, seg_index as i64);
2289
2290        let (vmctx, func_addr) =
2291            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2292
2293        pos.ins().call_indirect(
2294            func_sig,
2295            func_addr,
2296            &[vmctx, table_index_arg, seg_index_arg, dst, src, len],
2297        );
2298
2299        Ok(())
2300    }
2301
2302    pub(crate) fn translate_elem_drop(
2303        &mut self,
2304        mut pos: FuncCursor,
2305        elem_index: u32,
2306    ) -> WasmResult<()> {
2307        let (func_sig, func_idx) = self.get_elem_drop_func(pos.func);
2308
2309        let elem_index_arg = pos.ins().iconst(I32, elem_index as i64);
2310
2311        let (vmctx, func_addr) =
2312            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2313
2314        pos.ins()
2315            .call_indirect(func_sig, func_addr, &[vmctx, elem_index_arg]);
2316
2317        Ok(())
2318    }
2319
2320    pub(crate) fn translate_atomic_wait(
2321        &mut self,
2322        mut pos: FuncCursor,
2323        index: MemoryIndex,
2324        _heap: Heap,
2325        addr: ir::Value,
2326        expected: ir::Value,
2327        timeout: ir::Value,
2328    ) -> WasmResult<ir::Value> {
2329        let (func_sig, index_arg, func_idx) = if pos.func.dfg.value_type(expected) == I64 {
2330            self.get_memory_atomic_wait64_func(pos.func, index)
2331        } else {
2332            self.get_memory_atomic_wait32_func(pos.func, index)
2333        };
2334        let memory_index = pos.ins().iconst(I32, index_arg as i64);
2335        let (vmctx, func_addr) =
2336            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2337        let call_inst = pos.ins().call_indirect(
2338            func_sig,
2339            func_addr,
2340            &[vmctx, memory_index, addr, expected, timeout],
2341        );
2342        Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
2343    }
2344
2345    pub(crate) fn translate_atomic_notify(
2346        &mut self,
2347        mut pos: FuncCursor,
2348        index: MemoryIndex,
2349        _heap: Heap,
2350        addr: ir::Value,
2351        count: ir::Value,
2352    ) -> WasmResult<ir::Value> {
2353        let (func_sig, index_arg, func_idx) = self.get_memory_atomic_notify_func(pos.func, index);
2354        let memory_index = pos.ins().iconst(I32, index_arg as i64);
2355        let (vmctx, func_addr) =
2356            self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2357        let call_inst =
2358            pos.ins()
2359                .call_indirect(func_sig, func_addr, &[vmctx, memory_index, addr, count]);
2360        Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
2361    }
2362
2363    pub(crate) fn push_local_decl_on_stack(&mut self, ty: WasmerType) {
2364        self.type_stack.push(ty);
2365    }
2366
2367    pub(crate) fn push_params_on_stack(&mut self, function_index: LocalFunctionIndex) {
2368        let func_index = self.module.func_index(function_index);
2369        let sig_idx = self.module.functions[func_index];
2370        let signature = &self.module.signatures[sig_idx];
2371        self.return_types = signature.results().to_vec();
2372        for param in signature.params() {
2373            self.type_stack.push(*param);
2374        }
2375    }
2376
2377    pub(crate) fn return_types(&self) -> &[WasmerType] {
2378        &self.return_types
2379    }
2380
2381    pub(crate) fn emit_wasm_return(&mut self, builder: &mut FunctionBuilder, values: &[ir::Value]) {
2382        let return_abi = abi::classify_returns(self.architecture, &self.return_types);
2383        match &return_abi {
2384            ReturnAbi::Sret(types) => {
2385                let ptr = builder
2386                    .func
2387                    .special_param(ArgumentPurpose::StructReturn)
2388                    .expect("sret function has a StructReturn parameter");
2389                let layout = abi::return_area_layout(types);
2390                abi::store_sret(builder, ptr, &layout, values);
2391                builder.ins().return_(&[]);
2392            }
2393            _ => {
2394                let packed = abi::pack_register_returns(builder, &return_abi, values);
2395                builder.ins().return_(&packed);
2396            }
2397        }
2398    }
2399
2400    pub(crate) fn heap_access_spectre_mitigation(&self) -> bool {
2401        false
2402    }
2403
2404    pub(crate) fn heaps(&self) -> &PrimaryMap<Heap, HeapData> {
2405        &self.heaps
2406    }
2407}