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