1use super::environ::ModuleEnvironment;
14use super::state::ModuleTranslationState;
15use crate::wasm_unsupported;
16use crate::{WasmError, WasmResult};
17use core::convert::TryFrom;
18use near_vm_types::entity::EntityRef;
19use near_vm_types::entity::packed_option::ReservedValue;
20use near_vm_types::{
21 DataIndex, ElemIndex, FunctionIndex, FunctionType, GlobalIndex, GlobalInit, GlobalType,
22 MemoryIndex, MemoryType, Mutability, Pages, SignatureIndex, TableIndex, TableType, Type, V128,
23};
24use std::boxed::Box;
25use std::collections::HashMap;
26use std::convert::TryInto;
27use std::sync::Arc;
28use std::vec::Vec;
29use wasmparser::{
30 self, Data, DataKind, DataSectionReader, Element, ElementItems, ElementKind,
31 ElementSectionReader, Export, ExportSectionReader, ExternalKind, FunctionSectionReader,
32 GlobalSectionReader, GlobalType as WPGlobalType, ImportSectionReader, MemorySectionReader,
33 NameMap, NameSectionReader, Naming, Operator, TableSectionReader, Type as WPType, TypeRef,
34 TypeSectionReader, ValType as WPValType,
35};
36
37pub fn wptype_to_type(ty: WPValType) -> WasmResult<Type> {
39 match ty {
40 WPValType::I32 => Ok(Type::I32),
41 WPValType::I64 => Ok(Type::I64),
42 WPValType::F32 => Ok(Type::F32),
43 WPValType::F64 => Ok(Type::F64),
44 WPValType::V128 => Ok(Type::V128),
45 WPValType::ExternRef => Ok(Type::ExternRef),
46 WPValType::FuncRef => Ok(Type::FuncRef),
47 }
48}
49
50pub fn parse_type_section(
52 types: TypeSectionReader,
53 module_translation_state: &mut ModuleTranslationState,
54 environ: &mut ModuleEnvironment,
55) -> WasmResult<()> {
56 let count = types.count();
57 environ.reserve_signatures(count)?;
58
59 for entry in types {
60 if let Ok(WPType::Func(t)) = entry {
61 let params: Box<[WPValType]> = t.params().into();
62 let results: Box<[WPValType]> = t.results().into();
63 let sig_params: Arc<[Type]> = params
64 .iter()
65 .map(|ty| {
66 wptype_to_type(*ty)
67 .expect("only numeric types are supported in function signatures")
68 })
69 .collect();
70 let sig_results: Arc<[Type]> = results
71 .iter()
72 .map(|ty| {
73 wptype_to_type(*ty)
74 .expect("only numeric types are supported in function signatures")
75 })
76 .collect();
77 let sig = FunctionType::new(sig_params, sig_results);
78 environ.declare_signature(sig)?;
79 module_translation_state.wasm_types.push((params, results));
80 } else {
81 unimplemented!("module linking not implemented yet")
82 }
83 }
84
85 Ok(())
86}
87
88pub fn parse_import_section<'data>(
90 imports: ImportSectionReader<'data>,
91 environ: &mut ModuleEnvironment<'data>,
92) -> WasmResult<()> {
93 environ.reserve_imports(imports.count())?;
94
95 for entry in imports {
96 let import = entry?;
97 let module_name = import.module;
98 let field_name = import.name;
99
100 match import.ty {
101 TypeRef::Func(sig) => {
102 environ.declare_func_import(
103 SignatureIndex::from_u32(sig),
104 module_name,
105 field_name,
106 )?;
107 }
108 TypeRef::Memory(mem) => {
109 assert!(!mem.memory64, "64bit memory not implemented yet");
110 environ.declare_memory_import(
111 MemoryType {
112 minimum: Pages(mem.initial.try_into().unwrap()),
113 maximum: mem.maximum.map(|m| Pages(m.try_into().unwrap())),
114 shared: mem.shared,
115 },
116 module_name,
117 field_name,
118 )?;
119 }
120 TypeRef::Global(ref ty) => {
121 environ.declare_global_import(
122 GlobalType {
123 ty: wptype_to_type(ty.content_type).unwrap(),
124 mutability: if ty.mutable { Mutability::Var } else { Mutability::Const },
125 },
126 module_name,
127 field_name,
128 )?;
129 }
130 TypeRef::Table(ref tab) => {
131 environ.declare_table_import(
132 TableType {
133 ty: wptype_to_type(tab.element_type).unwrap(),
134 minimum: tab.initial,
135 maximum: tab.maximum,
136 },
137 module_name,
138 field_name,
139 )?;
140 }
141 TypeRef::Tag(_) => panic!("exception handling proposal is not implemented yet"),
142 }
143 }
144
145 environ.finish_imports()?;
146 Ok(())
147}
148
149pub fn parse_function_section(
151 functions: FunctionSectionReader,
152 environ: &mut ModuleEnvironment,
153) -> WasmResult<()> {
154 let num_functions = functions.count();
155 if num_functions == std::u32::MAX {
156 return Err(WasmError::ImplLimitExceeded);
158 }
159
160 environ.reserve_func_types(num_functions)?;
161
162 for entry in functions {
163 let sigindex = entry?;
164 environ.declare_func_type(SignatureIndex::from_u32(sigindex))?;
165 }
166
167 Ok(())
168}
169
170pub fn parse_table_section(
172 tables: TableSectionReader,
173 environ: &mut ModuleEnvironment,
174) -> WasmResult<()> {
175 environ.reserve_tables(tables.count())?;
176
177 for entry in tables {
178 let table = entry?;
179 environ.declare_table(TableType {
180 ty: wptype_to_type(table.element_type).unwrap(),
181 minimum: table.initial,
182 maximum: table.maximum,
183 })?;
184 }
185
186 Ok(())
187}
188
189pub fn parse_memory_section(
191 memories: MemorySectionReader,
192 environ: &mut ModuleEnvironment,
193) -> WasmResult<()> {
194 environ.reserve_memories(memories.count())?;
195
196 for entry in memories {
197 let mem = entry?;
198 assert!(!mem.memory64, "64bit memory not implemented yet");
199
200 environ.declare_memory(MemoryType {
201 minimum: Pages(mem.initial.try_into().unwrap()),
202 maximum: mem.maximum.map(|m| Pages(m.try_into().unwrap())),
203 shared: mem.shared,
204 })?;
205 }
206
207 Ok(())
208}
209
210pub fn parse_global_section(
212 globals: GlobalSectionReader,
213 environ: &mut ModuleEnvironment,
214) -> WasmResult<()> {
215 environ.reserve_globals(globals.count())?;
216
217 for entry in globals {
218 let wasmparser::Global { ty: WPGlobalType { content_type, mutable }, init_expr } = entry?;
219 let mut init_expr_reader = init_expr.get_binary_reader();
220 let initializer = match init_expr_reader.read_operator()? {
221 Operator::I32Const { value } => GlobalInit::I32Const(value),
222 Operator::I64Const { value } => GlobalInit::I64Const(value),
223 Operator::F32Const { value } => GlobalInit::F32Const(f32::from_bits(value.bits())),
224 Operator::F64Const { value } => GlobalInit::F64Const(f64::from_bits(value.bits())),
225 Operator::V128Const { value } => GlobalInit::V128Const(V128::from(*value.bytes())),
226 Operator::RefNull { ty: _ } => GlobalInit::RefNullConst,
227 Operator::RefFunc { function_index } => {
228 GlobalInit::RefFunc(FunctionIndex::from_u32(function_index))
229 }
230 Operator::GlobalGet { global_index } => {
231 GlobalInit::GetGlobal(GlobalIndex::from_u32(global_index))
232 }
233 ref s => {
234 return Err(wasm_unsupported!("unsupported init expr in global section: {:?}", s));
235 }
236 };
237 let global = GlobalType {
238 ty: wptype_to_type(content_type).unwrap(),
239 mutability: if mutable { Mutability::Var } else { Mutability::Const },
240 };
241 environ.declare_global(global, initializer)?;
242 }
243
244 Ok(())
245}
246
247pub fn parse_export_section<'data>(
249 exports: ExportSectionReader<'data>,
250 environ: &mut ModuleEnvironment<'data>,
251) -> WasmResult<()> {
252 environ.reserve_exports(exports.count())?;
253
254 for entry in exports {
255 let Export { name, ref kind, index } = entry?;
256
257 let index = index as usize;
261 match *kind {
262 ExternalKind::Func => environ.declare_func_export(FunctionIndex::new(index), name)?,
263 ExternalKind::Table => environ.declare_table_export(TableIndex::new(index), name)?,
264 ExternalKind::Memory => environ.declare_memory_export(MemoryIndex::new(index), name)?,
265 ExternalKind::Global => environ.declare_global_export(GlobalIndex::new(index), name)?,
266 ExternalKind::Tag => panic!("exception handling proposal is not implemented yet"),
267 }
268 }
269
270 environ.finish_exports()?;
271 Ok(())
272}
273
274pub fn parse_start_section(index: u32, environ: &mut ModuleEnvironment) -> WasmResult<()> {
276 environ.declare_start_function(FunctionIndex::from_u32(index))?;
277 Ok(())
278}
279
280fn read_elems(items: &ElementItems) -> WasmResult<Box<[FunctionIndex]>> {
281 match items.clone() {
282 ElementItems::Functions(items) => items
283 .into_iter()
284 .map(|v| v.map(FunctionIndex::from_u32).map_err(WasmError::from))
285 .collect(),
286 ElementItems::Expressions(items) => {
287 let mut elems = Vec::with_capacity(usize::try_from(items.count()).unwrap());
288 for item in items {
289 let mut reader = item?.get_operators_reader();
290 let op = reader.read()?;
291 let end = reader.read()?;
292 reader.ensure_end()?;
293 use Operator::*;
294 match (op, end) {
295 (RefFunc { function_index }, End) => {
296 elems.push(FunctionIndex::from_u32(function_index))
297 }
298 (RefNull { .. }, End) => elems.push(FunctionIndex::reserved_value()),
299 _ => todo!("unexpected syntax for elems item initializer"),
300 }
301 }
302 Ok(elems.into_boxed_slice())
303 }
304 }
305}
306
307pub fn parse_element_section<'data>(
309 elements: ElementSectionReader<'data>,
310 environ: &mut ModuleEnvironment,
311) -> WasmResult<()> {
312 environ.reserve_table_initializers(elements.count())?;
313
314 for (index, entry) in elements.into_iter().enumerate() {
315 let Element { kind, items, ty, .. } = entry?;
316 if ty != WPValType::FuncRef {
317 return Err(wasm_unsupported!("unsupported table element type: {:?}", ty));
318 }
319 let segments = read_elems(&items)?;
320 match kind {
321 ElementKind::Active { table_index, offset_expr } => {
322 let mut offset_expr_reader = offset_expr.get_binary_reader();
323 let (base, offset) = match offset_expr_reader.read_operator()? {
324 Operator::I32Const { value } => (None, value as u32 as usize),
325 Operator::GlobalGet { global_index } => {
326 (Some(GlobalIndex::from_u32(global_index)), 0)
327 }
328 ref s => {
329 return Err(wasm_unsupported!(
330 "unsupported init expr in element section: {:?}",
331 s
332 ));
333 }
334 };
335 environ.declare_table_initializers(
336 TableIndex::from_u32(table_index),
337 base,
338 offset,
339 segments,
340 )?
341 }
342 ElementKind::Passive => {
343 let index = ElemIndex::from_u32(index as u32);
344 environ.declare_passive_element(index, segments)?;
345 }
346 ElementKind::Declared => (),
347 }
348 }
349 Ok(())
350}
351
352pub fn parse_data_section<'data>(
354 data: DataSectionReader<'data>,
355 environ: &mut ModuleEnvironment<'data>,
356) -> WasmResult<()> {
357 environ.reserve_data_initializers(data.count())?;
358
359 for (index, entry) in data.into_iter().enumerate() {
360 let Data { kind, data, .. } = entry?;
361 match kind {
362 DataKind::Active { memory_index, offset_expr } => {
363 let mut offset_expr_reader = offset_expr.get_binary_reader();
364 let (base, offset) = match offset_expr_reader.read_operator()? {
365 Operator::I32Const { value } => (None, value as u32 as usize),
366 Operator::GlobalGet { global_index } => {
367 (Some(GlobalIndex::from_u32(global_index)), 0)
368 }
369 ref s => {
370 return Err(wasm_unsupported!(
371 "unsupported init expr in data section: {:?}",
372 s
373 ));
374 }
375 };
376 environ.declare_data_initialization(
377 MemoryIndex::from_u32(memory_index),
378 base,
379 offset,
380 data,
381 )?;
382 }
383 DataKind::Passive => {
384 let index = DataIndex::from_u32(index as u32);
385 environ.declare_passive_data(index, data)?;
386 }
387 }
388 }
389
390 Ok(())
391}
392
393pub fn parse_name_section<'data>(
395 mut names: NameSectionReader<'data>,
396 environ: &mut ModuleEnvironment<'data>,
397) -> WasmResult<()> {
398 use wasmparser::Name;
399 while let Some(subsection) = names.next() {
400 let subsection = subsection?;
401 match subsection {
402 Name::Function(function_subsection) => {
403 if let Some(function_names) = parse_function_name_subsection(function_subsection) {
404 for (index, name) in function_names {
405 environ.declare_function_name(index, name)?;
406 }
407 }
408 }
409 Name::Module { name, .. } => {
410 environ.declare_module_name(name)?;
411 }
412 Name::Local(_) => {}
413 Name::Label(_) => {}
414 Name::Type(_) => {}
415 Name::Table(_) => {}
416 Name::Memory(_) => {}
417 Name::Global(_) => {}
418 Name::Element(_) => {}
419 Name::Data(_) => {}
420 Name::Unknown { .. } => {}
421 };
422 }
423 Ok(())
424}
425
426fn parse_function_name_subsection(
427 naming_reader: NameMap<'_>,
428) -> Option<HashMap<FunctionIndex, &str>> {
429 let mut function_names = HashMap::new();
430 for name in naming_reader {
431 let Naming { index, name } = name.ok()?;
432 if index == std::u32::MAX {
433 return None;
435 }
436
437 if function_names.insert(FunctionIndex::from_u32(index), name).is_some() {
438 return None;
442 }
443 }
444 Some(function_names)
445}