Skip to main content

wasmtime_environ/compile/
module_environ.rs

1use crate::error::{OutOfMemory, Result, bail};
2use crate::module::{
3    FuncRefIndex, Initializer, MemoryInitialization, Module, TableSegment, TableSegmentElements,
4};
5use crate::prelude::*;
6use crate::{
7    ConstExpr, ConstOp, DataIndex, DefinedFuncIndex, DefinedGlobalIndex, ElemIndex,
8    EngineOrModuleTypeIndex, EntityIndex, EntityType, FuncIndex, FuncKey, GlobalIndex, IndexType,
9    MemoryIndex, MemoryInitializer, ModuleInternedTypeIndex, ModuleStartup, ModuleTypesBuilder,
10    PanicOnOom as _, PassiveElemIndex, PrimaryMap, RuntimeDataIndex, StaticModuleIndex, TableIndex,
11    TableInitialValue, TableInitialization, Tag, TagIndex, Trap, Tunables, TypeConvert, TypeIndex,
12    WasmHeapTopType, WasmHeapType, WasmResult, WasmValType, WasmparserTypeConverter,
13};
14use alloc::borrow::Cow;
15use cranelift_entity::SecondaryMap;
16use cranelift_entity::packed_option::ReservedValue;
17use std::collections::HashMap;
18use std::mem;
19use std::path::PathBuf;
20use std::sync::Arc;
21use wasmparser::{
22    CustomSectionReader, DataKind, ElementItems, ElementKind, Encoding, ExternalKind,
23    FuncToValidate, FunctionBody, KnownCustom, NameSectionReader, Naming, Parser, Payload, TypeRef,
24    Validator, ValidatorResources, types::Types,
25};
26
27/// Object containing the standalone environment information.
28pub struct ModuleEnvironment<'a, 'data> {
29    /// The current module being translated
30    result: ModuleTranslation<'data>,
31
32    /// Intern'd types for this entire translation, shared by all modules.
33    types: &'a mut ModuleTypesBuilder,
34
35    // Various bits and pieces of configuration
36    validator: &'a mut Validator,
37    tunables: &'a Tunables,
38}
39
40/// Identifies a FACT adapter-module import that the compiler lowers inline when
41/// translating the adapter function.
42#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
43pub enum FactInlineIntrinsic {
44    /// `enter-sync-call`: push a deferred component-model thread inline.
45    EnterSyncCall,
46    /// `exit-sync-call`: pop the deferred thread inline on the fast path, or
47    /// fall back to the out-of-line `exit-sync-call` libcall when the thread
48    /// was promoted.
49    ExitSyncCall,
50    /// `trap`: raise the given trap.
51    Trap(Trap),
52}
53
54/// A statically-known function import.
55#[derive(Clone, Debug)]
56pub enum KnownFunc {
57    /// A function described by the given key.
58    FuncKey(FuncKey),
59    /// An always-inlined FACT intrinsic.
60    FactIntrinsic(FactInlineIntrinsic),
61}
62
63impl From<FuncKey> for KnownFunc {
64    fn from(key: FuncKey) -> Self {
65        Self::FuncKey(key)
66    }
67}
68
69impl From<FactInlineIntrinsic> for KnownFunc {
70    fn from(intrinsic: FactInlineIntrinsic) -> Self {
71        Self::FactIntrinsic(intrinsic)
72    }
73}
74
75/// The result of translating via `ModuleEnvironment`.
76///
77/// Function bodies are not yet translated, and data initializers have not yet
78/// been copied out of the original buffer.
79pub struct ModuleTranslation<'data> {
80    /// Module information.
81    pub module: Module,
82
83    /// The input wasm binary.
84    ///
85    /// This can be useful, for example, when modules are parsed from a
86    /// component and the embedder wants access to the raw wasm modules
87    /// themselves.
88    pub wasm: &'data [u8],
89
90    /// The byte offset of this module's Wasm binary within the outer
91    /// binary (e.g. a component). For standalone modules this is 0.
92    /// This is used to convert component-relative source locations to
93    /// module-relative source locations.
94    pub wasm_module_offset: u64,
95
96    /// References to the function bodies.
97    pub function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
98
99    /// For each imported function, the single statically-known function that
100    /// always satisfies that import, if any.
101    ///
102    /// This is used to turn what would otherwise be indirect calls through the
103    /// imports table into direct calls, when possible.
104    ///
105    /// When filled in, this only ever contains
106    /// `FuncKey::DefinedWasmFunction(..)`s, `FuncKey::Intrinsic(..)`s, and
107    /// `FuncKey::FactInlineIntrinsic`s.
108    pub known_imported_functions: SecondaryMap<FuncIndex, Option<KnownFunc>>,
109
110    /// A list of type signatures which are considered exported from this
111    /// module, or those that can possibly be called. This list is sorted, and
112    /// trampolines for each of these signatures are required.
113    pub exported_signatures: Vec<ModuleInternedTypeIndex>,
114
115    /// DWARF debug information, if enabled, parsed from the module.
116    pub debuginfo: DebugInfoData<'data>,
117
118    /// Set if debuginfo was found but it was not parsed due to `Tunables`
119    /// configuration.
120    pub has_unparsed_debuginfo: bool,
121
122    /// The desired alignment of `data` in the final data section of the object
123    /// file that we'll emit.
124    ///
125    /// Note that this is 1 by default but `MemoryInitialization::Static` might
126    /// switch this to a higher alignment to facilitate mmap-ing data from
127    /// an object file into a linear memory.
128    pub data_align: Option<u64>,
129
130    /// Map from a data segment to whether it's a passive data segment or not.
131    pub runtime_data_map: SecondaryMap<DataIndex, Option<RuntimeDataIndex>>,
132
133    /// Map from an elem segment to whether it's a passive elem segment or not.
134    pub passive_elem_map: SecondaryMap<ElemIndex, Option<PassiveElemIndex>>,
135
136    /// List of passive element segments found in this module which will get
137    /// concatenated for the final artifact.
138    pub runtime_data: PrimaryMap<RuntimeDataIndex, Cow<'data, [u8]>>,
139
140    /// Record of all passive data segments that this module contains.
141    ///
142    /// These are processed during [`ModuleTranslation::finalize_memory_init`]
143    /// and eventually moved over into the `runtime_data` list above. Until
144    /// then, however, their `RuntimeDataIndex` is not yet assigned.
145    passive_data: Vec<(DataIndex, &'data [u8])>,
146
147    /// When we're parsing the code section this will be incremented so we know
148    /// which function is currently being defined.
149    code_index: u32,
150
151    /// The type information of the current module made available at the end of the
152    /// validation process.
153    types: Option<Types>,
154
155    /// Per-function [`BranchHintReader`]s from the `metadata.code.branch_hint`
156    /// section, keyed by function index. Populated only when
157    /// [`Tunables::branch_hinting`] is enabled.
158    branch_hints: HashMap<FuncIndex, BranchHintReader<'data>>,
159
160    /// The WebAssembly `start` function, if defined.
161    pub start_func: Option<FuncIndex>,
162
163    /// Initializers for `global` values which aren't considered "simple".
164    ///
165    /// These initializers are later compiled into a "module startup" function.
166    pub global_initializers: Vec<(DefinedGlobalIndex, ConstExpr)>,
167
168    /// Definitions of all passive elements found within a module.
169    ///
170    /// This maps passive element segments to their definition, either functions
171    /// or expressions-basd.
172    pub passive_elements: PrimaryMap<PassiveElemIndex, TableSegmentElements>,
173
174    /// WebAssembly table initialization data, per table.
175    ///
176    /// This keeps track of all per-table initialization (e.g. initial value for
177    /// non-null tables) as well as active element segments. This is processed
178    /// and refined by [`ModuleTranslation::finalize_table_init`] after
179    /// translation.
180    pub table_initialization: TableInitialization,
181
182    /// WebAssembly memory initialization.
183    ///
184    /// This is held here in an `Unprocessed` form during translation, and then
185    /// this is later finished with [`ModuleTranslation::finalize_memory_init`].
186    pub memory_init: MemoryInit<'data>,
187}
188
189/// Different forms of memory initialization that happens for a module.
190pub enum MemoryInit<'a> {
191    /// Raw active data segments that are being applied for an instance.
192    ///
193    /// This list contains the raw data  which hasn't yet been processed into
194    /// `RuntimeDataIndex`, for example. This is later processed during
195    /// [`ModuleTranslation::finalize_memory_init`] to optionally shuffle things
196    /// around.
197    Unprocessed(Vec<MemoryInitializer<'a>>),
198
199    /// Finalized memory initialization to be executed after
200    /// [`ModuleTranslation::finalize_memory_init`] has run. This represents
201    /// active data segments which may have been merged from the `Unprocessed`
202    /// list above, and may or may not have statically know offsets.
203    Processed(Vec<(MemoryIndex, MemorySegmentOffset, RuntimeDataIndex)>),
204}
205
206/// Offset within [`MemoryInit::Processed`] which indicates the initial offset
207/// a data segment is applied at.
208pub enum MemorySegmentOffset {
209    /// A "complicated" constant expression deferred to get evaluated at runtime
210    /// with compiled code.
211    Expr(ConstExpr),
212
213    /// A statically known, in-bounds, constant value.
214    Static(u64),
215}
216
217/// Lazy decoder over the branch hints attached to a single function in the
218/// `metadata.code.branch_hint` custom section
219/// ([branch-hinting proposal](https://github.com/WebAssembly/branch-hinting)).
220pub type BranchHintReader<'a> = wasmparser::SectionLimited<'a, wasmparser::BranchHint>;
221
222impl<'data> ModuleTranslation<'data> {
223    /// Create a new translation for the module with the given index.
224    pub fn new(module_index: StaticModuleIndex) -> Self {
225        Self {
226            module: Module::new(module_index),
227            wasm: &[],
228            wasm_module_offset: 0,
229            function_body_inputs: PrimaryMap::default(),
230            known_imported_functions: SecondaryMap::default(),
231            exported_signatures: Vec::default(),
232            debuginfo: DebugInfoData::default(),
233            has_unparsed_debuginfo: false,
234            data_align: None,
235            runtime_data: Default::default(),
236            code_index: 0,
237            types: None,
238            runtime_data_map: Default::default(),
239            passive_elem_map: Default::default(),
240            branch_hints: HashMap::default(),
241            start_func: None,
242            global_initializers: Vec::new(),
243            passive_elements: Default::default(),
244            table_initialization: Default::default(),
245            memory_init: MemoryInit::Unprocessed(Vec::new()),
246            passive_data: Default::default(),
247        }
248    }
249
250    /// Returns the [`BranchHintReader`] for `func`, if the section attached any.
251    pub fn branch_hints(&self, func: FuncIndex) -> Option<BranchHintReader<'data>> {
252        self.branch_hints.get(&func).cloned()
253    }
254
255    /// Returns a reference to the type information of the current module.
256    pub fn get_types(&self) -> &Types {
257        self.types
258            .as_ref()
259            .expect("module type information to be available")
260    }
261
262    /// Get this translation's module's index.
263    pub fn module_index(&self) -> StaticModuleIndex {
264        self.module.module_index
265    }
266}
267
268/// Contains function data: byte code and its offset in the module.
269pub struct FunctionBodyData<'a> {
270    /// The body of the function, containing code and locals.
271    pub body: FunctionBody<'a>,
272    /// Validator for the function body
273    pub validator: FuncToValidate<ValidatorResources>,
274}
275
276#[derive(Debug, Default)]
277#[expect(missing_docs, reason = "self-describing fields")]
278pub struct DebugInfoData<'a> {
279    pub dwarf: Dwarf<'a>,
280    pub name_section: NameSection<'a>,
281    pub wasm_file: WasmFileInfo,
282    pub debug_loc: gimli::DebugLoc<Reader<'a>>,
283    pub debug_loclists: gimli::DebugLocLists<Reader<'a>>,
284    pub debug_ranges: gimli::DebugRanges<Reader<'a>>,
285    pub debug_rnglists: gimli::DebugRngLists<Reader<'a>>,
286    pub debug_cu_index: gimli::DebugCuIndex<Reader<'a>>,
287    pub debug_tu_index: gimli::DebugTuIndex<Reader<'a>>,
288}
289
290#[expect(missing_docs, reason = "self-describing")]
291pub type Dwarf<'input> = gimli::Dwarf<Reader<'input>>;
292
293type Reader<'input> = gimli::EndianSlice<'input, gimli::LittleEndian>;
294
295#[derive(Debug, Default)]
296#[expect(missing_docs, reason = "self-describing fields")]
297pub struct NameSection<'a> {
298    pub module_name: Option<&'a str>,
299    pub func_names: HashMap<FuncIndex, &'a str>,
300    pub locals_names: HashMap<FuncIndex, HashMap<u32, &'a str>>,
301}
302
303#[derive(Debug, Default)]
304#[expect(missing_docs, reason = "self-describing fields")]
305pub struct WasmFileInfo {
306    pub path: Option<PathBuf>,
307    pub code_section_offset: u64,
308    pub imported_func_count: u32,
309    pub funcs: Vec<FunctionMetadata>,
310}
311
312#[derive(Debug)]
313#[expect(missing_docs, reason = "self-describing fields")]
314pub struct FunctionMetadata {
315    pub params: Box<[WasmValType]>,
316    pub locals: Box<[(u32, WasmValType)]>,
317}
318
319impl<'a, 'data> ModuleEnvironment<'a, 'data> {
320    /// Allocates the environment data structures.
321    pub fn new(
322        tunables: &'a Tunables,
323        validator: &'a mut Validator,
324        types: &'a mut ModuleTypesBuilder,
325        module_index: StaticModuleIndex,
326    ) -> Self {
327        Self {
328            result: ModuleTranslation::new(module_index),
329            types,
330            tunables,
331            validator,
332        }
333    }
334
335    /// Translate a wasm module using this environment.
336    ///
337    /// This function will translate the `data` provided with `parser`,
338    /// validating everything along the way with this environment's validator.
339    ///
340    /// The result of translation, [`ModuleTranslation`], contains everything
341    /// necessary to compile functions afterwards as well as learn type
342    /// information about the module at runtime.
343    pub fn translate(
344        mut self,
345        parser: Parser,
346        data: &'data [u8],
347    ) -> Result<ModuleTranslation<'data>> {
348        self.result.wasm = data;
349
350        for payload in parser.parse_all(data) {
351            self.translate_payload(payload?)?;
352        }
353
354        Ok(self.result)
355    }
356
357    fn translate_payload(&mut self, payload: Payload<'data>) -> Result<()> {
358        match payload {
359            Payload::Version {
360                num,
361                encoding,
362                range,
363            } => {
364                self.validator.version(num, encoding, &range)?;
365                match encoding {
366                    Encoding::Module => {}
367                    Encoding::Component => {
368                        bail!("expected a WebAssembly module but was given a WebAssembly component")
369                    }
370                }
371            }
372
373            Payload::End(offset) => {
374                self.result.types = Some(self.validator.end(offset)?);
375
376                // With the `escaped_funcs` set of functions finished
377                // we can calculate the set of signatures that are exported as
378                // the set of exported functions' signatures.
379                self.result.exported_signatures = self
380                    .result
381                    .module
382                    .functions
383                    .iter()
384                    .filter_map(|(_, func)| {
385                        if func.is_escaping() {
386                            Some(func.signature.unwrap_module_type_index())
387                        } else {
388                            None
389                        }
390                    })
391                    .collect();
392                self.result.exported_signatures.sort_unstable();
393                self.result.exported_signatures.dedup();
394            }
395
396            Payload::TypeSection(types) => {
397                self.validator.type_section(&types)?;
398
399                let count = self.validator.types(0).unwrap().core_type_count_in_module();
400                log::trace!("interning {count} Wasm types");
401
402                let capacity = usize::try_from(count).unwrap();
403                self.result.module.types.reserve(capacity)?;
404                self.types.reserve_wasm_signatures(capacity);
405
406                // Iterate over each *rec group* -- not type -- defined in the
407                // types section. Rec groups are the unit of canonicalization
408                // and therefore the unit at which we need to process at a
409                // time. `wasmparser` has already done the hard work of
410                // de-duplicating and canonicalizing the rec groups within the
411                // module for us, we just need to translate them into our data
412                // structures. Note that, if the Wasm defines duplicate rec
413                // groups, we need copy the duplicates over (shallowly) as well,
414                // so that our types index space doesn't have holes.
415                let mut type_index = 0;
416                while type_index < count {
417                    let validator_types = self.validator.types(0).unwrap();
418
419                    // Get the rec group for the current type index, which is
420                    // always the first type defined in a rec group.
421                    log::trace!("looking up wasmparser type for index {type_index}");
422                    let core_type_id = validator_types.core_type_at_in_module(type_index);
423                    log::trace!(
424                        "  --> {core_type_id:?} = {:?}",
425                        validator_types[core_type_id],
426                    );
427                    let rec_group_id = validator_types.rec_group_id_of(core_type_id);
428                    debug_assert_eq!(
429                        validator_types
430                            .rec_group_elements(rec_group_id)
431                            .position(|id| id == core_type_id),
432                        Some(0)
433                    );
434
435                    // Intern the rec group and then fill in this module's types
436                    // index space.
437                    let interned = self.types.intern_rec_group(validator_types, rec_group_id)?;
438                    let elems = self.types.rec_group_elements(interned);
439                    let len = elems.len();
440                    self.result.module.types.reserve(len)?;
441                    for ty in elems {
442                        self.result.module.types.push(ty.into())?;
443                    }
444
445                    // Advance `type_index` to the start of the next rec group.
446                    type_index += u32::try_from(len).unwrap();
447                }
448            }
449
450            Payload::ImportSection(imports) => {
451                self.validator.import_section(&imports)?;
452
453                let cnt = usize::try_from(imports.count()).unwrap();
454                self.result.module.initializers.reserve(cnt)?;
455
456                for entry in imports.into_imports() {
457                    let import = entry?;
458                    let ty = match import.ty {
459                        TypeRef::Func(index) => {
460                            let index = TypeIndex::from_u32(index);
461                            let interned_index = self.result.module.types[index];
462                            self.result.module.num_imported_funcs += 1;
463                            self.result.debuginfo.wasm_file.imported_func_count += 1;
464                            EntityType::Function(interned_index)
465                        }
466                        TypeRef::Memory(ty) => {
467                            self.result.module.num_imported_memories += 1;
468                            EntityType::Memory(ty.into())
469                        }
470                        TypeRef::Global(ty) => {
471                            self.result.module.num_imported_globals += 1;
472                            EntityType::Global(self.convert_global_type(&ty)?)
473                        }
474                        TypeRef::Table(ty) => {
475                            self.result.module.num_imported_tables += 1;
476                            EntityType::Table(self.convert_table_type(&ty)?)
477                        }
478                        TypeRef::Tag(ty) => {
479                            let index = TypeIndex::from_u32(ty.func_type_idx);
480                            let signature = self.result.module.types[index];
481                            let exception = self.types.define_exception_type_for_tag(
482                                signature.unwrap_module_type_index(),
483                            );
484                            let tag = Tag {
485                                signature,
486                                exception: EngineOrModuleTypeIndex::Module(exception),
487                            };
488                            self.result.module.num_imported_tags += 1;
489                            EntityType::Tag(tag)
490                        }
491                        TypeRef::FuncExact(_) => {
492                            bail!("custom-descriptors proposal not implemented yet");
493                        }
494                    };
495                    self.declare_import(import.module, import.name, ty)?;
496                }
497            }
498
499            Payload::FunctionSection(functions) => {
500                self.validator.function_section(&functions)?;
501
502                let cnt = usize::try_from(functions.count()).unwrap();
503                self.result.module.functions.reserve_exact(cnt)?;
504
505                for entry in functions {
506                    let sigindex = entry?;
507                    let ty = TypeIndex::from_u32(sigindex);
508                    let interned_index = self.result.module.types[ty];
509                    self.result.module.push_function(interned_index);
510                }
511            }
512
513            Payload::TableSection(tables) => {
514                self.validator.table_section(&tables)?;
515                let cnt = usize::try_from(tables.count()).unwrap();
516                self.result.module.tables.reserve_exact(cnt)?;
517
518                for entry in tables {
519                    let wasmparser::Table { ty, init } = entry?;
520                    let table = self.convert_table_type(&ty)?;
521                    self.result.module.needs_gc_heap |= table.ref_type.is_vmgcref_type();
522                    self.result.module.tables.push(table)?;
523                    let init = match init {
524                        wasmparser::TableInit::RefNull => TableInitialValue::Null,
525                        wasmparser::TableInit::Expr(expr) => {
526                            let (init, escaped) = ConstExpr::from_wasmparser(self, expr)?;
527                            for f in escaped {
528                                self.flag_func_escaped(f);
529                            }
530                            TableInitialValue::Expr(init)
531                        }
532                    };
533                    self.result.table_initialization.initial_values.push(init)?;
534                    self.result
535                        .module
536                        .table_initialization
537                        .push(Default::default())?;
538                }
539            }
540
541            Payload::MemorySection(memories) => {
542                self.validator.memory_section(&memories)?;
543
544                let cnt = usize::try_from(memories.count()).unwrap();
545                self.result.module.memories.reserve_exact(cnt)?;
546
547                for entry in memories {
548                    let memory = entry?;
549                    self.result.module.memories.push(memory.into())?;
550                }
551            }
552
553            Payload::TagSection(tags) => {
554                self.validator.tag_section(&tags)?;
555
556                for entry in tags {
557                    let sigindex = entry?.func_type_idx;
558                    let ty = TypeIndex::from_u32(sigindex);
559                    let interned_index = self.result.module.types[ty];
560                    let exception = self
561                        .types
562                        .define_exception_type_for_tag(interned_index.unwrap_module_type_index());
563                    self.result.module.push_tag(interned_index, exception);
564                }
565            }
566
567            Payload::GlobalSection(globals) => {
568                self.validator.global_section(&globals)?;
569
570                let cnt = usize::try_from(globals.count()).unwrap();
571                self.result.module.globals.reserve_exact(cnt)?;
572
573                for entry in globals {
574                    let wasmparser::Global { ty, init_expr } = entry?;
575                    let (initializer, escaped) = ConstExpr::from_wasmparser(self, init_expr)?;
576                    for f in escaped {
577                        self.flag_func_escaped(f);
578                    }
579                    let ty = self.convert_global_type(&ty)?;
580                    let index = self.result.module.globals.push(ty)?;
581                    let defined_index = self.result.module.defined_global_index(index).unwrap();
582                    match initializer.const_eval() {
583                        Some(val) => {
584                            self.result
585                                .module
586                                .global_initializers
587                                .push((defined_index, val))?;
588                        }
589                        None => {
590                            // "Complicated" global initializers are deferred
591                            // to get evaluated in the startup function.
592                            self.require_startup_func();
593                            self.result
594                                .global_initializers
595                                .push((defined_index, initializer));
596                        }
597                    }
598                }
599            }
600
601            Payload::ExportSection(exports) => {
602                self.validator.export_section(&exports)?;
603
604                let cnt = usize::try_from(exports.count()).unwrap();
605                self.result.module.exports.reserve(cnt)?;
606
607                for entry in exports {
608                    let wasmparser::Export { name, kind, index } = entry?;
609                    let entity = match kind {
610                        ExternalKind::Func | ExternalKind::FuncExact => {
611                            let index = FuncIndex::from_u32(index);
612                            self.flag_func_escaped(index);
613                            EntityIndex::Function(index)
614                        }
615                        ExternalKind::Table => EntityIndex::Table(TableIndex::from_u32(index)),
616                        ExternalKind::Memory => EntityIndex::Memory(MemoryIndex::from_u32(index)),
617                        ExternalKind::Global => EntityIndex::Global(GlobalIndex::from_u32(index)),
618                        ExternalKind::Tag => EntityIndex::Tag(TagIndex::from_u32(index)),
619                    };
620                    let name = self.result.module.strings.insert(name)?;
621                    self.result.module.exports.insert(name, entity)?;
622                }
623            }
624
625            Payload::StartSection { func, range } => {
626                self.validator.start_section(func, &range)?;
627
628                let func_index = FuncIndex::from_u32(func);
629                debug_assert!(self.result.start_func.is_none());
630                self.result.start_func = Some(func_index);
631
632                // To make startup a bit easier, invoking the `start` function
633                // is a responsibility deferred to the startup function.
634                self.require_startup_func();
635            }
636
637            Payload::ElementSection(elements) => {
638                self.validator.element_section(&elements)?;
639
640                for (index, entry) in elements.into_iter().enumerate() {
641                    let wasmparser::Element {
642                        kind,
643                        items,
644                        range: _,
645                    } = entry?;
646
647                    // Build up a list of `FuncIndex` corresponding to all the
648                    // entries listed in this segment. Note that it's not
649                    // possible to create anything other than a `ref.null
650                    // extern` for externref segments, so those just get
651                    // translated to the reserved value of `FuncIndex`.
652                    let elements = match items {
653                        ElementItems::Functions(funcs) => {
654                            let mut elems =
655                                Vec::with_capacity(usize::try_from(funcs.count()).unwrap());
656                            for func in funcs {
657                                let func = FuncIndex::from_u32(func?);
658                                self.flag_func_escaped(func);
659                                elems.push(func);
660                            }
661                            TableSegmentElements::Functions(elems.into())
662                        }
663                        ElementItems::Expressions(ty, items) => {
664                            let ty = self.convert_ref_type(ty)?;
665                            let mut exprs =
666                                Vec::with_capacity(usize::try_from(items.count()).unwrap());
667                            for expr in items {
668                                let (expr, escaped) = ConstExpr::from_wasmparser(self, expr?)?;
669                                exprs.push(expr);
670                                for func in escaped {
671                                    self.flag_func_escaped(func);
672                                }
673                            }
674                            TableSegmentElements::Expressions {
675                                ty,
676                                exprs: exprs.into(),
677                            }
678                        }
679                    };
680
681                    let passive_index = match kind {
682                        ElementKind::Active {
683                            table_index,
684                            offset_expr,
685                        } => {
686                            let table_index = TableIndex::from_u32(table_index.unwrap_or(0));
687                            let (offset, escaped) = ConstExpr::from_wasmparser(self, offset_expr)?;
688                            debug_assert!(escaped.is_empty());
689
690                            self.result
691                                .table_initialization
692                                .segments
693                                .push(TableSegment {
694                                    table_index,
695                                    offset,
696                                    elements,
697                                })?;
698                            None
699                        }
700
701                        ElementKind::Passive => {
702                            let passive_index = self
703                                .result
704                                .module
705                                .passive_elements
706                                .push((elements.ty(), elements.len()))?;
707                            self.result.passive_elements.push(elements);
708                            // One-time initialization of passive element
709                            // segments is deferred to the startup function.
710                            self.require_startup_func();
711                            Some(passive_index)
712                        }
713
714                        ElementKind::Declared => None,
715                    };
716                    let elem_index = ElemIndex::from_u32(index as u32);
717                    self.result
718                        .passive_elem_map
719                        .insert(elem_index, passive_index);
720                }
721            }
722
723            Payload::CodeSectionStart { count, range, .. } => {
724                self.validator.code_section_start(&range)?;
725                let cnt = usize::try_from(count).unwrap();
726                self.result.function_body_inputs.reserve_exact(cnt);
727                self.result.debuginfo.wasm_file.code_section_offset = range.start as u64;
728            }
729
730            Payload::CodeSectionEntry(body) => {
731                let validator = self.validator.code_section_entry(&body)?;
732                let func_index =
733                    self.result.code_index + self.result.module.num_imported_funcs as u32;
734                let func_index = FuncIndex::from_u32(func_index);
735
736                if self.tunables.debug_native {
737                    let sig_index = self.result.module.functions[func_index]
738                        .signature
739                        .unwrap_module_type_index();
740                    let sig = self.types[sig_index].unwrap_func();
741                    let mut locals = Vec::new();
742                    for pair in body.get_locals_reader()? {
743                        let (cnt, ty) = pair?;
744                        let ty = self.convert_valtype(ty)?;
745                        locals.push((cnt, ty));
746                    }
747                    self.result
748                        .debuginfo
749                        .wasm_file
750                        .funcs
751                        .push(FunctionMetadata {
752                            locals: locals.into_boxed_slice(),
753                            params: sig.params().into(),
754                        });
755                }
756                if self.tunables.debug_guest {
757                    // All functions are potentially reachable and
758                    // callable by the guest debugger, so they must
759                    // all be flagged as escaping.
760                    self.flag_func_escaped(func_index);
761                }
762                self.result
763                    .function_body_inputs
764                    .push(FunctionBodyData { validator, body });
765                self.result.code_index += 1;
766            }
767
768            Payload::DataSection(data) => {
769                self.validator.data_section(&data)?;
770
771                assert!(self.result.module.memory_initialization.is_segmented());
772
773                for (index, entry) in data.into_iter().enumerate() {
774                    let wasmparser::Data {
775                        kind,
776                        data,
777                        range: _,
778                    } = entry?;
779                    let data_index = DataIndex::from_u32(index.try_into().unwrap());
780                    match kind {
781                        DataKind::Active {
782                            memory_index,
783                            offset_expr,
784                        } => {
785                            let memory_index = MemoryIndex::from_u32(memory_index);
786                            let (offset, escaped) = ConstExpr::from_wasmparser(self, offset_expr)?;
787                            debug_assert!(escaped.is_empty());
788
789                            let MemoryInit::Unprocessed(list) = &mut self.result.memory_init else {
790                                panic!("memory initializers should be unprocessed at this point");
791                            };
792                            list.push(MemoryInitializer {
793                                memory_index,
794                                offset,
795                                data,
796                            });
797                        }
798                        DataKind::Passive => {
799                            self.result.passive_data.push((data_index, data));
800                        }
801                    }
802                }
803            }
804
805            Payload::DataCountSection { count, range } => {
806                self.validator.data_count_section(count, &range)?;
807
808                // Note: the count passed in here is the *total* segment count
809                // There is no way to reserve for just the passive segments as
810                // they are discovered when iterating the data section entries
811                // Given that the total segment count might be much larger than
812                // the passive count, do not reserve anything here.
813            }
814
815            Payload::CustomSection(s)
816                if s.name() == "webidl-bindings" || s.name() == "wasm-interface-types" =>
817            {
818                bail!(
819                    "\
820Support for interface types has temporarily been removed from `wasmtime`.
821
822For more information about this temporary change you can read on the issue online:
823
824    https://github.com/bytecodealliance/wasmtime/issues/1271
825
826and for re-adding support for interface types you can see this issue:
827
828    https://github.com/bytecodealliance/wasmtime/issues/677
829"
830                )
831            }
832
833            Payload::CustomSection(s) => {
834                self.register_custom_section(&s);
835            }
836
837            // It's expected that validation will probably reject other
838            // payloads such as `UnknownSection` or those related to the
839            // component model. If, however, something gets past validation then
840            // that's a bug in Wasmtime as we forgot to implement something.
841            other => {
842                self.validator.payload(&other)?;
843                panic!("unimplemented section in wasm file {other:?}");
844            }
845        }
846        Ok(())
847    }
848
849    fn register_custom_section(&mut self, section: &CustomSectionReader<'data>) {
850        match section.as_known() {
851            KnownCustom::Name(name) => {
852                let result = self.name_section(name);
853                if let Err(e) = result {
854                    log::warn!("failed to parse name section {e:?}");
855                }
856            }
857            KnownCustom::BranchHints(reader) if self.tunables.branch_hinting => {
858                // Branch hints are advisory and this section is never validated;
859                // it is decoded lazily during compilation, so record only the
860                // per-function sub-readers here. Discard the whole section if any
861                // entry is malformed rather than applying it partially.
862                let mut hints = HashMap::new();
863                let result: wasmparser::Result<()> = reader.into_iter().try_for_each(|func| {
864                    let func = func?;
865                    // A well-formed section lists each function at most once; keep
866                    // the first entry deterministically if it repeats.
867                    hints
868                        .entry(FuncIndex::from_u32(func.func))
869                        .or_insert(func.hints);
870                    Ok(())
871                });
872                match result {
873                    Ok(()) => self.result.branch_hints = hints,
874                    Err(e) => log::warn!("failed to parse branch-hint section {e:?}"),
875                }
876            }
877            _ => {
878                let name = section.name().trim_end_matches(".dwo");
879                if name.starts_with(".debug_") {
880                    self.dwarf_section(name, section);
881                }
882            }
883        }
884    }
885
886    fn dwarf_section(&mut self, name: &str, section: &CustomSectionReader<'data>) {
887        if !self.tunables.debug_native && !self.tunables.parse_wasm_debuginfo {
888            self.result.has_unparsed_debuginfo = true;
889            return;
890        }
891        let info = &mut self.result.debuginfo;
892        let dwarf = &mut info.dwarf;
893        let endian = gimli::LittleEndian;
894        let data = section.data();
895        let slice = gimli::EndianSlice::new(data, endian);
896
897        match name {
898            // `gimli::Dwarf` fields.
899            ".debug_abbrev" => dwarf.debug_abbrev = gimli::DebugAbbrev::new(data, endian),
900            ".debug_addr" => dwarf.debug_addr = gimli::DebugAddr::from(slice),
901            ".debug_info" => {
902                dwarf.debug_info = gimli::DebugInfo::new(data, endian);
903            }
904            ".debug_line" => dwarf.debug_line = gimli::DebugLine::new(data, endian),
905            ".debug_line_str" => dwarf.debug_line_str = gimli::DebugLineStr::from(slice),
906            ".debug_str" => dwarf.debug_str = gimli::DebugStr::new(data, endian),
907            ".debug_str_offsets" => dwarf.debug_str_offsets = gimli::DebugStrOffsets::from(slice),
908            ".debug_str_sup" => {
909                let mut dwarf_sup: Dwarf<'data> = Default::default();
910                dwarf_sup.debug_str = gimli::DebugStr::from(slice);
911                dwarf.sup = Some(Arc::new(dwarf_sup));
912            }
913            ".debug_types" => dwarf.debug_types = gimli::DebugTypes::from(slice),
914
915            // Additional fields.
916            ".debug_loc" => info.debug_loc = gimli::DebugLoc::from(slice),
917            ".debug_loclists" => info.debug_loclists = gimli::DebugLocLists::from(slice),
918            ".debug_ranges" => info.debug_ranges = gimli::DebugRanges::new(data, endian),
919            ".debug_rnglists" => info.debug_rnglists = gimli::DebugRngLists::new(data, endian),
920
921            // DWARF package fields
922            ".debug_cu_index" => info.debug_cu_index = gimli::DebugCuIndex::new(data, endian),
923            ".debug_tu_index" => info.debug_tu_index = gimli::DebugTuIndex::new(data, endian),
924
925            // We don't use these at the moment.
926            ".debug_aranges" | ".debug_pubnames" | ".debug_pubtypes" => return,
927            other => {
928                log::warn!("unknown debug section `{other}`");
929                return;
930            }
931        }
932
933        dwarf.ranges = gimli::RangeLists::new(info.debug_ranges, info.debug_rnglists);
934        dwarf.locations = gimli::LocationLists::new(info.debug_loc, info.debug_loclists);
935    }
936
937    /// Declares a new import with the `module` and `field` names, importing the
938    /// `ty` specified.
939    ///
940    /// Note that this method is somewhat tricky due to the implementation of
941    /// the module linking proposal. In the module linking proposal two-level
942    /// imports are recast as single-level imports of instances. That recasting
943    /// happens here by recording an import of an instance for the first time
944    /// we see a two-level import.
945    ///
946    /// When the module linking proposal is disabled, however, disregard this
947    /// logic and instead work directly with two-level imports since no
948    /// instances are defined.
949    fn declare_import(
950        &mut self,
951        module: &'data str,
952        field: &'data str,
953        ty: EntityType,
954    ) -> Result<(), OutOfMemory> {
955        let index = self.push_type(ty);
956        self.result.module.initializers.push(Initializer::Import {
957            name: self.result.module.strings.insert(module)?,
958            field: self.result.module.strings.insert(field)?,
959            index,
960        })?;
961        Ok(())
962    }
963
964    fn push_type(&mut self, ty: EntityType) -> EntityIndex {
965        match ty {
966            EntityType::Function(ty) => EntityIndex::Function({
967                let func_index = self
968                    .result
969                    .module
970                    .push_function(ty.unwrap_module_type_index());
971                // Imported functions can escape; in fact, they've already done
972                // so to get here.
973                self.flag_func_escaped(func_index);
974                func_index
975            }),
976            EntityType::Table(ty) => {
977                EntityIndex::Table(self.result.module.tables.push(ty).panic_on_oom())
978            }
979            EntityType::Memory(ty) => {
980                EntityIndex::Memory(self.result.module.memories.push(ty).panic_on_oom())
981            }
982            EntityType::Global(ty) => {
983                EntityIndex::Global(self.result.module.globals.push(ty).panic_on_oom())
984            }
985            EntityType::Tag(ty) => {
986                EntityIndex::Tag(self.result.module.tags.push(ty).panic_on_oom())
987            }
988        }
989    }
990
991    fn flag_func_escaped(&mut self, func: FuncIndex) {
992        let ty = &mut self.result.module.functions[func];
993        // If this was already assigned a funcref index no need to re-assign it.
994        if ty.is_escaping() {
995            return;
996        }
997        let index = self.result.module.num_escaped_funcs as u32;
998        ty.func_ref = FuncRefIndex::from_u32(index);
999        self.result.module.num_escaped_funcs += 1;
1000    }
1001
1002    /// Parses the Name section of the wasm module.
1003    fn name_section(&mut self, names: NameSectionReader<'data>) -> WasmResult<()> {
1004        for subsection in names {
1005            match subsection? {
1006                wasmparser::Name::Function(names) => {
1007                    for name in names {
1008                        let Naming { index, name } = name?;
1009                        // Skip this naming if it's naming a function that
1010                        // doesn't actually exist.
1011                        if (index as usize) >= self.result.module.functions.len() {
1012                            continue;
1013                        }
1014
1015                        // Store the name unconditionally, regardless of
1016                        // whether we're parsing debuginfo, since function
1017                        // names are almost always present in the
1018                        // final compilation artifact.
1019                        let index = FuncIndex::from_u32(index);
1020                        self.result
1021                            .debuginfo
1022                            .name_section
1023                            .func_names
1024                            .insert(index, name);
1025                    }
1026                }
1027                wasmparser::Name::Module { name, .. } => {
1028                    self.result.module.name =
1029                        Some(self.result.module.strings.insert(name).panic_on_oom());
1030                    if self.tunables.debug_native {
1031                        self.result.debuginfo.name_section.module_name = Some(name);
1032                    }
1033                }
1034                wasmparser::Name::Local(reader) => {
1035                    if !self.tunables.debug_native {
1036                        continue;
1037                    }
1038                    for f in reader {
1039                        let f = f?;
1040                        // Skip this naming if it's naming a function that
1041                        // doesn't actually exist.
1042                        if (f.index as usize) >= self.result.module.functions.len() {
1043                            continue;
1044                        }
1045                        for name in f.names {
1046                            let Naming { index, name } = name?;
1047
1048                            self.result
1049                                .debuginfo
1050                                .name_section
1051                                .locals_names
1052                                .entry(FuncIndex::from_u32(f.index))
1053                                .or_insert(HashMap::new())
1054                                .insert(index, name);
1055                        }
1056                    }
1057                }
1058                wasmparser::Name::Label(_)
1059                | wasmparser::Name::Type(_)
1060                | wasmparser::Name::Table(_)
1061                | wasmparser::Name::Global(_)
1062                | wasmparser::Name::Memory(_)
1063                | wasmparser::Name::Element(_)
1064                | wasmparser::Name::Data(_)
1065                | wasmparser::Name::Tag(_)
1066                | wasmparser::Name::Field(_)
1067                | wasmparser::Name::Unknown { .. } => {}
1068            }
1069        }
1070        Ok(())
1071    }
1072
1073    fn require_startup_func(&mut self) {
1074        self.result.require_startup_func(self.types);
1075    }
1076}
1077
1078impl TypeConvert for ModuleEnvironment<'_, '_> {
1079    fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType {
1080        WasmparserTypeConverter::new(&self.types, |idx| {
1081            self.result.module.types[idx].unwrap_module_type_index()
1082        })
1083        .lookup_heap_type(index)
1084    }
1085
1086    fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex {
1087        WasmparserTypeConverter::new(&self.types, |idx| {
1088            self.result.module.types[idx].unwrap_module_type_index()
1089        })
1090        .lookup_type_index(index)
1091    }
1092}
1093
1094impl ModuleTranslation<'_> {
1095    /// Called after translation is complete this will finalize the memory
1096    /// initialization strategy for this module.
1097    ///
1098    /// This will notably use `Self::try_static_init` to attempt to massage
1099    /// data segments to being CoW-init-friendly. Afterwards the
1100    /// `self.memory_init` field is transitioned from `Unprocessed` to
1101    /// `Processed`.
1102    pub fn finalize_memory_init(
1103        &mut self,
1104        tunables: &Tunables,
1105        page_size: u64,
1106        max_image_size_always_allowed: u64,
1107        types: &mut ModuleTypesBuilder,
1108    ) {
1109        if tunables.memory_init_cow {
1110            self.try_static_init(page_size, max_image_size_always_allowed);
1111        }
1112
1113        // If any memory is statically initialized, and if that memory has an
1114        // initial data segment, then a startup function is at least
1115        // conditionally needed if the memory needs initialization. Flag as such
1116        // here.
1117        if let MemoryInitialization::Static { map } = &self.module.memory_initialization {
1118            if map.iter().any(|(_, v)| v.is_some()) {
1119                self.require_startup_func_if_memories_need_init(types);
1120            }
1121        }
1122
1123        // If, after `try_static_init`, initializers are still `Unprocessed`
1124        // then this is the catch-all fallback path for initialization. All
1125        // segments are promoted into `self.runtime_data` and then the
1126        // initialization is rewritten to `Processed`.
1127        if let MemoryInit::Unprocessed(list) = &mut self.memory_init {
1128            let segments = mem::take(list);
1129            let mut new_initializers = Vec::new();
1130            for segment in segments {
1131                new_initializers.push((
1132                    segment.memory_index,
1133                    MemorySegmentOffset::Expr(segment.offset),
1134                    self.runtime_data.push(segment.data.into()),
1135                ));
1136            }
1137            if !new_initializers.is_empty() {
1138                self.require_startup_func(types);
1139            }
1140            self.memory_init = MemoryInit::Processed(new_initializers);
1141        }
1142
1143        // At this point append all passive data to the `runtime_data` list.
1144        // This notably occurs after `try_static_init` above to ensure that the
1145        // page-aligned data for static initialization, if applicable, comes
1146        // first.
1147        for (data_index, segment) in self.passive_data.iter() {
1148            let runtime_index = self.runtime_data.push((*segment).into());
1149            self.runtime_data_map
1150                .insert(*data_index, Some(runtime_index));
1151        }
1152
1153        // And, finally, record all chunks from `self.runtime_data` within
1154        // `self.module.runtime_data` as well.
1155        let mut cur = 0;
1156        for (idx, data) in self.runtime_data.iter() {
1157            let len = u32::try_from(data.len()).unwrap();
1158            let i = self.module.runtime_data.push(cur..cur + len).panic_on_oom();
1159            cur += len;
1160            assert_eq!(idx, i);
1161        }
1162    }
1163
1164    /// Attempts to convert segmented memory initialization into static
1165    /// initialization for the module that this translation represents.
1166    ///
1167    /// If this module's memory initialization is not compatible with paged
1168    /// initialization then this won't change anything. Otherwise if it is
1169    /// compatible then the `memory_initialization` field will be updated.
1170    ///
1171    /// Takes a `page_size` argument in order to ensure that all
1172    /// initialization is page-aligned for mmap-ability, and
1173    /// `max_image_size_always_allowed` to control how we decide
1174    /// whether to use static init.
1175    ///
1176    /// We will try to avoid generating very sparse images, which are
1177    /// possible if e.g. a module has an initializer at offset 0 and a
1178    /// very high offset (say, 1 GiB). To avoid this, we use a dual
1179    /// condition: we always allow images less than
1180    /// `max_image_size_always_allowed`, and the embedder of Wasmtime
1181    /// can set this if desired to ensure that static init should
1182    /// always be done if the size of the module or its heaps is
1183    /// otherwise bounded by the system. We also allow images with
1184    /// static init data bigger than that, but only if it is "dense",
1185    /// defined as having at least half (50%) of its pages with some
1186    /// data.
1187    ///
1188    /// We could do something slightly better by building a dense part
1189    /// and keeping a sparse list of outlier/leftover segments (see
1190    /// issue #3820). This would also allow mostly-static init of
1191    /// modules that have some dynamically-placed data segments. But,
1192    /// for now, this is sufficient to allow a system that "knows what
1193    /// it's doing" to always get static init.
1194    fn try_static_init(&mut self, page_size: u64, max_image_size_always_allowed: u64) {
1195        let segments = match &mut self.memory_init {
1196            MemoryInit::Unprocessed(list) => list,
1197            _ => return,
1198        };
1199
1200        // First a dry run of memory initialization is performed. This
1201        // collects information about the extent of memory initialized for each
1202        // memory as well as the size of all data segments being copied in.
1203        struct Memory<'a> {
1204            data_size: u64,
1205            min_addr: u64,
1206            max_addr: u64,
1207            segments: Vec<(u64, &'a [u8])>,
1208        }
1209        let mut info = PrimaryMap::with_capacity(self.module.memories.len());
1210        for _ in 0..self.module.memories.len() {
1211            info.push(Memory {
1212                data_size: 0,
1213                min_addr: u64::MAX,
1214                max_addr: 0,
1215                segments: Vec::new(),
1216            });
1217        }
1218
1219        for initializer in segments.iter() {
1220            let &MemoryInitializer {
1221                memory_index,
1222                ref offset,
1223                ref data,
1224            } = initializer;
1225
1226            // Currently `Static` only applies to locally-defined memories,
1227            // so if a data segment references an imported memory then
1228            // transitioning to a `Static` memory initializer is not
1229            // possible.
1230            if self.module.defined_memory_index(memory_index).is_none() {
1231                return;
1232            }
1233
1234            // First up determine the start/end range and verify that they're
1235            // in-bounds for the initial size of the memory at `memory_index`.
1236            // Note that this can bail if we don't have access to globals yet
1237            // (e.g. this is a task happening before instantiation at
1238            // compile-time).
1239            let start = match (offset.ops(), self.module.memories[memory_index].idx_type) {
1240                (&[ConstOp::I32Const(offset)], IndexType::I32) => offset.cast_unsigned().into(),
1241                (&[ConstOp::I64Const(offset)], IndexType::I64) => offset.cast_unsigned(),
1242                _ => return,
1243            };
1244            let len = u64::try_from(data.len()).unwrap();
1245            let end = match start.checked_add(len) {
1246                Some(end) => end,
1247                None => return,
1248            };
1249
1250            match self.module.memories[memory_index].minimum_byte_size() {
1251                Ok(max) => {
1252                    if end > max {
1253                        return;
1254                    }
1255                }
1256
1257                // Note that computing the minimum can overflow if the page
1258                // size is the default 64KiB and the memory's minimum size in
1259                // pages is `1 << 48`, the maximum number of minimum pages for
1260                // 64-bit memories. We don't return `false` to signal an error
1261                // here and instead defer the error to runtime, when it will be
1262                // impossible to allocate that much memory anyways.
1263                Err(_) => return,
1264            }
1265
1266            // Skip empty in-bounds data segments.
1267            if data.is_empty() {
1268                continue;
1269            }
1270
1271            let info = &mut info[memory_index];
1272            let len64 = u64::try_from(data.len()).unwrap();
1273            info.data_size += len64;
1274            info.min_addr = info.min_addr.min(start);
1275            info.max_addr = info.max_addr.max(start + len64);
1276            info.segments.push((start, data));
1277        }
1278
1279        // Validate that the memory information collected is indeed valid for
1280        // static memory initialization.
1281        for (i, info) in info.iter().filter(|(_, info)| info.data_size > 0) {
1282            let image_size = info.max_addr - info.min_addr;
1283
1284            // Simplify things for now by bailing out entirely if any memory has
1285            // a page size smaller than the host's page size. This fixes a case
1286            // where currently initializers are created in host-page-size units
1287            // of length which means that a larger-than-the-entire-memory
1288            // initializer can be created. This can be handled technically but
1289            // would require some more changes to help fix the assert elsewhere
1290            // that this protects against.
1291            if self.module.memories[i].page_size() < page_size {
1292                return;
1293            }
1294
1295            // If the range of memory being initialized is less than twice the
1296            // total size of the data itself then it's assumed that static
1297            // initialization is ok. This means we'll at most double memory
1298            // consumption during the memory image creation process, which is
1299            // currently assumed to "probably be ok" but this will likely need
1300            // tweaks over time.
1301            if image_size < info.data_size.saturating_mul(2) {
1302                continue;
1303            }
1304
1305            // If the memory initialization image is larger than the size of all
1306            // data, then we still allow memory initialization if the image will
1307            // be of a relatively modest size, such as 1MB here.
1308            if image_size < max_image_size_always_allowed {
1309                continue;
1310            }
1311
1312            // At this point memory initialization is concluded to be too
1313            // expensive to do at compile time so it's entirely deferred to
1314            // happen at runtime.
1315            return;
1316        }
1317
1318        // Here's where we've now committed to changing to static memory. The
1319        // memory initialization image is built here from the page data and then
1320        // it's converted to a single initializer.
1321        let mut map = TryPrimaryMap::with_capacity(info.len()).panic_on_oom();
1322        let mut new_initializers = Vec::new();
1323        for (memory, info) in info.iter() {
1324            // Create the in-memory `image` which is the initialized contents of
1325            // this linear memory.
1326            let extent = if info.segments.len() > 0 {
1327                (info.max_addr - info.min_addr) as usize
1328            } else {
1329                0
1330            };
1331            let mut image = Vec::with_capacity(extent);
1332            for (offset, data) in info.segments.iter() {
1333                let offset = usize::try_from(*offset - info.min_addr).unwrap();
1334                if image.len() < offset {
1335                    image.resize(offset, 0u8);
1336                    image.extend_from_slice(data);
1337                } else {
1338                    image.splice(
1339                        offset..(offset + data.len()).min(image.len()),
1340                        data.iter().copied(),
1341                    );
1342                }
1343            }
1344            assert_eq!(image.len(), extent);
1345            assert_eq!(image.capacity(), extent);
1346            let mut offset = if info.segments.len() > 0 {
1347                info.min_addr
1348            } else {
1349                0
1350            };
1351
1352            // Chop off trailing zeros from the image as memory is already
1353            // zero-initialized. Note that `i` is the position of a nonzero
1354            // entry here, so to not lose it we truncate to `i + 1`.
1355            if let Some(i) = image.iter().rposition(|i| *i != 0) {
1356                image.truncate(i + 1);
1357            }
1358
1359            // Also chop off leading zeros, if any.
1360            if let Some(i) = image.iter().position(|i| *i != 0) {
1361                offset += i as u64;
1362                image.drain(..i);
1363            }
1364            let mut len = u64::try_from(image.len()).unwrap();
1365
1366            // The goal is to enable mapping this image directly into memory, so
1367            // the offset into linear memory must be a multiple of the page
1368            // size. If that's not already the case then the image is padded at
1369            // the front and back with extra zeros as necessary
1370            if offset % page_size != 0 {
1371                let zero_padding = offset % page_size;
1372                image.splice(0..0, std::iter::repeat(0).take(zero_padding as usize));
1373                offset -= zero_padding;
1374                len += zero_padding;
1375            }
1376            if len % page_size != 0 {
1377                let zero_padding = page_size - (len % page_size);
1378                image.extend(std::iter::repeat(0).take(zero_padding as usize));
1379                len += zero_padding;
1380            }
1381            let runtime_index = if image.is_empty() {
1382                None
1383            } else {
1384                Some(self.runtime_data.push(image.into()))
1385            };
1386
1387            // Offset/length should now always be page-aligned.
1388            assert!(offset % page_size == 0);
1389            assert!(len % page_size == 0);
1390
1391            // Record the static memory initializer which describes this image,
1392            // only needed if the image is actually present and has a nonzero
1393            // length. The `offset` has been calculates above, originally
1394            // sourced from `info.min_addr`. The `data` field is the extent
1395            // within the final data segment we'll emit to an ELF image, which
1396            // is the concatenation of `self.data`, so here it's the size of
1397            // the section-so-far plus the current segment we're appending.
1398            let idx = map.push(runtime_index.map(|i| (offset, i))).panic_on_oom();
1399            assert_eq!(idx, memory);
1400            if let Some(runtime_index) = runtime_index {
1401                new_initializers.push((idx, MemorySegmentOffset::Static(offset), runtime_index));
1402            }
1403        }
1404        self.data_align = Some(page_size);
1405        self.module.memory_initialization = MemoryInitialization::Static { map };
1406        self.memory_init = MemoryInit::Processed(new_initializers);
1407    }
1408
1409    /// Finalizes the initialization of tables.
1410    ///
1411    /// This is invoked after translation and notably uses
1412    /// `Self::try_func_table_init` to attempt to optimize initialization of
1413    /// tables into static precomputed images.
1414    pub fn finalize_table_init(&mut self, tunables: &Tunables, types: &mut ModuleTypesBuilder) {
1415        if tunables.table_lazy_init {
1416            self.try_func_table_init();
1417        }
1418
1419        // If any table has a non-null initializers, or if there's any active
1420        // data segments, then a startup function is unconditionally required to
1421        // configure the table.
1422        if self
1423            .table_initialization
1424            .initial_values
1425            .iter()
1426            .any(|(_, v)| !matches!(v, TableInitialValue::Null))
1427            || !self.table_initialization.segments.is_empty()
1428        {
1429            self.require_startup_func(types);
1430        }
1431    }
1432
1433    /// Attempts to convert the module's table initializers to
1434    /// FuncTable form where possible. This enables lazy table
1435    /// initialization later by providing a one-to-one map of initial
1436    /// table values, without having to parse all segments.
1437    fn try_func_table_init(&mut self) {
1438        // This should be large enough to support very large Wasm
1439        // modules with huge funcref tables, but small enough to avoid
1440        // OOMs or DoS on truly sparse tables.
1441        const MAX_FUNC_TABLE_SIZE: u64 = 1024 * 1024;
1442
1443        // First convert any element-initialized tables to images of just that
1444        // single function if the minimum size of the table allows doing so.
1445        for ((i, init), (_, table)) in self.table_initialization.initial_values.iter_mut().zip(
1446            self.module
1447                .tables
1448                .iter()
1449                .skip(self.module.num_imported_tables),
1450        ) {
1451            let table_size = table.limits.min;
1452            if table_size > MAX_FUNC_TABLE_SIZE {
1453                continue;
1454            }
1455            if let TableInitialValue::Expr(expr) = init {
1456                if let [ConstOp::RefFunc(f)] = expr.ops() {
1457                    assert!(self.module.table_initialization[i].is_empty());
1458                    self.module.table_initialization[i] =
1459                        try_vec![*f; table_size as usize].panic_on_oom();
1460                    *init = TableInitialValue::Null;
1461                }
1462            }
1463        }
1464
1465        let mut segments = mem::take(&mut self.table_initialization.segments)
1466            .into_iter()
1467            .peekable();
1468
1469        // The goal of this loop is to interpret a table segment and apply it
1470        // "statically" to a local table. This will iterate over segments and
1471        // apply them one-by-one to each table.
1472        //
1473        // If any segment can't be applied, however, then this loop exits and
1474        // all remaining segments are placed back into the segment list. This is
1475        // because segments are supposed to be initialized one-at-a-time which
1476        // means that intermediate state is visible with respect to traps. If
1477        // anything isn't statically known to not trap it's pessimistically
1478        // assumed to trap meaning all further segment initializers must be
1479        // applied manually at instantiation time.
1480        while let Some(segment) = segments.peek() {
1481            let defined_index = match self.module.defined_table_index(segment.table_index) {
1482                Some(index) => index,
1483                // Skip imported tables: we can't provide a preconstructed
1484                // table for them, because their values depend on the
1485                // imported table overlaid with whatever segments we have.
1486                None => break,
1487            };
1488
1489            // If the base of this segment is dynamic, then we can't
1490            // include it in the statically-built array of initial
1491            // contents.
1492            let offset = match segment.offset.ops() {
1493                &[ConstOp::I32Const(offset)] => u64::from(offset.cast_unsigned()),
1494                &[ConstOp::I64Const(offset)] => offset.cast_unsigned(),
1495                _ => break,
1496            };
1497
1498            // Get the end of this segment. If out-of-bounds, or too
1499            // large for our dense table representation, then skip the
1500            // segment.
1501            let top = match offset.checked_add(segment.elements.len()) {
1502                Some(top) => top,
1503                None => break,
1504            };
1505            let table_size = self.module.tables[segment.table_index].limits.min;
1506            if top > table_size || top > MAX_FUNC_TABLE_SIZE {
1507                break;
1508            }
1509
1510            match self.module.tables[segment.table_index]
1511                .ref_type
1512                .heap_type
1513                .top()
1514            {
1515                WasmHeapTopType::Func => {}
1516                // If this is not a funcref table, then we can't support a
1517                // pre-computed table of function indices. Technically this
1518                // initializer won't trap so we could continue processing
1519                // segments, but that's left as a future optimization if
1520                // necessary.
1521                WasmHeapTopType::Any
1522                | WasmHeapTopType::Extern
1523                | WasmHeapTopType::Cont
1524                | WasmHeapTopType::Exn => break,
1525            }
1526
1527            // Function indices can be optimized here, but fully general
1528            // expressions are deferred to get evaluated at runtime.
1529            let function_elements = match &segment.elements {
1530                TableSegmentElements::Functions(indices) => indices,
1531                TableSegmentElements::Expressions { .. } => break,
1532            };
1533
1534            match &self.table_initialization.initial_values[defined_index] {
1535                TableInitialValue::Null => {}
1536
1537                // If this table is still listed as an initial value here
1538                // then that means the initial size of the table doesn't
1539                // support a precomputed function list, so skip this.
1540                // Technically this won't trap so it's possible to process
1541                // further initializers, but that's left as a future
1542                // optimization.
1543                TableInitialValue::Expr(_) => break,
1544            }
1545            let precomputed = &mut self.module.table_initialization[defined_index];
1546
1547            // At this point we're committing to pre-initializing the table
1548            // with the `segment` that's being iterated over. This segment is
1549            // applied to the `precomputed` list for the table by ensuring
1550            // it's large enough to hold the segment and then copying the
1551            // segment into the precomputed list.
1552            if precomputed.len() < top as usize {
1553                precomputed
1554                    .resize(top as usize, FuncIndex::reserved_value())
1555                    .panic_on_oom();
1556            }
1557            let dst = &mut precomputed[offset as usize..top as usize];
1558            dst.copy_from_slice(&function_elements);
1559
1560            // advance the iterator to see the next segment
1561            let _ = segments.next();
1562        }
1563        self.table_initialization.segments = segments.try_collect().panic_on_oom();
1564    }
1565
1566    /// Helper function to ratchet the `startup` function for this module as
1567    /// `Always`.
1568    fn require_startup_func(&mut self, types: &mut ModuleTypesBuilder) {
1569        let ty = match self.module.startup {
1570            ModuleStartup::None => types.startup_func_type().into(),
1571            ModuleStartup::Always(_) => return,
1572            ModuleStartup::IfMemoriesNeedInit(ty) => ty,
1573        };
1574        self.module.startup = ModuleStartup::Always(ty);
1575    }
1576
1577    /// Helper function to ratchet the `startup` function for this module as
1578    /// `IfMemoriesNeedInit`.
1579    fn require_startup_func_if_memories_need_init(&mut self, types: &mut ModuleTypesBuilder) {
1580        let ty = match self.module.startup {
1581            ModuleStartup::None => types.startup_func_type().into(),
1582            ModuleStartup::Always(_) | ModuleStartup::IfMemoriesNeedInit(_) => return,
1583        };
1584        self.module.startup = ModuleStartup::IfMemoriesNeedInit(ty);
1585    }
1586}