1use crate::module::{
2 FuncRefIndex, Initializer, MemoryInitialization, MemoryInitializer, Module, TableSegment,
3 TableSegmentElements,
4};
5use crate::{
6 ConstExpr, ConstOp, DataIndex, DefinedFuncIndex, ElemIndex, EngineOrModuleTypeIndex,
7 EntityIndex, EntityType, FuncIndex, GlobalIndex, IndexType, InitMemory, MemoryIndex,
8 ModuleInternedTypeIndex, ModuleTypesBuilder, PrimaryMap, SizeOverflow, StaticMemoryInitializer,
9 TableIndex, TableInitialValue, Tag, TagIndex, Tunables, TypeConvert, TypeIndex, WasmError,
10 WasmHeapTopType, WasmHeapType, WasmResult, WasmValType, WasmparserTypeConverter,
11};
12use crate::{StaticModuleIndex, prelude::*};
13use anyhow::{Result, bail};
14use cranelift_entity::SecondaryMap;
15use cranelift_entity::packed_option::ReservedValue;
16use std::borrow::Cow;
17use std::collections::HashMap;
18use std::mem;
19use std::path::PathBuf;
20use std::sync::Arc;
21use wasmparser::{
22 CustomSectionReader, DataKind, ElementItems, ElementKind, Encoding, ExternalKind,
23 FuncToValidate, FunctionBody, KnownCustom, NameSectionReader, Naming, Parser, Payload, TypeRef,
24 Validator, ValidatorResources, types::Types,
25};
26
27pub struct ModuleEnvironment<'a, 'data> {
29 result: ModuleTranslation<'data>,
31
32 types: &'a mut ModuleTypesBuilder,
34
35 validator: &'a mut Validator,
37 tunables: &'a Tunables,
38}
39
40pub struct ModuleTranslation<'data> {
45 pub module: Module,
47
48 pub wasm: &'data [u8],
54
55 pub function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
57
58 pub known_imported_functions:
63 SecondaryMap<FuncIndex, Option<(StaticModuleIndex, DefinedFuncIndex)>>,
64
65 pub exported_signatures: Vec<ModuleInternedTypeIndex>,
69
70 pub debuginfo: DebugInfoData<'data>,
72
73 pub has_unparsed_debuginfo: bool,
76
77 pub data: Vec<Cow<'data, [u8]>>,
83
84 pub data_align: Option<u64>,
91
92 total_data: u32,
94
95 pub passive_data: Vec<&'data [u8]>,
98
99 total_passive_data: u32,
101
102 code_index: u32,
105
106 types: Option<Types>,
109}
110
111impl<'data> ModuleTranslation<'data> {
112 pub fn new(module_index: StaticModuleIndex) -> Self {
114 Self {
115 module: Module::new(module_index),
116 wasm: &[],
117 function_body_inputs: PrimaryMap::default(),
118 known_imported_functions: SecondaryMap::default(),
119 exported_signatures: Vec::default(),
120 debuginfo: DebugInfoData::default(),
121 has_unparsed_debuginfo: false,
122 data: Vec::default(),
123 data_align: None,
124 total_data: 0,
125 passive_data: Vec::default(),
126 total_passive_data: 0,
127 code_index: 0,
128 types: None,
129 }
130 }
131
132 pub fn get_types(&self) -> &Types {
134 self.types
135 .as_ref()
136 .expect("module type information to be available")
137 }
138
139 pub fn module_index(&self) -> StaticModuleIndex {
141 self.module.module_index
142 }
143}
144
145pub struct FunctionBodyData<'a> {
147 pub body: FunctionBody<'a>,
149 pub validator: FuncToValidate<ValidatorResources>,
151}
152
153#[derive(Debug, Default)]
154#[expect(missing_docs, reason = "self-describing fields")]
155pub struct DebugInfoData<'a> {
156 pub dwarf: Dwarf<'a>,
157 pub name_section: NameSection<'a>,
158 pub wasm_file: WasmFileInfo,
159 pub debug_loc: gimli::DebugLoc<Reader<'a>>,
160 pub debug_loclists: gimli::DebugLocLists<Reader<'a>>,
161 pub debug_ranges: gimli::DebugRanges<Reader<'a>>,
162 pub debug_rnglists: gimli::DebugRngLists<Reader<'a>>,
163 pub debug_cu_index: gimli::DebugCuIndex<Reader<'a>>,
164 pub debug_tu_index: gimli::DebugTuIndex<Reader<'a>>,
165}
166
167#[expect(missing_docs, reason = "self-describing")]
168pub type Dwarf<'input> = gimli::Dwarf<Reader<'input>>;
169
170type Reader<'input> = gimli::EndianSlice<'input, gimli::LittleEndian>;
171
172#[derive(Debug, Default)]
173#[expect(missing_docs, reason = "self-describing fields")]
174pub struct NameSection<'a> {
175 pub module_name: Option<&'a str>,
176 pub func_names: HashMap<FuncIndex, &'a str>,
177 pub locals_names: HashMap<FuncIndex, HashMap<u32, &'a str>>,
178}
179
180#[derive(Debug, Default)]
181#[expect(missing_docs, reason = "self-describing fields")]
182pub struct WasmFileInfo {
183 pub path: Option<PathBuf>,
184 pub code_section_offset: u64,
185 pub imported_func_count: u32,
186 pub funcs: Vec<FunctionMetadata>,
187}
188
189#[derive(Debug)]
190#[expect(missing_docs, reason = "self-describing fields")]
191pub struct FunctionMetadata {
192 pub params: Box<[WasmValType]>,
193 pub locals: Box<[(u32, WasmValType)]>,
194}
195
196impl<'a, 'data> ModuleEnvironment<'a, 'data> {
197 pub fn new(
199 tunables: &'a Tunables,
200 validator: &'a mut Validator,
201 types: &'a mut ModuleTypesBuilder,
202 module_index: StaticModuleIndex,
203 ) -> Self {
204 Self {
205 result: ModuleTranslation::new(module_index),
206 types,
207 tunables,
208 validator,
209 }
210 }
211
212 pub fn translate(
221 mut self,
222 parser: Parser,
223 data: &'data [u8],
224 ) -> Result<ModuleTranslation<'data>> {
225 self.result.wasm = data;
226
227 for payload in parser.parse_all(data) {
228 self.translate_payload(payload?)?;
229 }
230
231 Ok(self.result)
232 }
233
234 fn translate_payload(&mut self, payload: Payload<'data>) -> Result<()> {
235 match payload {
236 Payload::Version {
237 num,
238 encoding,
239 range,
240 } => {
241 self.validator.version(num, encoding, &range)?;
242 match encoding {
243 Encoding::Module => {}
244 Encoding::Component => {
245 bail!("expected a WebAssembly module but was given a WebAssembly component")
246 }
247 }
248 }
249
250 Payload::End(offset) => {
251 self.result.types = Some(self.validator.end(offset)?);
252
253 self.result.exported_signatures = self
257 .result
258 .module
259 .functions
260 .iter()
261 .filter_map(|(_, func)| {
262 if func.is_escaping() {
263 Some(func.signature.unwrap_module_type_index())
264 } else {
265 None
266 }
267 })
268 .collect();
269 self.result.exported_signatures.sort_unstable();
270 self.result.exported_signatures.dedup();
271 }
272
273 Payload::TypeSection(types) => {
274 self.validator.type_section(&types)?;
275
276 let count = self.validator.types(0).unwrap().core_type_count_in_module();
277 log::trace!("interning {count} Wasm types");
278
279 let capacity = usize::try_from(count).unwrap();
280 self.result.module.types.reserve(capacity);
281 self.types.reserve_wasm_signatures(capacity);
282
283 let mut type_index = 0;
293 while type_index < count {
294 let validator_types = self.validator.types(0).unwrap();
295
296 log::trace!("looking up wasmparser type for index {type_index}");
299 let core_type_id = validator_types.core_type_at_in_module(type_index);
300 log::trace!(
301 " --> {core_type_id:?} = {:?}",
302 validator_types[core_type_id],
303 );
304 let rec_group_id = validator_types.rec_group_id_of(core_type_id);
305 debug_assert_eq!(
306 validator_types
307 .rec_group_elements(rec_group_id)
308 .position(|id| id == core_type_id),
309 Some(0)
310 );
311
312 let interned = self.types.intern_rec_group(validator_types, rec_group_id)?;
315 let elems = self.types.rec_group_elements(interned);
316 let len = elems.len();
317 self.result.module.types.reserve(len);
318 for ty in elems {
319 self.result.module.types.push(ty.into());
320 }
321
322 type_index += u32::try_from(len).unwrap();
324 }
325 }
326
327 Payload::ImportSection(imports) => {
328 self.validator.import_section(&imports)?;
329
330 let cnt = usize::try_from(imports.count()).unwrap();
331 self.result.module.initializers.reserve(cnt);
332
333 for entry in imports {
334 let import = entry?;
335 let ty = match import.ty {
336 TypeRef::Func(index) => {
337 let index = TypeIndex::from_u32(index);
338 let interned_index = self.result.module.types[index];
339 self.result.module.num_imported_funcs += 1;
340 self.result.debuginfo.wasm_file.imported_func_count += 1;
341 EntityType::Function(interned_index)
342 }
343 TypeRef::Memory(ty) => {
344 self.result.module.num_imported_memories += 1;
345 EntityType::Memory(ty.into())
346 }
347 TypeRef::Global(ty) => {
348 self.result.module.num_imported_globals += 1;
349 EntityType::Global(self.convert_global_type(&ty)?)
350 }
351 TypeRef::Table(ty) => {
352 self.result.module.num_imported_tables += 1;
353 EntityType::Table(self.convert_table_type(&ty)?)
354 }
355 TypeRef::Tag(ty) => {
356 let index = TypeIndex::from_u32(ty.func_type_idx);
357 let signature = self.result.module.types[index];
358 let exception = self.types.define_exception_type_for_tag(
359 signature.unwrap_module_type_index(),
360 );
361 let tag = Tag {
362 signature,
363 exception: EngineOrModuleTypeIndex::Module(exception),
364 };
365 self.result.module.num_imported_tags += 1;
366 EntityType::Tag(tag)
367 }
368 };
369 self.declare_import(import.module, import.name, ty);
370 }
371 }
372
373 Payload::FunctionSection(functions) => {
374 self.validator.function_section(&functions)?;
375
376 let cnt = usize::try_from(functions.count()).unwrap();
377 self.result.module.functions.reserve_exact(cnt);
378
379 for entry in functions {
380 let sigindex = entry?;
381 let ty = TypeIndex::from_u32(sigindex);
382 let interned_index = self.result.module.types[ty];
383 self.result.module.push_function(interned_index);
384 }
385 }
386
387 Payload::TableSection(tables) => {
388 self.validator.table_section(&tables)?;
389 let cnt = usize::try_from(tables.count()).unwrap();
390 self.result.module.tables.reserve_exact(cnt);
391
392 for entry in tables {
393 let wasmparser::Table { ty, init } = entry?;
394 let table = self.convert_table_type(&ty)?;
395 self.result.module.needs_gc_heap |= table.ref_type.is_vmgcref_type();
396 self.result.module.tables.push(table);
397 let init = match init {
398 wasmparser::TableInit::RefNull => TableInitialValue::Null {
399 precomputed: Vec::new(),
400 },
401 wasmparser::TableInit::Expr(expr) => {
402 let (init, escaped) = ConstExpr::from_wasmparser(self, expr)?;
403 for f in escaped {
404 self.flag_func_escaped(f);
405 }
406 TableInitialValue::Expr(init)
407 }
408 };
409 self.result
410 .module
411 .table_initialization
412 .initial_values
413 .push(init);
414 }
415 }
416
417 Payload::MemorySection(memories) => {
418 self.validator.memory_section(&memories)?;
419
420 let cnt = usize::try_from(memories.count()).unwrap();
421 self.result.module.memories.reserve_exact(cnt);
422
423 for entry in memories {
424 let memory = entry?;
425 self.result.module.memories.push(memory.into());
426 }
427 }
428
429 Payload::TagSection(tags) => {
430 self.validator.tag_section(&tags)?;
431
432 for entry in tags {
433 let sigindex = entry?.func_type_idx;
434 let ty = TypeIndex::from_u32(sigindex);
435 let interned_index = self.result.module.types[ty];
436 let exception = self
437 .types
438 .define_exception_type_for_tag(interned_index.unwrap_module_type_index());
439 self.result.module.push_tag(interned_index, exception);
440 }
441 }
442
443 Payload::GlobalSection(globals) => {
444 self.validator.global_section(&globals)?;
445
446 let cnt = usize::try_from(globals.count()).unwrap();
447 self.result.module.globals.reserve_exact(cnt);
448
449 for entry in globals {
450 let wasmparser::Global { ty, init_expr } = entry?;
451 let (initializer, escaped) = ConstExpr::from_wasmparser(self, init_expr)?;
452 for f in escaped {
453 self.flag_func_escaped(f);
454 }
455 let ty = self.convert_global_type(&ty)?;
456 self.result.module.globals.push(ty);
457 self.result.module.global_initializers.push(initializer);
458 }
459 }
460
461 Payload::ExportSection(exports) => {
462 self.validator.export_section(&exports)?;
463
464 let cnt = usize::try_from(exports.count()).unwrap();
465 self.result.module.exports.reserve(cnt);
466
467 for entry in exports {
468 let wasmparser::Export { name, kind, index } = entry?;
469 let entity = match kind {
470 ExternalKind::Func => {
471 let index = FuncIndex::from_u32(index);
472 self.flag_func_escaped(index);
473 EntityIndex::Function(index)
474 }
475 ExternalKind::Table => EntityIndex::Table(TableIndex::from_u32(index)),
476 ExternalKind::Memory => EntityIndex::Memory(MemoryIndex::from_u32(index)),
477 ExternalKind::Global => EntityIndex::Global(GlobalIndex::from_u32(index)),
478 ExternalKind::Tag => EntityIndex::Tag(TagIndex::from_u32(index)),
479 };
480 self.result
481 .module
482 .exports
483 .insert(String::from(name), entity);
484 }
485 }
486
487 Payload::StartSection { func, range } => {
488 self.validator.start_section(func, &range)?;
489
490 let func_index = FuncIndex::from_u32(func);
491 self.flag_func_escaped(func_index);
492 debug_assert!(self.result.module.start_func.is_none());
493 self.result.module.start_func = Some(func_index);
494 }
495
496 Payload::ElementSection(elements) => {
497 self.validator.element_section(&elements)?;
498
499 for (index, entry) in elements.into_iter().enumerate() {
500 let wasmparser::Element {
501 kind,
502 items,
503 range: _,
504 } = entry?;
505
506 let elements = match items {
512 ElementItems::Functions(funcs) => {
513 let mut elems =
514 Vec::with_capacity(usize::try_from(funcs.count()).unwrap());
515 for func in funcs {
516 let func = FuncIndex::from_u32(func?);
517 self.flag_func_escaped(func);
518 elems.push(func);
519 }
520 TableSegmentElements::Functions(elems.into())
521 }
522 ElementItems::Expressions(_ty, items) => {
523 let mut exprs =
524 Vec::with_capacity(usize::try_from(items.count()).unwrap());
525 for expr in items {
526 let (expr, escaped) = ConstExpr::from_wasmparser(self, expr?)?;
527 exprs.push(expr);
528 for func in escaped {
529 self.flag_func_escaped(func);
530 }
531 }
532 TableSegmentElements::Expressions(exprs.into())
533 }
534 };
535
536 match kind {
537 ElementKind::Active {
538 table_index,
539 offset_expr,
540 } => {
541 let table_index = TableIndex::from_u32(table_index.unwrap_or(0));
542 let (offset, escaped) = ConstExpr::from_wasmparser(self, offset_expr)?;
543 debug_assert!(escaped.is_empty());
544
545 self.result
546 .module
547 .table_initialization
548 .segments
549 .push(TableSegment {
550 table_index,
551 offset,
552 elements,
553 });
554 }
555
556 ElementKind::Passive => {
557 let elem_index = ElemIndex::from_u32(index as u32);
558 let index = self.result.module.passive_elements.len();
559 self.result.module.passive_elements.push(elements);
560 self.result
561 .module
562 .passive_elements_map
563 .insert(elem_index, index);
564 }
565
566 ElementKind::Declared => {}
567 }
568 }
569 }
570
571 Payload::CodeSectionStart { count, range, .. } => {
572 self.validator.code_section_start(&range)?;
573 let cnt = usize::try_from(count).unwrap();
574 self.result.function_body_inputs.reserve_exact(cnt);
575 self.result.debuginfo.wasm_file.code_section_offset = range.start as u64;
576 }
577
578 Payload::CodeSectionEntry(body) => {
579 let validator = self.validator.code_section_entry(&body)?;
580 let func_index =
581 self.result.code_index + self.result.module.num_imported_funcs as u32;
582 let func_index = FuncIndex::from_u32(func_index);
583
584 if self.tunables.generate_native_debuginfo {
585 let sig_index = self.result.module.functions[func_index]
586 .signature
587 .unwrap_module_type_index();
588 let sig = self.types[sig_index].unwrap_func();
589 let mut locals = Vec::new();
590 for pair in body.get_locals_reader()? {
591 let (cnt, ty) = pair?;
592 let ty = self.convert_valtype(ty)?;
593 locals.push((cnt, ty));
594 }
595 self.result
596 .debuginfo
597 .wasm_file
598 .funcs
599 .push(FunctionMetadata {
600 locals: locals.into_boxed_slice(),
601 params: sig.params().into(),
602 });
603 }
604 self.result
605 .function_body_inputs
606 .push(FunctionBodyData { validator, body });
607 self.result.code_index += 1;
608 }
609
610 Payload::DataSection(data) => {
611 self.validator.data_section(&data)?;
612
613 let initializers = match &mut self.result.module.memory_initialization {
614 MemoryInitialization::Segmented(i) => i,
615 _ => unreachable!(),
616 };
617
618 let cnt = usize::try_from(data.count()).unwrap();
619 initializers.reserve_exact(cnt);
620 self.result.data.reserve_exact(cnt);
621
622 for (index, entry) in data.into_iter().enumerate() {
623 let wasmparser::Data {
624 kind,
625 data,
626 range: _,
627 } = entry?;
628 let mk_range = |total: &mut u32| -> Result<_, WasmError> {
629 let range = u32::try_from(data.len())
630 .ok()
631 .and_then(|size| {
632 let start = *total;
633 let end = start.checked_add(size)?;
634 Some(start..end)
635 })
636 .ok_or_else(|| {
637 WasmError::Unsupported(format!(
638 "more than 4 gigabytes of data in wasm module",
639 ))
640 })?;
641 *total += range.end - range.start;
642 Ok(range)
643 };
644 match kind {
645 DataKind::Active {
646 memory_index,
647 offset_expr,
648 } => {
649 let range = mk_range(&mut self.result.total_data)?;
650 let memory_index = MemoryIndex::from_u32(memory_index);
651 let (offset, escaped) = ConstExpr::from_wasmparser(self, offset_expr)?;
652 debug_assert!(escaped.is_empty());
653
654 let initializers = match &mut self.result.module.memory_initialization {
655 MemoryInitialization::Segmented(i) => i,
656 _ => unreachable!(),
657 };
658 initializers.push(MemoryInitializer {
659 memory_index,
660 offset,
661 data: range,
662 });
663 self.result.data.push(data.into());
664 }
665 DataKind::Passive => {
666 let data_index = DataIndex::from_u32(index as u32);
667 let range = mk_range(&mut self.result.total_passive_data)?;
668 self.result.passive_data.push(data);
669 self.result
670 .module
671 .passive_data_map
672 .insert(data_index, range);
673 }
674 }
675 }
676 }
677
678 Payload::DataCountSection { count, range } => {
679 self.validator.data_count_section(count, &range)?;
680
681 }
687
688 Payload::CustomSection(s)
689 if s.name() == "webidl-bindings" || s.name() == "wasm-interface-types" =>
690 {
691 bail!(
692 "\
693Support for interface types has temporarily been removed from `wasmtime`.
694
695For more information about this temporary change you can read on the issue online:
696
697 https://github.com/bytecodealliance/wasmtime/issues/1271
698
699and for re-adding support for interface types you can see this issue:
700
701 https://github.com/bytecodealliance/wasmtime/issues/677
702"
703 )
704 }
705
706 Payload::CustomSection(s) => {
707 self.register_custom_section(&s);
708 }
709
710 other => {
715 self.validator.payload(&other)?;
716 panic!("unimplemented section in wasm file {other:?}");
717 }
718 }
719 Ok(())
720 }
721
722 fn register_custom_section(&mut self, section: &CustomSectionReader<'data>) {
723 match section.as_known() {
724 KnownCustom::Name(name) => {
725 let result = self.name_section(name);
726 if let Err(e) = result {
727 log::warn!("failed to parse name section {e:?}");
728 }
729 }
730 _ => {
731 let name = section.name().trim_end_matches(".dwo");
732 if name.starts_with(".debug_") {
733 self.dwarf_section(name, section);
734 }
735 }
736 }
737 }
738
739 fn dwarf_section(&mut self, name: &str, section: &CustomSectionReader<'data>) {
740 if !self.tunables.generate_native_debuginfo && !self.tunables.parse_wasm_debuginfo {
741 self.result.has_unparsed_debuginfo = true;
742 return;
743 }
744 let info = &mut self.result.debuginfo;
745 let dwarf = &mut info.dwarf;
746 let endian = gimli::LittleEndian;
747 let data = section.data();
748 let slice = gimli::EndianSlice::new(data, endian);
749
750 match name {
751 ".debug_abbrev" => dwarf.debug_abbrev = gimli::DebugAbbrev::new(data, endian),
753 ".debug_addr" => dwarf.debug_addr = gimli::DebugAddr::from(slice),
754 ".debug_info" => {
755 dwarf.debug_info = gimli::DebugInfo::new(data, endian);
756 }
757 ".debug_line" => dwarf.debug_line = gimli::DebugLine::new(data, endian),
758 ".debug_line_str" => dwarf.debug_line_str = gimli::DebugLineStr::from(slice),
759 ".debug_str" => dwarf.debug_str = gimli::DebugStr::new(data, endian),
760 ".debug_str_offsets" => dwarf.debug_str_offsets = gimli::DebugStrOffsets::from(slice),
761 ".debug_str_sup" => {
762 let mut dwarf_sup: Dwarf<'data> = Default::default();
763 dwarf_sup.debug_str = gimli::DebugStr::from(slice);
764 dwarf.sup = Some(Arc::new(dwarf_sup));
765 }
766 ".debug_types" => dwarf.debug_types = gimli::DebugTypes::from(slice),
767
768 ".debug_loc" => info.debug_loc = gimli::DebugLoc::from(slice),
770 ".debug_loclists" => info.debug_loclists = gimli::DebugLocLists::from(slice),
771 ".debug_ranges" => info.debug_ranges = gimli::DebugRanges::new(data, endian),
772 ".debug_rnglists" => info.debug_rnglists = gimli::DebugRngLists::new(data, endian),
773
774 ".debug_cu_index" => info.debug_cu_index = gimli::DebugCuIndex::new(data, endian),
776 ".debug_tu_index" => info.debug_tu_index = gimli::DebugTuIndex::new(data, endian),
777
778 ".debug_aranges" | ".debug_pubnames" | ".debug_pubtypes" => return,
780 other => {
781 log::warn!("unknown debug section `{other}`");
782 return;
783 }
784 }
785
786 dwarf.ranges = gimli::RangeLists::new(info.debug_ranges, info.debug_rnglists);
787 dwarf.locations = gimli::LocationLists::new(info.debug_loc, info.debug_loclists);
788 }
789
790 fn declare_import(&mut self, module: &'data str, field: &'data str, ty: EntityType) {
803 let index = self.push_type(ty);
804 self.result.module.initializers.push(Initializer::Import {
805 name: module.to_owned(),
806 field: field.to_owned(),
807 index,
808 });
809 }
810
811 fn push_type(&mut self, ty: EntityType) -> EntityIndex {
812 match ty {
813 EntityType::Function(ty) => EntityIndex::Function({
814 let func_index = self
815 .result
816 .module
817 .push_function(ty.unwrap_module_type_index());
818 self.flag_func_escaped(func_index);
821 func_index
822 }),
823 EntityType::Table(ty) => EntityIndex::Table(self.result.module.tables.push(ty)),
824 EntityType::Memory(ty) => EntityIndex::Memory(self.result.module.memories.push(ty)),
825 EntityType::Global(ty) => EntityIndex::Global(self.result.module.globals.push(ty)),
826 EntityType::Tag(ty) => EntityIndex::Tag(self.result.module.tags.push(ty)),
827 }
828 }
829
830 fn flag_func_escaped(&mut self, func: FuncIndex) {
831 let ty = &mut self.result.module.functions[func];
832 if ty.is_escaping() {
834 return;
835 }
836 let index = self.result.module.num_escaped_funcs as u32;
837 ty.func_ref = FuncRefIndex::from_u32(index);
838 self.result.module.num_escaped_funcs += 1;
839 }
840
841 fn name_section(&mut self, names: NameSectionReader<'data>) -> WasmResult<()> {
843 for subsection in names {
844 match subsection? {
845 wasmparser::Name::Function(names) => {
846 for name in names {
847 let Naming { index, name } = name?;
848 if (index as usize) >= self.result.module.functions.len() {
851 continue;
852 }
853
854 let index = FuncIndex::from_u32(index);
859 self.result
860 .debuginfo
861 .name_section
862 .func_names
863 .insert(index, name);
864 }
865 }
866 wasmparser::Name::Module { name, .. } => {
867 self.result.module.name = Some(name.to_string());
868 if self.tunables.generate_native_debuginfo {
869 self.result.debuginfo.name_section.module_name = Some(name);
870 }
871 }
872 wasmparser::Name::Local(reader) => {
873 if !self.tunables.generate_native_debuginfo {
874 continue;
875 }
876 for f in reader {
877 let f = f?;
878 if (f.index as usize) >= self.result.module.functions.len() {
881 continue;
882 }
883 for name in f.names {
884 let Naming { index, name } = name?;
885
886 self.result
887 .debuginfo
888 .name_section
889 .locals_names
890 .entry(FuncIndex::from_u32(f.index))
891 .or_insert(HashMap::new())
892 .insert(index, name);
893 }
894 }
895 }
896 wasmparser::Name::Label(_)
897 | wasmparser::Name::Type(_)
898 | wasmparser::Name::Table(_)
899 | wasmparser::Name::Global(_)
900 | wasmparser::Name::Memory(_)
901 | wasmparser::Name::Element(_)
902 | wasmparser::Name::Data(_)
903 | wasmparser::Name::Tag(_)
904 | wasmparser::Name::Field(_)
905 | wasmparser::Name::Unknown { .. } => {}
906 }
907 }
908 Ok(())
909 }
910}
911
912impl TypeConvert for ModuleEnvironment<'_, '_> {
913 fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType {
914 WasmparserTypeConverter::new(&self.types, |idx| {
915 self.result.module.types[idx].unwrap_module_type_index()
916 })
917 .lookup_heap_type(index)
918 }
919
920 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex {
921 WasmparserTypeConverter::new(&self.types, |idx| {
922 self.result.module.types[idx].unwrap_module_type_index()
923 })
924 .lookup_type_index(index)
925 }
926}
927
928impl ModuleTranslation<'_> {
929 pub fn try_static_init(&mut self, page_size: u64, max_image_size_always_allowed: u64) {
960 if !self.module.memory_initialization.is_segmented() {
963 return;
964 }
965
966 struct Memory {
970 data_size: u64,
971 min_addr: u64,
972 max_addr: u64,
973 segments: Vec<(usize, StaticMemoryInitializer)>,
977 }
978 let mut info = PrimaryMap::with_capacity(self.module.memories.len());
979 for _ in 0..self.module.memories.len() {
980 info.push(Memory {
981 data_size: 0,
982 min_addr: u64::MAX,
983 max_addr: 0,
984 segments: Vec::new(),
985 });
986 }
987
988 struct InitMemoryAtCompileTime<'a> {
989 module: &'a Module,
990 info: &'a mut PrimaryMap<MemoryIndex, Memory>,
991 idx: usize,
992 }
993 impl InitMemory for InitMemoryAtCompileTime<'_> {
994 fn memory_size_in_bytes(
995 &mut self,
996 memory_index: MemoryIndex,
997 ) -> Result<u64, SizeOverflow> {
998 self.module.memories[memory_index].minimum_byte_size()
999 }
1000
1001 fn eval_offset(&mut self, memory_index: MemoryIndex, expr: &ConstExpr) -> Option<u64> {
1002 match (expr.ops(), self.module.memories[memory_index].idx_type) {
1003 (&[ConstOp::I32Const(offset)], IndexType::I32) => {
1004 Some(offset.cast_unsigned().into())
1005 }
1006 (&[ConstOp::I64Const(offset)], IndexType::I64) => Some(offset.cast_unsigned()),
1007 _ => None,
1008 }
1009 }
1010
1011 fn write(&mut self, memory: MemoryIndex, init: &StaticMemoryInitializer) -> bool {
1012 if self.module.defined_memory_index(memory).is_none() {
1017 return false;
1018 };
1019 let info = &mut self.info[memory];
1020 let data_len = u64::from(init.data.end - init.data.start);
1021 if data_len > 0 {
1022 info.data_size += data_len;
1023 info.min_addr = info.min_addr.min(init.offset);
1024 info.max_addr = info.max_addr.max(init.offset + data_len);
1025 info.segments.push((self.idx, init.clone()));
1026 }
1027 self.idx += 1;
1028 true
1029 }
1030 }
1031 let ok = self
1032 .module
1033 .memory_initialization
1034 .init_memory(&mut InitMemoryAtCompileTime {
1035 idx: 0,
1036 module: &self.module,
1037 info: &mut info,
1038 });
1039 if !ok {
1040 return;
1041 }
1042
1043 for (i, info) in info.iter().filter(|(_, info)| info.data_size > 0) {
1046 let image_size = info.max_addr - info.min_addr;
1047
1048 if self.module.memories[i].page_size() < page_size {
1056 return;
1057 }
1058
1059 if image_size < info.data_size.saturating_mul(2) {
1066 continue;
1067 }
1068
1069 if image_size < max_image_size_always_allowed {
1073 continue;
1074 }
1075
1076 return;
1080 }
1081
1082 let data = mem::replace(&mut self.data, Vec::new());
1086 let mut map = PrimaryMap::with_capacity(info.len());
1087 let mut module_data_size = 0u32;
1088 for (memory, info) in info.iter() {
1089 let extent = if info.segments.len() > 0 {
1092 (info.max_addr - info.min_addr) as usize
1093 } else {
1094 0
1095 };
1096 let mut image = Vec::with_capacity(extent);
1097 for (idx, init) in info.segments.iter() {
1098 let data = &data[*idx];
1099 assert_eq!(data.len(), init.data.len());
1100 let offset = usize::try_from(init.offset - info.min_addr).unwrap();
1101 if image.len() < offset {
1102 image.resize(offset, 0u8);
1103 image.extend_from_slice(data);
1104 } else {
1105 image.splice(
1106 offset..(offset + data.len()).min(image.len()),
1107 data.iter().copied(),
1108 );
1109 }
1110 }
1111 assert_eq!(image.len(), extent);
1112 assert_eq!(image.capacity(), extent);
1113 let mut offset = if info.segments.len() > 0 {
1114 info.min_addr
1115 } else {
1116 0
1117 };
1118
1119 if let Some(i) = image.iter().rposition(|i| *i != 0) {
1123 image.truncate(i + 1);
1124 }
1125
1126 if let Some(i) = image.iter().position(|i| *i != 0) {
1128 offset += i as u64;
1129 image.drain(..i);
1130 }
1131 let mut len = u64::try_from(image.len()).unwrap();
1132
1133 if offset % page_size != 0 {
1138 let zero_padding = offset % page_size;
1139 self.data.push(vec![0; zero_padding as usize].into());
1140 offset -= zero_padding;
1141 len += zero_padding;
1142 }
1143 self.data.push(image.into());
1144 if len % page_size != 0 {
1145 let zero_padding = page_size - (len % page_size);
1146 self.data.push(vec![0; zero_padding as usize].into());
1147 len += zero_padding;
1148 }
1149
1150 assert!(offset % page_size == 0);
1152 assert!(len % page_size == 0);
1153
1154 let len = u32::try_from(len).unwrap();
1162 let init = if len > 0 {
1163 Some(StaticMemoryInitializer {
1164 offset,
1165 data: module_data_size..module_data_size + len,
1166 })
1167 } else {
1168 None
1169 };
1170 let idx = map.push(init);
1171 assert_eq!(idx, memory);
1172 module_data_size += len;
1173 }
1174 self.data_align = Some(page_size);
1175 self.module.memory_initialization = MemoryInitialization::Static { map };
1176 }
1177
1178 pub fn try_func_table_init(&mut self) {
1183 const MAX_FUNC_TABLE_SIZE: u64 = 1024 * 1024;
1187
1188 for ((_, init), (_, table)) in self
1191 .module
1192 .table_initialization
1193 .initial_values
1194 .iter_mut()
1195 .zip(
1196 self.module
1197 .tables
1198 .iter()
1199 .skip(self.module.num_imported_tables),
1200 )
1201 {
1202 let table_size = table.limits.min;
1203 if table_size > MAX_FUNC_TABLE_SIZE {
1204 continue;
1205 }
1206 if let TableInitialValue::Expr(expr) = init {
1207 if let [ConstOp::RefFunc(f)] = expr.ops() {
1208 *init = TableInitialValue::Null {
1209 precomputed: vec![*f; table_size as usize],
1210 };
1211 }
1212 }
1213 }
1214
1215 let mut segments = mem::take(&mut self.module.table_initialization.segments)
1216 .into_iter()
1217 .peekable();
1218
1219 while let Some(segment) = segments.peek() {
1231 let defined_index = match self.module.defined_table_index(segment.table_index) {
1232 Some(index) => index,
1233 None => break,
1237 };
1238
1239 let offset = match segment.offset.ops() {
1243 &[ConstOp::I32Const(offset)] => u64::from(offset.cast_unsigned()),
1244 &[ConstOp::I64Const(offset)] => offset.cast_unsigned(),
1245 _ => break,
1246 };
1247
1248 let top = match offset.checked_add(segment.elements.len()) {
1252 Some(top) => top,
1253 None => break,
1254 };
1255 let table_size = self.module.tables[segment.table_index].limits.min;
1256 if top > table_size || top > MAX_FUNC_TABLE_SIZE {
1257 break;
1258 }
1259
1260 match self.module.tables[segment.table_index]
1261 .ref_type
1262 .heap_type
1263 .top()
1264 {
1265 WasmHeapTopType::Func => {}
1266 WasmHeapTopType::Any
1272 | WasmHeapTopType::Extern
1273 | WasmHeapTopType::Cont
1274 | WasmHeapTopType::Exn => break,
1275 }
1276
1277 let function_elements = match &segment.elements {
1280 TableSegmentElements::Functions(indices) => indices,
1281 TableSegmentElements::Expressions(_) => break,
1282 };
1283
1284 let precomputed =
1285 match &mut self.module.table_initialization.initial_values[defined_index] {
1286 TableInitialValue::Null { precomputed } => precomputed,
1287
1288 TableInitialValue::Expr(_) => break,
1295 };
1296
1297 if precomputed.len() < top as usize {
1303 precomputed.resize(top as usize, FuncIndex::reserved_value());
1304 }
1305 let dst = &mut precomputed[offset as usize..top as usize];
1306 dst.copy_from_slice(&function_elements);
1307
1308 let _ = segments.next();
1310 }
1311 self.module.table_initialization.segments = segments.collect();
1312 }
1313}