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