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 },
183 module_name,
184 field_name,
185 )?;
186 }
187 }
188 }
189
190 environ.finish_imports()?;
191 Ok(())
192}
193
194pub fn parse_function_section(
196 functions: FunctionSectionReader,
197 environ: &mut ModuleEnvironment,
198) -> WasmResult<()> {
199 let num_functions = functions.count();
200 if num_functions == u32::MAX {
201 return Err(WasmError::ImplLimitExceeded);
203 }
204
205 environ.reserve_func_types(num_functions)?;
206
207 for entry in functions {
208 let sigindex = entry.map_err(from_binaryreadererror_wasmerror)?;
209 environ.declare_func_type(SignatureIndex::from_u32(sigindex))?;
210 }
211
212 Ok(())
213}
214
215pub fn parse_table_section(
217 tables: TableSectionReader,
218 environ: &mut ModuleEnvironment,
219) -> WasmResult<()> {
220 environ.reserve_tables(tables.count())?;
221
222 for entry in tables {
223 let table = entry.map_err(from_binaryreadererror_wasmerror)?;
224 environ.declare_table(TableType {
225 ty: wpreftype_to_type(table.ty.element_type).unwrap(),
226 minimum: table.ty.initial as u32,
227 maximum: table.ty.maximum.map(|v| v as u32),
228 })?;
229 }
230
231 Ok(())
232}
233
234pub fn parse_memory_section(
236 memories: MemorySectionReader,
237 environ: &mut ModuleEnvironment,
238) -> WasmResult<()> {
239 environ.reserve_memories(memories.count())?;
240
241 for entry in memories {
242 let WPMemoryType {
243 shared,
244 memory64,
245 initial,
246 maximum,
247 ..
248 } = entry.map_err(from_binaryreadererror_wasmerror)?;
249 if memory64 {
250 unimplemented!("64bit memory not implemented yet");
251 }
252 environ.declare_memory(MemoryType {
253 minimum: Pages(initial as u32),
254 maximum: maximum.map(|p| Pages(p as u32)),
255 shared,
256 })?;
257 }
258
259 Ok(())
260}
261
262pub fn parse_tag_section(
264 tags: wasmparser::SectionLimited<wasmparser::TagType>,
265 environ: &mut ModuleEnvironment,
266) -> WasmResult<()> {
267 environ.reserve_tags(tags.count())?;
268
269 for entry in tags {
270 let WPTagType { func_type_idx, .. } = entry.map_err(from_binaryreadererror_wasmerror)?;
271 environ.declare_tag(SignatureIndex::from_u32(func_type_idx))?;
272 }
273
274 Ok(())
275}
276
277fn parse_serialized_init_expr(
278 expr: &wasmparser::ConstExpr<'_>,
279 section_name: &str,
280 module: &ModuleInfo,
281) -> WasmResult<InitExpr> {
282 let mut reader = expr.get_operators_reader();
283 let mut ops = Vec::new();
284 loop {
285 let op = reader.read().map_err(from_binaryreadererror_wasmerror)?;
286 match op {
287 Operator::End => break,
288 Operator::I32Const { value } => ops.push(InitExprOp::I32Const(value)),
289 Operator::I64Const { value } => ops.push(InitExprOp::I64Const(value)),
290 Operator::GlobalGet { global_index } => {
291 let global_index = GlobalIndex::from_u32(global_index);
292 let global_type = module
293 .global_type(global_index)
294 .expect("Global index must be valid");
295
296 match global_type.ty {
297 Type::I32 => ops.push(InitExprOp::GlobalGetI32(global_index)),
298 Type::I64 => ops.push(InitExprOp::GlobalGetI64(global_index)),
299 other => {
300 return Err(wasm_unsupported!(
301 "unsupported init expr in {section_name}: global.get type must be i32 or i64, got {other:?}",
302 ));
303 }
304 }
305 }
306 Operator::I32Add => ops.push(InitExprOp::I32Add),
307 Operator::I32Sub => ops.push(InitExprOp::I32Sub),
308 Operator::I32Mul => ops.push(InitExprOp::I32Mul),
309 Operator::I64Add => ops.push(InitExprOp::I64Add),
310 Operator::I64Sub => ops.push(InitExprOp::I64Sub),
311 Operator::I64Mul => ops.push(InitExprOp::I64Mul),
312 other => {
313 return Err(wasm_unsupported!(
314 "unsupported init expr in {section_name}: {other:?}",
315 ));
316 }
317 }
318 }
319
320 if ops.is_empty() {
321 return Err(wasm_unsupported!("empty init expr in {section_name}"));
322 }
323
324 Ok(InitExpr::new(ops.into_boxed_slice()))
325}
326
327fn parse_global_initializer(
328 init_expr: &wasmparser::ConstExpr<'_>,
329 module: &ModuleInfo,
330) -> WasmResult<GlobalInit> {
331 let mut init_expr_reader = init_expr.get_operators_reader();
332 let first = init_expr_reader
333 .read()
334 .map_err(from_binaryreadererror_wasmerror)?;
335 let second = init_expr_reader
336 .read()
337 .map_err(from_binaryreadererror_wasmerror)?;
338
339 if matches!(second, Operator::End) {
340 return match first {
341 Operator::I32Const { value } => Ok(GlobalInit::I32Const(value)),
342 Operator::I64Const { value } => Ok(GlobalInit::I64Const(value)),
343 Operator::F32Const { value } => Ok(GlobalInit::F32Const(f32::from_bits(value.bits()))),
344 Operator::F64Const { value } => Ok(GlobalInit::F64Const(f64::from_bits(value.bits()))),
345 Operator::V128Const { value } => Ok(GlobalInit::V128Const(V128::from(*value.bytes()))),
346 Operator::RefNull { hty: _ } => {
347 Ok(GlobalInit::RefNullConst)
349 }
350 Operator::RefFunc { function_index } => {
351 Ok(GlobalInit::RefFunc(FunctionIndex::from_u32(function_index)))
352 }
353 Operator::GlobalGet { global_index } => {
354 Ok(GlobalInit::GetGlobal(GlobalIndex::from_u32(global_index)))
355 }
356 other => Err(wasm_unsupported!(
357 "unsupported init expr in global section: {other:?}",
358 )),
359 };
360 }
361
362 let expr = parse_serialized_init_expr(init_expr, "global section", module)?;
363 Ok(GlobalInit::Expr(expr))
364}
365
366pub fn parse_global_section(
368 globals: GlobalSectionReader,
369 environ: &mut ModuleEnvironment,
370) -> WasmResult<()> {
371 environ.reserve_globals(globals.count())?;
372
373 for entry in globals {
374 let wasmparser::Global {
375 ty:
376 WPGlobalType {
377 content_type,
378 mutable,
379 ..
380 },
381 init_expr,
382 } = entry.map_err(from_binaryreadererror_wasmerror)?;
383 let initializer = parse_global_initializer(&init_expr, &environ.module)?;
384 let global = GlobalType {
385 ty: wptype_to_type(content_type).unwrap(),
386 mutability: mutable.into(),
387 };
388 environ.declare_global(global, initializer)?;
389 }
390
391 Ok(())
392}
393
394pub fn parse_export_section<'data>(
396 exports: ExportSectionReader<'data>,
397 environ: &mut ModuleEnvironment<'data>,
398) -> WasmResult<()> {
399 environ.reserve_exports(exports.count())?;
400
401 for entry in exports {
402 let Export {
403 name: field,
404 ref kind,
405 index,
406 } = entry.map_err(from_binaryreadererror_wasmerror)?;
407
408 let index = index as usize;
412 match *kind {
413 ExternalKind::Func => environ.declare_func_export(FunctionIndex::new(index), field)?,
414 ExternalKind::Table => environ.declare_table_export(TableIndex::new(index), field)?,
415 ExternalKind::Memory => {
416 environ.declare_memory_export(MemoryIndex::new(index), field)?
417 }
418 ExternalKind::Global => {
419 environ.declare_global_export(GlobalIndex::new(index), field)?
420 }
421 ExternalKind::Tag => environ.declare_tag_export(TagIndex::new(index), field)?,
422 ExternalKind::FuncExact => unimplemented!("custom-descriptors not implemented yet"),
423 }
424 }
425
426 environ.finish_exports()?;
427 Ok(())
428}
429
430pub fn parse_start_section(index: u32, environ: &mut ModuleEnvironment) -> WasmResult<()> {
432 environ.declare_start_function(FunctionIndex::from_u32(index))?;
433 Ok(())
434}
435
436fn read_elems(items: &ElementItems) -> WasmResult<Box<[FunctionIndex]>> {
437 let mut out = Vec::new();
438
439 match items {
440 ElementItems::Functions(funcs) => {
441 for res in funcs.clone().into_iter() {
442 let func_index = res.map_err(from_binaryreadererror_wasmerror)?;
443 out.push(FunctionIndex::from_u32(func_index));
444 }
445 }
446 ElementItems::Expressions(ty, section) => {
447 if !(ty.is_extern_ref() || ty.is_func_ref()) {
449 return Err(wasm_unsupported!(
450 "unsupported element type in element section: {:?}",
451 ty
452 ));
453 }
454
455 for res in section.clone().into_iter() {
456 let expr = res.map_err(from_binaryreadererror_wasmerror)?;
457
458 let op = expr
459 .get_operators_reader()
460 .read()
461 .map_err(from_binaryreadererror_wasmerror)?;
462 match op {
463 Operator::RefNull { .. } => out.push(FunctionIndex::reserved_value()),
464 Operator::RefFunc { function_index } => {
465 out.push(FunctionIndex::from_u32(function_index))
466 }
467 other => {
468 return Err(WasmError::Unsupported(format!(
469 "unsupported init expr in element section: {other:?}",
470 )));
471 }
472 }
473 }
474 }
475 }
476
477 Ok(out.into_boxed_slice())
478}
479
480pub fn parse_element_section(
482 elements: ElementSectionReader<'_>,
483 environ: &mut ModuleEnvironment,
484) -> WasmResult<()> {
485 environ.reserve_table_initializers(elements.count())?;
486
487 for (index, elem) in elements.into_iter().enumerate() {
488 let Element {
489 kind,
490 items,
491 range: _,
492 } = elem.map_err(from_binaryreadererror_wasmerror)?;
493
494 let segments = read_elems(&items)?;
495 match kind {
496 ElementKind::Active {
497 table_index,
498 offset_expr,
499 } => {
500 let table_index = TableIndex::from_u32(table_index.unwrap_or(0));
501 let offset_expr =
502 parse_serialized_init_expr(&offset_expr, "element section", &environ.module)?;
503 environ.declare_table_initializers(table_index, offset_expr, segments)?
504 }
505 ElementKind::Passive => {
506 let index = ElemIndex::from_u32(index as u32);
507 environ.declare_passive_element(index, segments)?;
508 }
509 ElementKind::Declared => (),
510 }
511 }
512 Ok(())
513}
514
515pub fn parse_data_section<'data>(
517 data: DataSectionReader<'data>,
518 environ: &mut ModuleEnvironment<'data>,
519) -> WasmResult<()> {
520 environ.reserve_data_initializers(data.count())?;
521
522 for (index, entry) in data.into_iter().enumerate() {
523 let Data {
524 kind,
525 data,
526 range: _,
527 } = entry.map_err(from_binaryreadererror_wasmerror)?;
528 match kind {
529 DataKind::Active {
530 memory_index,
531 offset_expr,
532 } => {
533 let offset_expr =
534 parse_serialized_init_expr(&offset_expr, "data section", &environ.module)?;
535 environ.declare_data_initialization(
536 MemoryIndex::from_u32(memory_index),
537 offset_expr,
538 data,
539 )?;
540 }
541 DataKind::Passive => {
542 let index = DataIndex::from_u32(index as u32);
543 environ.declare_passive_data(index, data)?;
544 }
545 }
546 }
547
548 Ok(())
549}
550
551pub fn parse_name_section<'data>(
553 names: NameSectionReader<'data>,
554 environ: &mut ModuleEnvironment<'data>,
555) -> WasmResult<()> {
556 let mut functions = HashMap::new();
557 let mut names_set = HashSet::new();
558
559 for res in names {
560 let subsection = if let Ok(subsection) = res {
561 subsection
562 } else {
563 continue;
565 };
566 match subsection {
567 wasmparser::Name::Function(function_subsection) => {
568 let mut unique_name_map = HashMap::new();
569 for naming in function_subsection.into_iter().flatten() {
570 if naming.index != u32::MAX {
571 let mut name = naming.name.to_string();
572 if names_set.contains(&name) {
574 let index = unique_name_map
575 .entry(name.clone())
576 .and_modify(|e| *e += 1)
577 .or_insert(0);
578 let alternative = format!("{name}.{index}");
579 name = alternative;
580 }
581 names_set.insert(name.clone());
582 functions.insert(FunctionIndex::from_u32(naming.index), name);
583 }
584 }
585 }
586 wasmparser::Name::Module {
587 name,
588 name_range: _,
589 } => {
590 environ.declare_module_name(name)?;
591 }
592 wasmparser::Name::Local(_) => {}
593 wasmparser::Name::Label(_)
594 | wasmparser::Name::Type(_)
595 | wasmparser::Name::Table(_)
596 | wasmparser::Name::Memory(_)
597 | wasmparser::Name::Global(_)
598 | wasmparser::Name::Element(_)
599 | wasmparser::Name::Data(_)
600 | wasmparser::Name::Unknown { .. }
601 | wasmparser::Name::Field(_)
602 | wasmparser::Name::Tag(..) => {}
603 }
604 }
605
606 environ.declare_function_names(functions)
607}