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