1use core::convert::{TryFrom, TryInto};
2use core::fmt;
3use core::iter::{self, FromIterator};
4
5use parity_wasm::elements as pwasm;
6
7pub use parity_wasm::elements::{
8 BlockType, BrTableData, CustomSection, ExportEntry, External, GlobalType, ImportEntry,
9 Instruction, Internal, MemoryType, ResizableLimits, TableElementType, TableType, ValueType,
10};
11pub use parity_wasm::SerializationError;
12pub use wasmi_validation::Error as ValidationError;
13
14pub const PAGE_SIZE: u32 = 64 * 1024; #[derive(Debug)]
17pub enum LoadError {
18 SerializationError(SerializationError),
19 ValidationError(ValidationError),
20}
21
22impl fmt::Display for LoadError {
23 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24 match self {
25 Self::SerializationError(error) => write!(f, "Error while serializing file: {}", error),
26 Self::ValidationError(error) => write!(f, "Error while validating file: {}", error),
27 }
28 }
29}
30
31impl From<SerializationError> for LoadError {
32 fn from(error: SerializationError) -> Self {
33 Self::SerializationError(error)
34 }
35}
36
37impl From<ValidationError> for LoadError {
38 fn from(error: ValidationError) -> Self {
39 Self::ValidationError(error)
40 }
41}
42
43#[derive(Clone, PartialEq, Eq, Hash, Debug)]
44pub struct FunctionType {
45 type_ref: u32,
46 params: Vec<ValueType>,
47 return_type: Option<ValueType>,
48}
49
50impl FunctionType {
51 fn new(type_ref: u32, func_type: &mut pwasm::FunctionType) -> Self {
52 FunctionType {
53 type_ref,
54 params: take(func_type.params_mut()),
55 return_type: take(func_type.return_type_mut()),
56 }
57 }
58 pub const fn type_ref(&self) -> u32 {
59 self.type_ref
60 }
61 pub fn params(&self) -> &[ValueType] {
62 &self.params
63 }
64 pub fn param_count(&self) -> u32 {
65 self.params.len() as u32
66 }
67 pub const fn return_type(&self) -> Option<ValueType> {
68 self.return_type
69 }
70}
71
72impl fmt::Display for FunctionType {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 let params = self
75 .params
76 .iter()
77 .map(|t| t.to_string())
78 .collect::<Vec<String>>()
79 .join(", ");
80 let return_type = match self.return_type {
81 Some(return_type) => return_type.to_string(),
82 None => String::from("()"),
83 };
84 write!(f, "fn ({}) -> {}", params, return_type)
85 }
86}
87
88#[derive(Clone, PartialEq, Eq, Hash, Debug)]
89pub struct Function {
90 name: String,
91 func_type: FunctionType,
92 is_imported: bool,
93 locals: Vec<ValueType>,
94 instructions: Vec<Instruction>,
95}
96
97impl Function {
98 const fn new(
99 name: String,
100 func_type: FunctionType,
101 locals: Vec<ValueType>,
102 instructions: Vec<Instruction>,
103 ) -> Self {
104 Function {
105 name,
106 func_type,
107 is_imported: false,
108 locals,
109 instructions,
110 }
111 }
112
113 fn new_imported(name: String, func_type: FunctionType) -> Self {
114 Function {
115 name,
116 func_type,
117 is_imported: true,
118 locals: Vec::new(),
119 instructions: Vec::new(),
120 }
121 }
122
123 pub fn name(&self) -> &str {
124 &self.name
125 }
126 pub const fn func_type(&self) -> &FunctionType {
127 &self.func_type
128 }
129 pub const fn type_ref(&self) -> u32 {
130 self.func_type.type_ref()
131 }
132 pub fn params(&self) -> &[ValueType] {
133 self.func_type.params()
134 }
135 pub fn param_count(&self) -> u32 {
136 self.func_type.param_count()
137 }
138 pub const fn return_type(&self) -> Option<ValueType> {
139 self.func_type().return_type()
140 }
141 pub const fn is_imported(&self) -> bool {
142 self.is_imported
143 }
144 pub fn locals(&self) -> &[ValueType] {
145 &self.locals
146 }
147 pub fn instructions(&self) -> &[Instruction] {
148 &self.instructions
149 }
150}
151
152impl fmt::Display for Function {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 write!(f, "fn {}{}", self.name, &self.func_type.to_string()[3..])
155 }
156}
157
158#[derive(Clone, Copy, PartialEq, Debug)]
159pub enum InitExpr {
160 I32Const(i32),
161 I64Const(i64),
162 F32Const(u32),
163 F64Const(u64),
164 Global(u32),
165}
166
167impl TryFrom<&pwasm::InitExpr> for InitExpr {
168 type Error = String;
169
170 fn try_from(init_expr: &pwasm::InitExpr) -> Result<Self, Self::Error> {
171 let instrs = init_expr.code();
172 if instrs.len() != 2 {
173 return Err(format!("Init expr has invalid length: {}", instrs.len()));
174 }
175 if instrs[1] != Instruction::End {
176 return Err("Init expr has multiple instructions".to_string());
177 }
178 match &instrs[0] {
179 Instruction::I32Const(val) => Ok(InitExpr::I32Const(*val)),
180 Instruction::I64Const(val) => Ok(InitExpr::I64Const(*val)),
181 Instruction::F32Const(val) => Ok(InitExpr::F32Const(*val)),
182 Instruction::F64Const(val) => Ok(InitExpr::F64Const(*val)),
183 Instruction::GetGlobal(index) => Ok(InitExpr::Global(*index)),
184 other => Err(format!("Invalid instruction in init expr: {}", other)),
185 }
186 }
187}
188
189#[derive(Clone, PartialEq, Debug)]
190pub struct Global {
191 name: String,
192 is_imported: bool,
193 is_mutable: bool,
194 value_type: ValueType,
195 init_expr: InitExpr,
196}
197
198impl Global {
199 fn from_parity(name: String, global: &pwasm::GlobalEntry) -> Self {
200 let global_type = global.global_type();
201 Global {
202 name,
203 is_imported: false,
204 is_mutable: global_type.is_mutable(),
205 value_type: global_type.content_type(),
206 init_expr: global.init_expr().try_into().unwrap(),
207 }
208 }
209 fn from_import(name: String, index: u32, global_type: pwasm::GlobalType) -> Self {
210 Global {
211 name,
212 is_imported: true,
213 is_mutable: global_type.is_mutable(),
214 value_type: global_type.content_type(),
215 init_expr: InitExpr::Global(index),
216 }
217 }
218 pub fn name(&self) -> &str {
219 &self.name
220 }
221 pub const fn is_imported(&self) -> bool {
222 self.is_imported
223 }
224 pub const fn is_mutable(&self) -> bool {
225 self.is_mutable
226 }
227 pub const fn value_type(&self) -> ValueType {
228 self.value_type
229 }
230 pub const fn init_expr(&self) -> &InitExpr {
231 &self.init_expr
232 }
233}
234
235#[derive(Clone, Copy, PartialEq, Debug)]
236pub struct Table {
237 is_imported: bool,
238 elem_type: TableElementType,
239 limits: ResizableLimits,
240}
241
242impl Table {
243 pub const fn is_imported(&self) -> bool {
244 self.is_imported
245 }
246 pub const fn elem_type(&self) -> TableElementType {
247 self.elem_type
248 }
249 pub const fn limits(&self) -> &ResizableLimits {
250 &self.limits
251 }
252}
253
254#[derive(Clone, Copy, PartialEq, Debug)]
255pub struct Memory {
256 is_imported: bool,
257 limits: ResizableLimits,
258}
259
260impl Memory {
261 pub const fn is_imported(&self) -> bool {
262 self.is_imported
263 }
264 pub const fn limits(&self) -> &ResizableLimits {
265 &self.limits
266 }
267}
268
269#[derive(Clone, PartialEq, Debug)]
270pub struct TableInit {
271 index: u32,
272 offset: InitExpr,
273 entries: Vec<u32>,
274}
275
276impl TableInit {
277 pub const fn index(&self) -> u32 {
278 self.index
279 }
280 pub const fn offset(&self) -> &InitExpr {
281 &self.offset
282 }
283 pub fn entries(&self) -> &[u32] {
284 &self.entries
285 }
286}
287
288#[derive(Clone, PartialEq, Debug)]
289pub struct MemoryInit {
290 index: u32,
291 offset: InitExpr,
292 data: Vec<u8>,
293}
294
295impl MemoryInit {
296 pub const fn index(&self) -> u32 {
297 self.index
298 }
299 pub const fn offset(&self) -> &InitExpr {
300 &self.offset
301 }
302 pub fn data(&self) -> &[u8] {
303 &self.data
304 }
305}
306
307#[derive(Clone, PartialEq, Debug)]
308pub struct Module {
309 types: Vec<FunctionType>,
310 functions: Vec<Function>,
311 globals: Vec<Global>,
312 tables: Vec<Table>,
313 memories: Vec<Memory>,
314 table_inits: Vec<TableInit>,
315 memory_inits: Vec<MemoryInit>,
316 imports: Vec<ImportEntry>,
317 exports: Vec<ExportEntry>,
318 start_func: Option<u32>,
319 custom_sections: Vec<CustomSection>,
320}
321
322impl Module {
323 pub fn from_file<P: AsRef<::std::path::Path>>(path: P) -> Result<Self, LoadError> {
324 let module = parity_wasm::deserialize_file(path)?;
325 wasmi_validation::validate_module::<wasmi_validation::PlainValidator>(&module)?;
326 Ok(Module::from_parity_module(module))
327 }
328
329 fn from_parity_module(module: pwasm::Module) -> Self {
330 let mut module = match module.parse_names() {
332 Ok(module) => module,
333 Err((_, module)) => module,
334 };
335
336 let types = get_types(&mut module);
337
338 let mut globals = Vec::new();
339 let mut functions = Vec::new();
340 let mut tables = Vec::new();
341 let mut memories = Vec::new();
342 let mut imports = Vec::new();
343 let mut exports = Vec::new();
344
345 if let Some(import_sec) = module.import_section_mut() {
346 for entry in import_sec.entries() {
347 let name = format!("{}.{}", entry.module(), entry.field());
348 match entry.external() {
349 External::Function(type_ref) => {
350 let func_type = types[*type_ref as usize].clone();
351 functions.push(Function::new_imported(name, func_type))
352 }
353 External::Global(global_type) => globals.push(Global::from_import(
354 name,
355 globals.len() as u32,
356 *global_type,
357 )),
358 External::Table(table_type) => tables.push(Table {
359 is_imported: true,
360 elem_type: table_type.elem_type(),
361 limits: *table_type.limits(),
362 }),
363 External::Memory(memory_type) => memories.push(Memory {
364 is_imported: true,
365 limits: *memory_type.limits(),
366 }),
367 }
368 }
369 imports = take(import_sec.entries_mut());
370 }
371
372 handle_global_section(&mut globals, &module);
373 handle_function_section(&mut functions, &module, &types);
374 handle_table_section(&mut tables, &mut module);
375 handle_memory_section(&mut memories, &mut module);
376
377 if let Some(export_sec) = module.export_section_mut() {
378 for export in export_sec.entries() {
379 match export.internal() {
380 Internal::Function(index) => {
381 functions[*index as usize].name = export.field().to_string()
382 }
383 Internal::Global(index) => {
384 globals[*index as usize].name = export.field().to_string()
385 }
386 _ => (),
387 }
388 }
389 exports = take(export_sec.entries_mut());
390 }
391
392 if let Some(name_sec) = module.names_section() {
393 if let Some(func_names) = name_sec.functions() {
394 for (i, name) in func_names.names() {
395 functions[i as usize].name = name.clone();
396 }
397 }
398 }
399
400 Module {
401 types,
402 functions,
403 globals,
404 tables,
405 memories,
406 table_inits: get_table_inits(&mut module),
407 memory_inits: get_memory_inits(&mut module),
408 imports,
409 exports,
410 start_func: module.start_section(),
411 custom_sections: Vec::from_iter(module.custom_sections().cloned()),
412 }
413 }
414
415 pub fn types(&self) -> &[FunctionType] {
416 &self.types
417 }
418 pub fn functions(&self) -> &[Function] {
419 &self.functions
420 }
421 pub fn func(&self, index: u32) -> &Function {
422 &self.functions[index as usize]
423 }
424 pub fn get_func(&self, index: u32) -> Option<&Function> {
425 self.functions.get(index as usize)
426 }
427 pub fn globals(&self) -> &[Global] {
428 &self.globals
429 }
430 pub fn tables(&self) -> &[Table] {
431 &self.tables
432 }
433 pub fn memories(&self) -> &[Memory] {
434 &self.memories
435 }
436 pub fn table_inits(&self) -> &[TableInit] {
437 &self.table_inits
438 }
439 pub fn memory_inits(&self) -> &[MemoryInit] {
440 &self.memory_inits
441 }
442 pub fn imports(&self) -> &[ImportEntry] {
443 &self.imports
444 }
445 pub fn exports(&self) -> &[ExportEntry] {
446 &self.exports
447 }
448 pub const fn start_func(&self) -> Option<u32> {
449 self.start_func
450 }
451 pub fn custom_sections(&self) -> &[CustomSection] {
452 &self.custom_sections
453 }
454}
455
456fn get_types(module: &mut pwasm::Module) -> Vec<FunctionType> {
457 match module.type_section_mut() {
458 Some(type_sec) => type_sec
459 .types_mut()
460 .iter_mut()
461 .enumerate()
462 .map(|(i, t)| {
463 let pwasm::Type::Function(func_type) = t;
464 FunctionType::new(i as u32, func_type)
465 })
466 .collect(),
467 None => Vec::new(),
468 }
469}
470
471fn handle_global_section(globals: &mut Vec<Global>, module: &pwasm::Module) {
472 if let Some(global_sec) = module.global_section() {
473 for global in global_sec.entries() {
474 let name = format!("global_{}", globals.len());
475 globals.push(Global::from_parity(name, global));
476 }
477 }
478}
479
480fn handle_function_section(
481 functions: &mut Vec<Function>,
482 module: &pwasm::Module,
483 types: &[FunctionType],
484) {
485 if let Some(func_sec) = module.function_section() {
486 let func_bodies = module.code_section().map(|sec| sec.bodies()).unwrap_or(&[]);
487 for (type_ref, body) in func_sec.entries().iter().zip(func_bodies.iter()) {
488 let type_ref = type_ref.type_ref();
489 let name = format!("func_{}", functions.len());
490 let func_type = types[type_ref as usize].clone();
491 let locals = body
492 .locals()
493 .iter()
494 .flat_map(|locals| iter::repeat(locals.value_type()).take(locals.count() as usize))
495 .collect();
496 let instructions = body.code().elements().to_vec();
497 functions.push(Function::new(name, func_type, locals, instructions));
498 }
499 }
500}
501
502fn handle_table_section(tables: &mut Vec<Table>, module: &mut pwasm::Module) {
503 if let Some(table_sec) = module.table_section_mut() {
504 tables.extend(table_sec.entries_mut().drain(..).map(|table_type| Table {
505 is_imported: false,
506 elem_type: table_type.elem_type(),
507 limits: *table_type.limits(),
508 }));
509 }
510}
511
512fn handle_memory_section(memories: &mut Vec<Memory>, module: &mut pwasm::Module) {
513 if let Some(memory_sec) = module.memory_section_mut() {
514 memories.extend(
515 memory_sec
516 .entries_mut()
517 .drain(..)
518 .map(|memory_type| Memory {
519 is_imported: false,
520 limits: *memory_type.limits(),
521 }),
522 );
523 }
524}
525
526fn get_table_inits(module: &mut pwasm::Module) -> Vec<TableInit> {
527 let mut inits = Vec::new();
528 if let Some(elements_sec) = module.elements_section_mut() {
529 for init in elements_sec.entries_mut() {
530 inits.push(TableInit {
531 index: init.index(),
532 offset: init.offset().as_ref().unwrap().try_into().unwrap(),
533 entries: take(init.members_mut()),
534 });
535 }
536 }
537 inits
538}
539
540fn get_memory_inits(module: &mut pwasm::Module) -> Vec<MemoryInit> {
541 let mut inits = Vec::new();
542 if let Some(data_sec) = module.data_section_mut() {
543 for init in data_sec.entries_mut() {
544 inits.push(MemoryInit {
545 index: init.index(),
546 offset: init.offset().as_ref().unwrap().try_into().unwrap(),
547 data: take(init.value_mut()),
548 });
549 }
550 }
551 inits
552}
553
554fn take<T: Default>(t: &mut T) -> T {
555 std::mem::replace(t, T::default())
556}