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
28pub struct ModuleEnvironment<'a, 'data> {
30 result: ModuleTranslation<'data>,
32
33 types: &'a mut ModuleTypesBuilder,
35
36 validator: &'a mut Validator,
38 tunables: &'a Tunables,
39}
40
41pub struct ModuleTranslation<'data> {
46 pub module: Module,
48
49 pub wasm: &'data [u8],
55
56 pub wasm_module_offset: u64,
61
62 pub function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
64
65 pub known_imported_functions: SecondaryMap<FuncIndex, Option<FuncKey>>,
74
75 pub exported_signatures: Vec<ModuleInternedTypeIndex>,
79
80 pub debuginfo: DebugInfoData<'data>,
82
83 pub has_unparsed_debuginfo: bool,
86
87 pub data: Vec<Cow<'data, [u8]>>,
93
94 pub data_align: Option<u64>,
101
102 total_data: u32,
104
105 pub passive_data: Vec<&'data [u8]>,
108
109 total_passive_data: u32,
111
112 code_index: u32,
115
116 types: Option<Types>,
119}
120
121impl<'data> ModuleTranslation<'data> {
122 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 pub fn get_types(&self) -> &Types {
145 self.types
146 .as_ref()
147 .expect("module type information to be available")
148 }
149
150 pub fn module_index(&self) -> StaticModuleIndex {
152 self.module.module_index
153 }
154}
155
156pub struct FunctionBodyData<'a> {
158 pub body: FunctionBody<'a>,
160 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 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 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 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 let mut type_index = 0;
304 while type_index < count {
305 let validator_types = self.validator.types(0).unwrap();
306
307 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 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 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 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 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 }
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 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 ".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 ".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 ".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 ".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 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 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 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 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 if (index as usize) >= self.result.module.functions.len() {
889 continue;
890 }
891
892 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 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 pub fn try_static_init(&mut self, page_size: u64, max_image_size_always_allowed: u64) {
999 if !self.module.memory_initialization.is_segmented() {
1002 return;
1003 }
1004
1005 struct Memory {
1009 data_size: u64,
1010 min_addr: u64,
1011 max_addr: u64,
1012 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 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 for (i, info) in info.iter().filter(|(_, info)| info.data_size > 0) {
1085 let image_size = info.max_addr - info.min_addr;
1086
1087 if self.module.memories[i].page_size() < page_size {
1095 return;
1096 }
1097
1098 if image_size < info.data_size.saturating_mul(2) {
1105 continue;
1106 }
1107
1108 if image_size < max_image_size_always_allowed {
1112 continue;
1113 }
1114
1115 return;
1119 }
1120
1121 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 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 if let Some(i) = image.iter().rposition(|i| *i != 0) {
1162 image.truncate(i + 1);
1163 }
1164
1165 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 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 assert!(offset % page_size == 0);
1191 assert!(len % page_size == 0);
1192
1193 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 pub fn try_func_table_init(&mut self) {
1222 const MAX_FUNC_TABLE_SIZE: u64 = 1024 * 1024;
1226
1227 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 while let Some(segment) = segments.peek() {
1270 let defined_index = match self.module.defined_table_index(segment.table_index) {
1271 Some(index) => index,
1272 None => break,
1276 };
1277
1278 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 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 WasmHeapTopType::Any
1311 | WasmHeapTopType::Extern
1312 | WasmHeapTopType::Cont
1313 | WasmHeapTopType::Exn => break,
1314 }
1315
1316 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 TableInitialValue::Expr(_) => break,
1334 };
1335
1336 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 let _ = segments.next();
1351 }
1352 self.module.table_initialization.segments = segments.try_collect().panic_on_oom();
1353 }
1354}