1use crate::module::{
2 FuncRefIndex, Initializer, MemoryInitialization, MemoryInitializer, Module, TableSegment,
3 TableSegmentElements,
4};
5use crate::prelude::*;
6use crate::{
7 ConstExpr, ConstOp, DataIndex, DefinedFuncIndex, ElemIndex, EngineOrModuleTypeIndex,
8 EntityIndex, EntityType, FuncIndex, GlobalIndex, IndexType, InitMemory, MemoryIndex,
9 ModuleInternedTypeIndex, ModuleTypesBuilder, PrimaryMap, SizeOverflow, StaticMemoryInitializer,
10 TableIndex, TableInitialValue, Tag, TagIndex, Tunables, TypeConvert, TypeIndex, Unsigned,
11 WasmError, WasmHeapTopType, WasmHeapType, WasmResult, WasmValType, WasmparserTypeConverter,
12};
13use anyhow::{bail, Result};
14use cranelift_entity::packed_option::ReservedValue;
15use std::borrow::Cow;
16use std::collections::HashMap;
17use std::mem;
18use std::path::PathBuf;
19use std::sync::Arc;
20use wasmparser::{
21 types::Types, CustomSectionReader, DataKind, ElementItems, ElementKind, Encoding, ExternalKind,
22 FuncToValidate, FunctionBody, KnownCustom, NameSectionReader, Naming, Parser, Payload, TypeRef,
23 Validator, ValidatorResources,
24};
25
26pub struct ModuleEnvironment<'a, 'data> {
28 result: ModuleTranslation<'data>,
30
31 types: &'a mut ModuleTypesBuilder,
33
34 validator: &'a mut Validator,
36 tunables: &'a Tunables,
37}
38
39#[derive(Default)]
43pub struct ModuleTranslation<'data> {
44 pub module: Module,
46
47 pub wasm: &'data [u8],
53
54 pub function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
56
57 pub exported_signatures: Vec<ModuleInternedTypeIndex>,
61
62 pub debuginfo: DebugInfoData<'data>,
64
65 pub has_unparsed_debuginfo: bool,
68
69 pub data: Vec<Cow<'data, [u8]>>,
75
76 pub data_align: Option<u64>,
83
84 total_data: u32,
86
87 pub passive_data: Vec<&'data [u8]>,
90
91 total_passive_data: u32,
93
94 code_index: u32,
97
98 types: Option<Types>,
101}
102
103impl<'data> ModuleTranslation<'data> {
104 pub fn get_types(&self) -> &Types {
106 self.types
107 .as_ref()
108 .expect("module type information to be available")
109 }
110}
111
112pub struct FunctionBodyData<'a> {
114 pub body: FunctionBody<'a>,
116 pub validator: FuncToValidate<ValidatorResources>,
118}
119
120#[derive(Debug, Default)]
121#[allow(missing_docs, reason = "self-describing fields")]
122pub struct DebugInfoData<'a> {
123 pub dwarf: Dwarf<'a>,
124 pub name_section: NameSection<'a>,
125 pub wasm_file: WasmFileInfo,
126 pub debug_loc: gimli::DebugLoc<Reader<'a>>,
127 pub debug_loclists: gimli::DebugLocLists<Reader<'a>>,
128 pub debug_ranges: gimli::DebugRanges<Reader<'a>>,
129 pub debug_rnglists: gimli::DebugRngLists<Reader<'a>>,
130 pub debug_cu_index: gimli::DebugCuIndex<Reader<'a>>,
131 pub debug_tu_index: gimli::DebugTuIndex<Reader<'a>>,
132}
133
134#[allow(missing_docs, reason = "self-describing")]
135pub type Dwarf<'input> = gimli::Dwarf<Reader<'input>>;
136
137type Reader<'input> = gimli::EndianSlice<'input, gimli::LittleEndian>;
138
139#[derive(Debug, Default)]
140#[allow(missing_docs, reason = "self-describing fields")]
141pub struct NameSection<'a> {
142 pub module_name: Option<&'a str>,
143 pub func_names: HashMap<FuncIndex, &'a str>,
144 pub locals_names: HashMap<FuncIndex, HashMap<u32, &'a str>>,
145}
146
147#[derive(Debug, Default)]
148#[allow(missing_docs, reason = "self-describing fields")]
149pub struct WasmFileInfo {
150 pub path: Option<PathBuf>,
151 pub code_section_offset: u64,
152 pub imported_func_count: u32,
153 pub funcs: Vec<FunctionMetadata>,
154}
155
156#[derive(Debug)]
157#[allow(missing_docs, reason = "self-describing fields")]
158pub struct FunctionMetadata {
159 pub params: Box<[WasmValType]>,
160 pub locals: Box<[(u32, WasmValType)]>,
161}
162
163impl<'a, 'data> ModuleEnvironment<'a, 'data> {
164 pub fn new(
166 tunables: &'a Tunables,
167 validator: &'a mut Validator,
168 types: &'a mut ModuleTypesBuilder,
169 ) -> Self {
170 Self {
171 result: ModuleTranslation::default(),
172 types,
173 tunables,
174 validator,
175 }
176 }
177
178 pub fn translate(
187 mut self,
188 parser: Parser,
189 data: &'data [u8],
190 ) -> Result<ModuleTranslation<'data>> {
191 self.result.wasm = data;
192
193 for payload in parser.parse_all(data) {
194 self.translate_payload(payload?)?;
195 }
196
197 Ok(self.result)
198 }
199
200 fn translate_payload(&mut self, payload: Payload<'data>) -> Result<()> {
201 match payload {
202 Payload::Version {
203 num,
204 encoding,
205 range,
206 } => {
207 self.validator.version(num, encoding, &range)?;
208 match encoding {
209 Encoding::Module => {}
210 Encoding::Component => {
211 bail!("expected a WebAssembly module but was given a WebAssembly component")
212 }
213 }
214 }
215
216 Payload::End(offset) => {
217 self.result.types = Some(self.validator.end(offset)?);
218
219 self.result.exported_signatures = self
223 .result
224 .module
225 .functions
226 .iter()
227 .filter_map(|(_, func)| {
228 if func.is_escaping() {
229 Some(func.signature.unwrap_module_type_index())
230 } else {
231 None
232 }
233 })
234 .collect();
235 self.result.exported_signatures.sort_unstable();
236 self.result.exported_signatures.dedup();
237 }
238
239 Payload::TypeSection(types) => {
240 self.validator.type_section(&types)?;
241
242 let count = self.validator.types(0).unwrap().core_type_count_in_module();
243 log::trace!("interning {count} Wasm types");
244
245 let capacity = usize::try_from(count).unwrap();
246 self.result.module.types.reserve(capacity);
247 self.types.reserve_wasm_signatures(capacity);
248
249 let mut type_index = 0;
259 while type_index < count {
260 let validator_types = self.validator.types(0).unwrap();
261
262 log::trace!("looking up wasmparser type for index {type_index}");
265 let core_type_id = validator_types.core_type_at_in_module(type_index);
266 log::trace!(
267 " --> {core_type_id:?} = {:?}",
268 validator_types[core_type_id],
269 );
270 let rec_group_id = validator_types.rec_group_id_of(core_type_id);
271 debug_assert_eq!(
272 validator_types
273 .rec_group_elements(rec_group_id)
274 .position(|id| id == core_type_id),
275 Some(0)
276 );
277
278 let interned = self.types.intern_rec_group(validator_types, rec_group_id)?;
281 let elems = self.types.rec_group_elements(interned);
282 let len = elems.len();
283 self.result.module.types.reserve(len);
284 for ty in elems {
285 self.result.module.types.push(ty.into());
286 }
287
288 type_index += u32::try_from(len).unwrap();
290 }
291 }
292
293 Payload::ImportSection(imports) => {
294 self.validator.import_section(&imports)?;
295
296 let cnt = usize::try_from(imports.count()).unwrap();
297 self.result.module.initializers.reserve(cnt);
298
299 for entry in imports {
300 let import = entry?;
301 let ty = match import.ty {
302 TypeRef::Func(index) => {
303 let index = TypeIndex::from_u32(index);
304 let interned_index = self.result.module.types[index];
305 self.result.module.num_imported_funcs += 1;
306 self.result.debuginfo.wasm_file.imported_func_count += 1;
307 EntityType::Function(interned_index)
308 }
309 TypeRef::Memory(ty) => {
310 self.result.module.num_imported_memories += 1;
311 EntityType::Memory(ty.into())
312 }
313 TypeRef::Global(ty) => {
314 self.result.module.num_imported_globals += 1;
315 EntityType::Global(self.convert_global_type(&ty))
316 }
317 TypeRef::Table(ty) => {
318 self.result.module.num_imported_tables += 1;
319 EntityType::Table(self.convert_table_type(&ty)?)
320 }
321 TypeRef::Tag(ty) => {
322 let index = TypeIndex::from_u32(ty.func_type_idx);
323 let signature = self.result.module.types[index];
324 let tag = Tag { signature };
325 self.result.module.num_imported_tags += 1;
326 EntityType::Tag(tag)
327 }
328 };
329 self.declare_import(import.module, import.name, ty);
330 }
331 }
332
333 Payload::FunctionSection(functions) => {
334 self.validator.function_section(&functions)?;
335
336 let cnt = usize::try_from(functions.count()).unwrap();
337 self.result.module.functions.reserve_exact(cnt);
338
339 for entry in functions {
340 let sigindex = entry?;
341 let ty = TypeIndex::from_u32(sigindex);
342 let interned_index = self.result.module.types[ty];
343 self.result.module.push_function(interned_index);
344 }
345 }
346
347 Payload::TableSection(tables) => {
348 self.validator.table_section(&tables)?;
349 let cnt = usize::try_from(tables.count()).unwrap();
350 self.result.module.tables.reserve_exact(cnt);
351
352 for entry in tables {
353 let wasmparser::Table { ty, init } = entry?;
354 let table = self.convert_table_type(&ty)?;
355 self.result.module.tables.push(table);
356 let init = match init {
357 wasmparser::TableInit::RefNull => TableInitialValue::Null {
358 precomputed: Vec::new(),
359 },
360 wasmparser::TableInit::Expr(expr) => {
361 let (init, escaped) = ConstExpr::from_wasmparser(expr)?;
362 for f in escaped {
363 self.flag_func_escaped(f);
364 }
365 TableInitialValue::Expr(init)
366 }
367 };
368 self.result
369 .module
370 .table_initialization
371 .initial_values
372 .push(init);
373 }
374 }
375
376 Payload::MemorySection(memories) => {
377 self.validator.memory_section(&memories)?;
378
379 let cnt = usize::try_from(memories.count()).unwrap();
380 self.result.module.memories.reserve_exact(cnt);
381
382 for entry in memories {
383 let memory = entry?;
384 self.result.module.memories.push(memory.into());
385 }
386 }
387
388 Payload::TagSection(tags) => {
389 self.validator.tag_section(&tags)?;
390
391 for entry in tags {
392 let sigindex = entry?.func_type_idx;
393 let ty = TypeIndex::from_u32(sigindex);
394 let interned_index = self.result.module.types[ty];
395 self.result.module.push_tag(interned_index);
396 }
397 }
398
399 Payload::GlobalSection(globals) => {
400 self.validator.global_section(&globals)?;
401
402 let cnt = usize::try_from(globals.count()).unwrap();
403 self.result.module.globals.reserve_exact(cnt);
404
405 for entry in globals {
406 let wasmparser::Global { ty, init_expr } = entry?;
407 let (initializer, escaped) = ConstExpr::from_wasmparser(init_expr)?;
408 for f in escaped {
409 self.flag_func_escaped(f);
410 }
411 let ty = self.convert_global_type(&ty);
412 self.result.module.globals.push(ty);
413 self.result.module.global_initializers.push(initializer);
414 }
415 }
416
417 Payload::ExportSection(exports) => {
418 self.validator.export_section(&exports)?;
419
420 let cnt = usize::try_from(exports.count()).unwrap();
421 self.result.module.exports.reserve(cnt);
422
423 for entry in exports {
424 let wasmparser::Export { name, kind, index } = entry?;
425 let entity = match kind {
426 ExternalKind::Func => {
427 let index = FuncIndex::from_u32(index);
428 self.flag_func_escaped(index);
429 EntityIndex::Function(index)
430 }
431 ExternalKind::Table => EntityIndex::Table(TableIndex::from_u32(index)),
432 ExternalKind::Memory => EntityIndex::Memory(MemoryIndex::from_u32(index)),
433 ExternalKind::Global => EntityIndex::Global(GlobalIndex::from_u32(index)),
434 ExternalKind::Tag => EntityIndex::Tag(TagIndex::from_u32(index)),
435 };
436 self.result
437 .module
438 .exports
439 .insert(String::from(name), entity);
440 }
441 }
442
443 Payload::StartSection { func, range } => {
444 self.validator.start_section(func, &range)?;
445
446 let func_index = FuncIndex::from_u32(func);
447 self.flag_func_escaped(func_index);
448 debug_assert!(self.result.module.start_func.is_none());
449 self.result.module.start_func = Some(func_index);
450 }
451
452 Payload::ElementSection(elements) => {
453 self.validator.element_section(&elements)?;
454
455 for (index, entry) in elements.into_iter().enumerate() {
456 let wasmparser::Element {
457 kind,
458 items,
459 range: _,
460 } = entry?;
461
462 let elements = match items {
468 ElementItems::Functions(funcs) => {
469 let mut elems =
470 Vec::with_capacity(usize::try_from(funcs.count()).unwrap());
471 for func in funcs {
472 let func = FuncIndex::from_u32(func?);
473 self.flag_func_escaped(func);
474 elems.push(func);
475 }
476 TableSegmentElements::Functions(elems.into())
477 }
478 ElementItems::Expressions(_ty, items) => {
479 let mut exprs =
480 Vec::with_capacity(usize::try_from(items.count()).unwrap());
481 for expr in items {
482 let (expr, escaped) = ConstExpr::from_wasmparser(expr?)?;
483 exprs.push(expr);
484 for func in escaped {
485 self.flag_func_escaped(func);
486 }
487 }
488 TableSegmentElements::Expressions(exprs.into())
489 }
490 };
491
492 match kind {
493 ElementKind::Active {
494 table_index,
495 offset_expr,
496 } => {
497 let table_index = TableIndex::from_u32(table_index.unwrap_or(0));
498 let (offset, escaped) = ConstExpr::from_wasmparser(offset_expr)?;
499 debug_assert!(escaped.is_empty());
500
501 self.result
502 .module
503 .table_initialization
504 .segments
505 .push(TableSegment {
506 table_index,
507 offset,
508 elements: elements.into(),
509 });
510 }
511
512 ElementKind::Passive => {
513 let elem_index = ElemIndex::from_u32(index as u32);
514 let index = self.result.module.passive_elements.len();
515 self.result.module.passive_elements.push(elements.into());
516 self.result
517 .module
518 .passive_elements_map
519 .insert(elem_index, index);
520 }
521
522 ElementKind::Declared => {}
523 }
524 }
525 }
526
527 Payload::CodeSectionStart { count, range, .. } => {
528 self.validator.code_section_start(count, &range)?;
529 let cnt = usize::try_from(count).unwrap();
530 self.result.function_body_inputs.reserve_exact(cnt);
531 self.result.debuginfo.wasm_file.code_section_offset = range.start as u64;
532 }
533
534 Payload::CodeSectionEntry(body) => {
535 let validator = self.validator.code_section_entry(&body)?;
536 let func_index =
537 self.result.code_index + self.result.module.num_imported_funcs as u32;
538 let func_index = FuncIndex::from_u32(func_index);
539
540 if self.tunables.generate_native_debuginfo {
541 let sig_index = self.result.module.functions[func_index]
542 .signature
543 .unwrap_module_type_index();
544 let sig = self.types[sig_index].unwrap_func();
545 let mut locals = Vec::new();
546 for pair in body.get_locals_reader()? {
547 let (cnt, ty) = pair?;
548 let ty = self.convert_valtype(ty);
549 locals.push((cnt, ty));
550 }
551 self.result
552 .debuginfo
553 .wasm_file
554 .funcs
555 .push(FunctionMetadata {
556 locals: locals.into_boxed_slice(),
557 params: sig.params().into(),
558 });
559 }
560 self.result
561 .function_body_inputs
562 .push(FunctionBodyData { validator, body });
563 self.result.code_index += 1;
564 }
565
566 Payload::DataSection(data) => {
567 self.validator.data_section(&data)?;
568
569 let initializers = match &mut self.result.module.memory_initialization {
570 MemoryInitialization::Segmented(i) => i,
571 _ => unreachable!(),
572 };
573
574 let cnt = usize::try_from(data.count()).unwrap();
575 initializers.reserve_exact(cnt);
576 self.result.data.reserve_exact(cnt);
577
578 for (index, entry) in data.into_iter().enumerate() {
579 let wasmparser::Data {
580 kind,
581 data,
582 range: _,
583 } = entry?;
584 let mk_range = |total: &mut u32| -> Result<_, WasmError> {
585 let range = u32::try_from(data.len())
586 .ok()
587 .and_then(|size| {
588 let start = *total;
589 let end = start.checked_add(size)?;
590 Some(start..end)
591 })
592 .ok_or_else(|| {
593 WasmError::Unsupported(format!(
594 "more than 4 gigabytes of data in wasm module",
595 ))
596 })?;
597 *total += range.end - range.start;
598 Ok(range)
599 };
600 match kind {
601 DataKind::Active {
602 memory_index,
603 offset_expr,
604 } => {
605 let range = mk_range(&mut self.result.total_data)?;
606 let memory_index = MemoryIndex::from_u32(memory_index);
607 let (offset, escaped) = ConstExpr::from_wasmparser(offset_expr)?;
608 debug_assert!(escaped.is_empty());
609
610 initializers.push(MemoryInitializer {
611 memory_index,
612 offset,
613 data: range,
614 });
615 self.result.data.push(data.into());
616 }
617 DataKind::Passive => {
618 let data_index = DataIndex::from_u32(index as u32);
619 let range = mk_range(&mut self.result.total_passive_data)?;
620 self.result.passive_data.push(data);
621 self.result
622 .module
623 .passive_data_map
624 .insert(data_index, range);
625 }
626 }
627 }
628 }
629
630 Payload::DataCountSection { count, range } => {
631 self.validator.data_count_section(count, &range)?;
632
633 }
639
640 Payload::CustomSection(s)
641 if s.name() == "webidl-bindings" || s.name() == "wasm-interface-types" =>
642 {
643 bail!(
644 "\
645Support for interface types has temporarily been removed from `wasmtime`.
646
647For more information about this temporary change you can read on the issue online:
648
649 https://github.com/bytecodealliance/wasmtime/issues/1271
650
651and for re-adding support for interface types you can see this issue:
652
653 https://github.com/bytecodealliance/wasmtime/issues/677
654"
655 )
656 }
657
658 Payload::CustomSection(s) => {
659 self.register_custom_section(&s);
660 }
661
662 other => {
667 self.validator.payload(&other)?;
668 panic!("unimplemented section in wasm file {other:?}");
669 }
670 }
671 Ok(())
672 }
673
674 fn register_custom_section(&mut self, section: &CustomSectionReader<'data>) {
675 match section.as_known() {
676 KnownCustom::Name(name) => {
677 let result = self.name_section(name);
678 if let Err(e) = result {
679 log::warn!("failed to parse name section {:?}", e);
680 }
681 }
682 _ => {
683 let name = section.name().trim_end_matches(".dwo");
684 if name.starts_with(".debug_") {
685 self.dwarf_section(name, section);
686 }
687 }
688 }
689 }
690
691 fn dwarf_section(&mut self, name: &str, section: &CustomSectionReader<'data>) {
692 if !self.tunables.generate_native_debuginfo && !self.tunables.parse_wasm_debuginfo {
693 self.result.has_unparsed_debuginfo = true;
694 return;
695 }
696 let info = &mut self.result.debuginfo;
697 let dwarf = &mut info.dwarf;
698 let endian = gimli::LittleEndian;
699 let data = section.data();
700 let slice = gimli::EndianSlice::new(data, endian);
701
702 match name {
703 ".debug_abbrev" => dwarf.debug_abbrev = gimli::DebugAbbrev::new(data, endian),
705 ".debug_addr" => dwarf.debug_addr = gimli::DebugAddr::from(slice),
706 ".debug_info" => {
707 dwarf.debug_info = gimli::DebugInfo::new(data, endian);
708 }
709 ".debug_line" => dwarf.debug_line = gimli::DebugLine::new(data, endian),
710 ".debug_line_str" => dwarf.debug_line_str = gimli::DebugLineStr::from(slice),
711 ".debug_str" => dwarf.debug_str = gimli::DebugStr::new(data, endian),
712 ".debug_str_offsets" => dwarf.debug_str_offsets = gimli::DebugStrOffsets::from(slice),
713 ".debug_str_sup" => {
714 let mut dwarf_sup: Dwarf<'data> = Default::default();
715 dwarf_sup.debug_str = gimli::DebugStr::from(slice);
716 dwarf.sup = Some(Arc::new(dwarf_sup));
717 }
718 ".debug_types" => dwarf.debug_types = gimli::DebugTypes::from(slice),
719
720 ".debug_loc" => info.debug_loc = gimli::DebugLoc::from(slice),
722 ".debug_loclists" => info.debug_loclists = gimli::DebugLocLists::from(slice),
723 ".debug_ranges" => info.debug_ranges = gimli::DebugRanges::new(data, endian),
724 ".debug_rnglists" => info.debug_rnglists = gimli::DebugRngLists::new(data, endian),
725
726 ".debug_cu_index" => info.debug_cu_index = gimli::DebugCuIndex::new(data, endian),
728 ".debug_tu_index" => info.debug_tu_index = gimli::DebugTuIndex::new(data, endian),
729
730 ".debug_aranges" | ".debug_pubnames" | ".debug_pubtypes" => return,
732 other => {
733 log::warn!("unknown debug section `{}`", other);
734 return;
735 }
736 }
737
738 dwarf.ranges = gimli::RangeLists::new(info.debug_ranges, info.debug_rnglists);
739 dwarf.locations = gimli::LocationLists::new(info.debug_loc, info.debug_loclists);
740 }
741
742 fn declare_import(&mut self, module: &'data str, field: &'data str, ty: EntityType) {
755 let index = self.push_type(ty);
756 self.result.module.initializers.push(Initializer::Import {
757 name: module.to_owned(),
758 field: field.to_owned(),
759 index,
760 });
761 }
762
763 fn push_type(&mut self, ty: EntityType) -> EntityIndex {
764 match ty {
765 EntityType::Function(ty) => EntityIndex::Function({
766 let func_index = self
767 .result
768 .module
769 .push_function(ty.unwrap_module_type_index());
770 self.flag_func_escaped(func_index);
773 func_index
774 }),
775 EntityType::Table(ty) => EntityIndex::Table(self.result.module.tables.push(ty)),
776 EntityType::Memory(ty) => EntityIndex::Memory(self.result.module.memories.push(ty)),
777 EntityType::Global(ty) => EntityIndex::Global(self.result.module.globals.push(ty)),
778 EntityType::Tag(ty) => EntityIndex::Tag(self.result.module.tags.push(ty)),
779 }
780 }
781
782 fn flag_func_escaped(&mut self, func: FuncIndex) {
783 let ty = &mut self.result.module.functions[func];
784 if ty.is_escaping() {
786 return;
787 }
788 let index = self.result.module.num_escaped_funcs as u32;
789 ty.func_ref = FuncRefIndex::from_u32(index);
790 self.result.module.num_escaped_funcs += 1;
791 }
792
793 fn name_section(&mut self, names: NameSectionReader<'data>) -> WasmResult<()> {
795 for subsection in names {
796 match subsection? {
797 wasmparser::Name::Function(names) => {
798 for name in names {
799 let Naming { index, name } = name?;
800 if (index as usize) >= self.result.module.functions.len() {
803 continue;
804 }
805
806 let index = FuncIndex::from_u32(index);
811 self.result
812 .debuginfo
813 .name_section
814 .func_names
815 .insert(index, name);
816 }
817 }
818 wasmparser::Name::Module { name, .. } => {
819 self.result.module.name = Some(name.to_string());
820 if self.tunables.generate_native_debuginfo {
821 self.result.debuginfo.name_section.module_name = Some(name);
822 }
823 }
824 wasmparser::Name::Local(reader) => {
825 if !self.tunables.generate_native_debuginfo {
826 continue;
827 }
828 for f in reader {
829 let f = f?;
830 if (f.index as usize) >= self.result.module.functions.len() {
833 continue;
834 }
835 for name in f.names {
836 let Naming { index, name } = name?;
837
838 self.result
839 .debuginfo
840 .name_section
841 .locals_names
842 .entry(FuncIndex::from_u32(f.index))
843 .or_insert(HashMap::new())
844 .insert(index, name);
845 }
846 }
847 }
848 wasmparser::Name::Label(_)
849 | wasmparser::Name::Type(_)
850 | wasmparser::Name::Table(_)
851 | wasmparser::Name::Global(_)
852 | wasmparser::Name::Memory(_)
853 | wasmparser::Name::Element(_)
854 | wasmparser::Name::Data(_)
855 | wasmparser::Name::Tag(_)
856 | wasmparser::Name::Field(_)
857 | wasmparser::Name::Unknown { .. } => {}
858 }
859 }
860 Ok(())
861 }
862}
863
864impl TypeConvert for ModuleEnvironment<'_, '_> {
865 fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType {
866 WasmparserTypeConverter::new(&self.types, |idx| {
867 self.result.module.types[idx].unwrap_module_type_index()
868 })
869 .lookup_heap_type(index)
870 }
871
872 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex {
873 WasmparserTypeConverter::new(&self.types, |idx| {
874 self.result.module.types[idx].unwrap_module_type_index()
875 })
876 .lookup_type_index(index)
877 }
878}
879
880impl ModuleTranslation<'_> {
881 pub fn try_static_init(&mut self, page_size: u64, max_image_size_always_allowed: u64) {
912 if !self.module.memory_initialization.is_segmented() {
915 return;
916 }
917
918 struct Memory {
922 data_size: u64,
923 min_addr: u64,
924 max_addr: u64,
925 segments: Vec<(usize, StaticMemoryInitializer)>,
929 }
930 let mut info = PrimaryMap::with_capacity(self.module.memories.len());
931 for _ in 0..self.module.memories.len() {
932 info.push(Memory {
933 data_size: 0,
934 min_addr: u64::MAX,
935 max_addr: 0,
936 segments: Vec::new(),
937 });
938 }
939
940 struct InitMemoryAtCompileTime<'a> {
941 module: &'a Module,
942 info: &'a mut PrimaryMap<MemoryIndex, Memory>,
943 idx: usize,
944 }
945 impl InitMemory for InitMemoryAtCompileTime<'_> {
946 fn memory_size_in_bytes(
947 &mut self,
948 memory_index: MemoryIndex,
949 ) -> Result<u64, SizeOverflow> {
950 self.module.memories[memory_index].minimum_byte_size()
951 }
952
953 fn eval_offset(&mut self, memory_index: MemoryIndex, expr: &ConstExpr) -> Option<u64> {
954 match (expr.ops(), self.module.memories[memory_index].idx_type) {
955 (&[ConstOp::I32Const(offset)], IndexType::I32) => {
956 Some(offset.unsigned().into())
957 }
958 (&[ConstOp::I64Const(offset)], IndexType::I64) => Some(offset.unsigned()),
959 _ => None,
960 }
961 }
962
963 fn write(&mut self, memory: MemoryIndex, init: &StaticMemoryInitializer) -> bool {
964 if self.module.defined_memory_index(memory).is_none() {
969 return false;
970 };
971 let info = &mut self.info[memory];
972 let data_len = u64::from(init.data.end - init.data.start);
973 if data_len > 0 {
974 info.data_size += data_len;
975 info.min_addr = info.min_addr.min(init.offset);
976 info.max_addr = info.max_addr.max(init.offset + data_len);
977 info.segments.push((self.idx, init.clone()));
978 }
979 self.idx += 1;
980 true
981 }
982 }
983 let ok = self
984 .module
985 .memory_initialization
986 .init_memory(&mut InitMemoryAtCompileTime {
987 idx: 0,
988 module: &self.module,
989 info: &mut info,
990 });
991 if !ok {
992 return;
993 }
994
995 for (i, info) in info.iter().filter(|(_, info)| info.data_size > 0) {
998 let image_size = info.max_addr - info.min_addr;
999
1000 if self.module.memories[i].page_size() < page_size {
1008 return;
1009 }
1010
1011 if image_size < info.data_size.saturating_mul(2) {
1018 continue;
1019 }
1020
1021 if image_size < max_image_size_always_allowed {
1025 continue;
1026 }
1027
1028 return;
1032 }
1033
1034 let data = mem::replace(&mut self.data, Vec::new());
1038 let mut map = PrimaryMap::with_capacity(info.len());
1039 let mut module_data_size = 0u32;
1040 for (memory, info) in info.iter() {
1041 let extent = if info.segments.len() > 0 {
1044 (info.max_addr - info.min_addr) as usize
1045 } else {
1046 0
1047 };
1048 let mut image = Vec::with_capacity(extent);
1049 for (idx, init) in info.segments.iter() {
1050 let data = &data[*idx];
1051 assert_eq!(data.len(), init.data.len());
1052 let offset = usize::try_from(init.offset - info.min_addr).unwrap();
1053 if image.len() < offset {
1054 image.resize(offset, 0u8);
1055 image.extend_from_slice(data);
1056 } else {
1057 image.splice(
1058 offset..(offset + data.len()).min(image.len()),
1059 data.iter().copied(),
1060 );
1061 }
1062 }
1063 assert_eq!(image.len(), extent);
1064 assert_eq!(image.capacity(), extent);
1065 let mut offset = if info.segments.len() > 0 {
1066 info.min_addr
1067 } else {
1068 0
1069 };
1070
1071 if let Some(i) = image.iter().rposition(|i| *i != 0) {
1075 image.truncate(i + 1);
1076 }
1077
1078 if let Some(i) = image.iter().position(|i| *i != 0) {
1080 offset += i as u64;
1081 image.drain(..i);
1082 }
1083 let mut len = u64::try_from(image.len()).unwrap();
1084
1085 if offset % page_size != 0 {
1090 let zero_padding = offset % page_size;
1091 self.data.push(vec![0; zero_padding as usize].into());
1092 offset -= zero_padding;
1093 len += zero_padding;
1094 }
1095 self.data.push(image.into());
1096 if len % page_size != 0 {
1097 let zero_padding = page_size - (len % page_size);
1098 self.data.push(vec![0; zero_padding as usize].into());
1099 len += zero_padding;
1100 }
1101
1102 assert!(offset % page_size == 0);
1104 assert!(len % page_size == 0);
1105
1106 let len = u32::try_from(len).unwrap();
1114 let init = if len > 0 {
1115 Some(StaticMemoryInitializer {
1116 offset,
1117 data: module_data_size..module_data_size + len,
1118 })
1119 } else {
1120 None
1121 };
1122 let idx = map.push(init);
1123 assert_eq!(idx, memory);
1124 module_data_size += len;
1125 }
1126 self.data_align = Some(page_size);
1127 self.module.memory_initialization = MemoryInitialization::Static { map };
1128 }
1129
1130 pub fn try_func_table_init(&mut self) {
1135 const MAX_FUNC_TABLE_SIZE: u64 = 1024 * 1024;
1139
1140 for ((_, init), (_, table)) in self
1143 .module
1144 .table_initialization
1145 .initial_values
1146 .iter_mut()
1147 .zip(
1148 self.module
1149 .tables
1150 .iter()
1151 .skip(self.module.num_imported_tables),
1152 )
1153 {
1154 let table_size = table.limits.min;
1155 if table_size > MAX_FUNC_TABLE_SIZE {
1156 continue;
1157 }
1158 if let TableInitialValue::Expr(expr) = init {
1159 if let [ConstOp::RefFunc(f)] = expr.ops() {
1160 *init = TableInitialValue::Null {
1161 precomputed: vec![*f; table_size as usize],
1162 };
1163 }
1164 }
1165 }
1166
1167 let mut segments = mem::take(&mut self.module.table_initialization.segments)
1168 .into_iter()
1169 .peekable();
1170
1171 while let Some(segment) = segments.peek() {
1183 let defined_index = match self.module.defined_table_index(segment.table_index) {
1184 Some(index) => index,
1185 None => break,
1189 };
1190
1191 let offset = match segment.offset.ops() {
1195 &[ConstOp::I32Const(offset)] => u64::from(offset.unsigned()),
1196 &[ConstOp::I64Const(offset)] => offset.unsigned(),
1197 _ => break,
1198 };
1199
1200 let top = match offset.checked_add(segment.elements.len()) {
1204 Some(top) => top,
1205 None => break,
1206 };
1207 let table_size = self.module.tables[segment.table_index].limits.min;
1208 if top > table_size || top > MAX_FUNC_TABLE_SIZE {
1209 break;
1210 }
1211
1212 match self.module.tables[segment.table_index]
1213 .ref_type
1214 .heap_type
1215 .top()
1216 {
1217 WasmHeapTopType::Func => {}
1218 WasmHeapTopType::Any | WasmHeapTopType::Extern | WasmHeapTopType::Cont => break,
1224 }
1225
1226 let function_elements = match &segment.elements {
1229 TableSegmentElements::Functions(indices) => indices,
1230 TableSegmentElements::Expressions(_) => break,
1231 };
1232
1233 let precomputed =
1234 match &mut self.module.table_initialization.initial_values[defined_index] {
1235 TableInitialValue::Null { precomputed } => precomputed,
1236
1237 TableInitialValue::Expr(_) => break,
1244 };
1245
1246 if precomputed.len() < top as usize {
1252 precomputed.resize(top as usize, FuncIndex::reserved_value());
1253 }
1254 let dst = &mut precomputed[offset as usize..top as usize];
1255 dst.copy_from_slice(&function_elements);
1256
1257 let _ = segments.next();
1259 }
1260 self.module.table_initialization.segments = segments.collect();
1261 }
1262}