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