Coverage Report

Created: 2026-08-15 07:39

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