1use super::environ::ModuleEnvironment;
15use super::error::from_binaryreadererror_wasmerror;
16use super::state::ModuleTranslationState;
17use std::boxed::Box;
18use std::collections::{HashMap, HashSet};
19use std::vec::Vec;
20use wasmer_types::entity::EntityRef;
21use wasmer_types::entity::packed_option::ReservedValue;
22use wasmer_types::{
23 DataIndex, ElemIndex, FunctionIndex, FunctionType, GlobalIndex, GlobalInit, GlobalType,
24 InitExpr, InitExprOp, MemoryIndex, MemoryType, ModuleInfo, Pages, SignatureIndex, TableIndex,
25 TableType, TagIndex, Type, V128,
26};
27use wasmer_types::{WasmError, WasmResult};
28use wasmparser::{
29 self, Data, DataKind, DataSectionReader, Element, ElementItems, ElementKind,
30 ElementSectionReader, Export, ExportSectionReader, ExternalKind, FunctionSectionReader,
31 GlobalSectionReader, GlobalType as WPGlobalType, ImportSectionReader, Imports,
32 MemorySectionReader, MemoryType as WPMemoryType, NameSectionReader, Operator,
33 TableSectionReader, TagType as WPTagType, TypeRef, TypeSectionReader,
34};
35
36pub fn wptype_to_type(ty: wasmparser::ValType) -> WasmResult<Type> {
38 match ty {
39 wasmparser::ValType::I32 => Ok(Type::I32),
40 wasmparser::ValType::I64 => Ok(Type::I64),
41 wasmparser::ValType::F32 => Ok(Type::F32),
42 wasmparser::ValType::F64 => Ok(Type::F64),
43 wasmparser::ValType::V128 => Ok(Type::V128),
44 wasmparser::ValType::Ref(ty) => wpreftype_to_type(ty),
45 }
46}
47
48pub fn wpreftype_to_type(ty: wasmparser::RefType) -> WasmResult<Type> {
50 if ty.is_extern_ref() {
51 Ok(Type::ExternRef)
52 } else if ty.is_func_ref() {
53 Ok(Type::FuncRef)
54 } else if ty == wasmparser::RefType::EXNREF || ty == wasmparser::RefType::EXN {
55 Ok(Type::ExceptionRef)
57 } else {
58 Err(wasm_unsupported!("unsupported reference type: {:?}", ty))
59 }
60}
61
62pub fn wpheaptype_to_type(ty: wasmparser::HeapType) -> WasmResult<Type> {
64 match ty {
65 wasmparser::HeapType::Abstract { ty, .. } => match ty {
66 wasmparser::AbstractHeapType::Func => Ok(Type::FuncRef),
67 wasmparser::AbstractHeapType::Extern => Ok(Type::ExternRef),
68 wasmparser::AbstractHeapType::Exn => Ok(Type::ExceptionRef),
69 other => Err(wasm_unsupported!("unsupported reference type: {other:?}")),
70 },
71 other => Err(wasm_unsupported!("unsupported reference type: {other:?}")),
72 }
73}
74
75pub fn parse_type_section(
77 types: TypeSectionReader,
78 module_translation_state: &mut ModuleTranslationState,
79 environ: &mut ModuleEnvironment,
80) -> WasmResult<()> {
81 let count = types.count();
82 environ.reserve_signatures(count)?;
83
84 for res in types.into_iter_err_on_gc_types() {
85 let functype = res.map_err(from_binaryreadererror_wasmerror)?;
86
87 let params = functype.params();
88 let returns = functype.results();
89 let sig_params: Box<[Type]> = params
90 .iter()
91 .map(|ty| {
92 wptype_to_type(*ty)
93 .expect("only numeric types are supported in function signatures")
94 })
95 .collect();
96 let sig_returns: Box<[Type]> = returns
97 .iter()
98 .map(|ty| {
99 wptype_to_type(*ty)
100 .expect("only numeric types are supported in function signatures")
101 })
102 .collect();
103 let sig = FunctionType::new(sig_params, sig_returns);
104 environ.declare_signature(sig)?;
105 module_translation_state
106 .wasm_types
107 .push((params.to_vec().into(), returns.to_vec().into()));
108 }
109
110 Ok(())
111}
112
113pub fn parse_import_section<'data>(
115 imports: ImportSectionReader<'data>,
116 environ: &mut ModuleEnvironment<'data>,
117) -> WasmResult<()> {
118 environ.reserve_imports(imports.count())?;
119
120 for entry in imports {
121 let import = entry.map_err(from_binaryreadererror_wasmerror)?;
122 let Imports::Single(_index, import) = import else {
123 return Err(WasmError::Generic(
124 "non-Single section Imports not implemented yet".to_string(),
125 ));
126 };
127 let module_name = import.module;
128 let field_name = import.name;
129
130 match import.ty {
131 TypeRef::Func(sig) => {
132 environ.declare_func_import(
133 SignatureIndex::from_u32(sig),
134 module_name,
135 field_name,
136 )?;
137 }
138 TypeRef::FuncExact(_) => {
139 return Err(WasmError::Generic(
140 "custom-descriptors not implemented yet".to_string(),
141 ));
142 }
143 TypeRef::Tag(t) => {
144 environ.declare_tag_import(t, module_name, field_name)?;
145 }
146 TypeRef::Memory(WPMemoryType {
147 shared,
148 memory64,
149 initial,
150 maximum,
151 ..
152 }) => {
153 if memory64 {
154 unimplemented!("64bit memory not implemented yet");
155 }
156 environ.declare_memory_import(
157 MemoryType {
158 minimum: Pages(initial as u32),
159 maximum: maximum.map(|p| Pages(p as u32)),
160 shared,
161 },
162 module_name,
163 field_name,
164 )?;
165 }
166 TypeRef::Global(ref ty) => {
167 environ.declare_global_import(
168 GlobalType {
169 ty: wptype_to_type(ty.content_type)?,
170 mutability: ty.mutable.into(),
171 },
172 module_name,
173 field_name,
174 )?;
175 }
176 TypeRef::Table(ref tab) => {
177 environ.declare_table_import(
178 TableType {
179 ty: wpreftype_to_type(tab.element_type)?,
180 minimum: tab.initial as u32,
181 maximum: tab.maximum.map(|v| v as u32),
182 readonly: false,
183 },
184 module_name,
185 field_name,
186 )?;
187 }
188 }
189 }
190
191 environ.finish_imports()?;
192 Ok(())
193}
194
195pub fn parse_function_section(
197 functions: FunctionSectionReader,
198 environ: &mut ModuleEnvironment,
199) -> WasmResult<()> {
200 let num_functions = functions.count();
201 if num_functions == u32::MAX {
202 return Err(WasmError::ImplLimitExceeded);
204 }
205
206 environ.reserve_func_types(num_functions)?;
207
208 for entry in functions {
209 let sigindex = entry.map_err(from_binaryreadererror_wasmerror)?;
210 environ.declare_func_type(SignatureIndex::from_u32(sigindex))?;
211 }
212
213 Ok(())
214}
215
216pub fn parse_table_section(
218 tables: TableSectionReader,
219 environ: &mut ModuleEnvironment,
220) -> WasmResult<()> {
221 environ.reserve_tables(tables.count())?;
222
223 for entry in tables {
224 let table = entry.map_err(from_binaryreadererror_wasmerror)?;
225 environ.declare_table(TableType {
226 ty: wpreftype_to_type(table.ty.element_type).unwrap(),
227 minimum: table.ty.initial as u32,
228 maximum: table.ty.maximum.map(|v| v as u32),
229 readonly: false,
230 })?;
231 }
232
233 Ok(())
234}
235
236pub fn parse_memory_section(
238 memories: MemorySectionReader,
239 environ: &mut ModuleEnvironment,
240) -> WasmResult<()> {
241 environ.reserve_memories(memories.count())?;
242
243 for entry in memories {
244 let WPMemoryType {
245 shared,
246 memory64,
247 initial,
248 maximum,
249 ..
250 } = entry.map_err(from_binaryreadererror_wasmerror)?;
251 if memory64 {
252 unimplemented!("64bit memory not implemented yet");
253 }
254 environ.declare_memory(MemoryType {
255 minimum: Pages(initial as u32),
256 maximum: maximum.map(|p| Pages(p as u32)),
257 shared,
258 })?;
259 }
260
261 Ok(())
262}
263
264pub fn parse_tag_section(
266 tags: wasmparser::SectionLimited<wasmparser::TagType>,
267 environ: &mut ModuleEnvironment,
268) -> WasmResult<()> {
269 environ.reserve_tags(tags.count())?;
270
271 for entry in tags {
272 let WPTagType { func_type_idx, .. } = entry.map_err(from_binaryreadererror_wasmerror)?;
273 environ.declare_tag(SignatureIndex::from_u32(func_type_idx))?;
274 }
275
276 Ok(())
277}
278
279fn parse_serialized_init_expr(
280 expr: &wasmparser::ConstExpr<'_>,
281 section_name: &str,
282 module: &ModuleInfo,
283) -> WasmResult<InitExpr> {
284 let mut reader = expr.get_operators_reader();
285 let mut ops = Vec::new();
286 loop {
287 let op = reader.read().map_err(from_binaryreadererror_wasmerror)?;
288 match op {
289 Operator::End => break,
290 Operator::I32Const { value } => ops.push(InitExprOp::I32Const(value)),
291 Operator::I64Const { value } => ops.push(InitExprOp::I64Const(value)),
292 Operator::GlobalGet { global_index } => {
293 let global_index = GlobalIndex::from_u32(global_index);
294 let global_type = module
295 .global_type(global_index)
296 .expect("Global index must be valid");
297
298 match global_type.ty {
299 Type::I32 => ops.push(InitExprOp::GlobalGetI32(global_index)),
300 Type::I64 => ops.push(InitExprOp::GlobalGetI64(global_index)),
301 other => {
302 return Err(wasm_unsupported!(
303 "unsupported init expr in {section_name}: global.get type must be i32 or i64, got {other:?}",
304 ));
305 }
306 }
307 }
308 Operator::I32Add => ops.push(InitExprOp::I32Add),
309 Operator::I32Sub => ops.push(InitExprOp::I32Sub),
310 Operator::I32Mul => ops.push(InitExprOp::I32Mul),
311 Operator::I64Add => ops.push(InitExprOp::I64Add),
312 Operator::I64Sub => ops.push(InitExprOp::I64Sub),
313 Operator::I64Mul => ops.push(InitExprOp::I64Mul),
314 other => {
315 return Err(wasm_unsupported!(
316 "unsupported init expr in {section_name}: {other:?}",
317 ));
318 }
319 }
320 }
321
322 if ops.is_empty() {
323 return Err(wasm_unsupported!("empty init expr in {section_name}"));
324 }
325
326 Ok(InitExpr::new(ops.into_boxed_slice()))
327}
328
329fn parse_global_initializer(
330 init_expr: &wasmparser::ConstExpr<'_>,
331 module: &ModuleInfo,
332) -> WasmResult<GlobalInit> {
333 let mut init_expr_reader = init_expr.get_operators_reader();
334 let first = init_expr_reader
335 .read()
336 .map_err(from_binaryreadererror_wasmerror)?;
337 let second = init_expr_reader
338 .read()
339 .map_err(from_binaryreadererror_wasmerror)?;
340
341 if matches!(second, Operator::End) {
342 return match first {
343 Operator::I32Const { value } => Ok(GlobalInit::I32Const(value)),
344 Operator::I64Const { value } => Ok(GlobalInit::I64Const(value)),
345 Operator::F32Const { value } => Ok(GlobalInit::F32Const(f32::from_bits(value.bits()))),
346 Operator::F64Const { value } => Ok(GlobalInit::F64Const(f64::from_bits(value.bits()))),
347 Operator::V128Const { value } => Ok(GlobalInit::V128Const(V128::from(*value.bytes()))),
348 Operator::RefNull { hty: _ } => {
349 Ok(GlobalInit::RefNullConst)
351 }
352 Operator::RefFunc { function_index } => {
353 Ok(GlobalInit::RefFunc(FunctionIndex::from_u32(function_index)))
354 }
355 Operator::GlobalGet { global_index } => {
356 Ok(GlobalInit::GetGlobal(GlobalIndex::from_u32(global_index)))
357 }
358 other => Err(wasm_unsupported!(
359 "unsupported init expr in global section: {other:?}",
360 )),
361 };
362 }
363
364 let expr = parse_serialized_init_expr(init_expr, "global section", module)?;
365 Ok(GlobalInit::Expr(expr))
366}
367
368pub fn parse_global_section(
370 globals: GlobalSectionReader,
371 environ: &mut ModuleEnvironment,
372) -> WasmResult<()> {
373 environ.reserve_globals(globals.count())?;
374
375 for entry in globals {
376 let wasmparser::Global {
377 ty:
378 WPGlobalType {
379 content_type,
380 mutable,
381 ..
382 },
383 init_expr,
384 } = entry.map_err(from_binaryreadererror_wasmerror)?;
385 let initializer = parse_global_initializer(&init_expr, &environ.module)?;
386 let global = GlobalType {
387 ty: wptype_to_type(content_type).unwrap(),
388 mutability: mutable.into(),
389 };
390 environ.declare_global(global, initializer)?;
391 }
392
393 Ok(())
394}
395
396pub fn parse_export_section<'data>(
398 exports: ExportSectionReader<'data>,
399 environ: &mut ModuleEnvironment<'data>,
400) -> WasmResult<()> {
401 environ.reserve_exports(exports.count())?;
402
403 for entry in exports {
404 let Export {
405 name: field,
406 ref kind,
407 index,
408 } = entry.map_err(from_binaryreadererror_wasmerror)?;
409
410 let index = index as usize;
414 match *kind {
415 ExternalKind::Func => environ.declare_func_export(FunctionIndex::new(index), field)?,
416 ExternalKind::Table => environ.declare_table_export(TableIndex::new(index), field)?,
417 ExternalKind::Memory => {
418 environ.declare_memory_export(MemoryIndex::new(index), field)?
419 }
420 ExternalKind::Global => {
421 environ.declare_global_export(GlobalIndex::new(index), field)?
422 }
423 ExternalKind::Tag => environ.declare_tag_export(TagIndex::new(index), field)?,
424 ExternalKind::FuncExact => unimplemented!("custom-descriptors not implemented yet"),
425 }
426 }
427
428 environ.finish_exports()?;
429 Ok(())
430}
431
432pub fn parse_start_section(index: u32, environ: &mut ModuleEnvironment) -> WasmResult<()> {
434 environ.declare_start_function(FunctionIndex::from_u32(index))?;
435 Ok(())
436}
437
438fn read_elems(items: &ElementItems) -> WasmResult<Box<[FunctionIndex]>> {
439 let mut out = Vec::new();
440
441 match items {
442 ElementItems::Functions(funcs) => {
443 for res in funcs.clone().into_iter() {
444 let func_index = res.map_err(from_binaryreadererror_wasmerror)?;
445 out.push(FunctionIndex::from_u32(func_index));
446 }
447 }
448 ElementItems::Expressions(ty, section) => {
449 if !(ty.is_extern_ref() || ty.is_func_ref()) {
451 return Err(wasm_unsupported!(
452 "unsupported element type in element section: {:?}",
453 ty
454 ));
455 }
456
457 for res in section.clone().into_iter() {
458 let expr = res.map_err(from_binaryreadererror_wasmerror)?;
459
460 let op = expr
461 .get_operators_reader()
462 .read()
463 .map_err(from_binaryreadererror_wasmerror)?;
464 match op {
465 Operator::RefNull { .. } => out.push(FunctionIndex::reserved_value()),
466 Operator::RefFunc { function_index } => {
467 out.push(FunctionIndex::from_u32(function_index))
468 }
469 other => {
470 return Err(WasmError::Unsupported(format!(
471 "unsupported init expr in element section: {other:?}",
472 )));
473 }
474 }
475 }
476 }
477 }
478
479 Ok(out.into_boxed_slice())
480}
481
482pub fn parse_element_section(
484 elements: ElementSectionReader<'_>,
485 environ: &mut ModuleEnvironment,
486) -> WasmResult<()> {
487 environ.reserve_table_initializers(elements.count())?;
488
489 for (index, elem) in elements.into_iter().enumerate() {
490 let Element {
491 kind,
492 items,
493 range: _,
494 } = elem.map_err(from_binaryreadererror_wasmerror)?;
495
496 let segments = read_elems(&items)?;
497 match kind {
498 ElementKind::Active {
499 table_index,
500 offset_expr,
501 } => {
502 let table_index = TableIndex::from_u32(table_index.unwrap_or(0));
503 let offset_expr =
504 parse_serialized_init_expr(&offset_expr, "element section", &environ.module)?;
505 environ.declare_table_initializers(table_index, offset_expr, segments)?
506 }
507 ElementKind::Passive => {
508 let index = ElemIndex::from_u32(index as u32);
509 environ.declare_passive_element(index, segments)?;
510 }
511 ElementKind::Declared => (),
512 }
513 }
514 Ok(())
515}
516
517pub fn parse_data_section<'data>(
519 data: DataSectionReader<'data>,
520 environ: &mut ModuleEnvironment<'data>,
521) -> WasmResult<()> {
522 environ.reserve_data_initializers(data.count())?;
523
524 for (index, entry) in data.into_iter().enumerate() {
525 let Data {
526 kind,
527 data,
528 range: _,
529 } = entry.map_err(from_binaryreadererror_wasmerror)?;
530 match kind {
531 DataKind::Active {
532 memory_index,
533 offset_expr,
534 } => {
535 let offset_expr =
536 parse_serialized_init_expr(&offset_expr, "data section", &environ.module)?;
537 environ.declare_data_initialization(
538 MemoryIndex::from_u32(memory_index),
539 offset_expr,
540 data,
541 )?;
542 }
543 DataKind::Passive => {
544 let index = DataIndex::from_u32(index as u32);
545 environ.declare_passive_data(index, data)?;
546 }
547 }
548 }
549
550 Ok(())
551}
552
553pub fn parse_name_section<'data>(
555 names: NameSectionReader<'data>,
556 environ: &mut ModuleEnvironment<'data>,
557) -> WasmResult<()> {
558 let mut functions = HashMap::new();
559 let mut names_set = HashSet::new();
560
561 for res in names {
562 let subsection = if let Ok(subsection) = res {
563 subsection
564 } else {
565 continue;
567 };
568 match subsection {
569 wasmparser::Name::Function(function_subsection) => {
570 let mut unique_name_map = HashMap::new();
571 for naming in function_subsection.into_iter().flatten() {
572 if naming.index != u32::MAX {
573 let mut name = naming.name.to_string();
574 if names_set.contains(&name) {
576 let index = unique_name_map
577 .entry(name.clone())
578 .and_modify(|e| *e += 1)
579 .or_insert(0);
580 let alternative = format!("{name}.{index}");
581 name = alternative;
582 }
583 names_set.insert(name.clone());
584 functions.insert(FunctionIndex::from_u32(naming.index), name);
585 }
586 }
587 }
588 wasmparser::Name::Module {
589 name,
590 name_range: _,
591 } => {
592 environ.declare_module_name(name)?;
593 }
594 wasmparser::Name::Local(_) => {}
595 wasmparser::Name::Label(_)
596 | wasmparser::Name::Type(_)
597 | wasmparser::Name::Table(_)
598 | wasmparser::Name::Memory(_)
599 | wasmparser::Name::Global(_)
600 | wasmparser::Name::Element(_)
601 | wasmparser::Name::Data(_)
602 | wasmparser::Name::Unknown { .. }
603 | wasmparser::Name::Field(_)
604 | wasmparser::Name::Tag(..) => {}
605 }
606 }
607
608 environ.declare_function_names(functions)
609}