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