Skip to main content

wasmtime_environ/compile/
module_environ.rs

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