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