1use std::fmt;
2use std::iter::{self, FromIterator};
3
4use failure::Fail;
5use parity_wasm::elements as pwasm;
6pub use parity_wasm::elements::{
7 CustomSection, ExportEntry, External, GlobalType, ImportEntry, Instruction, Internal,
8 MemoryType, ResizableLimits, TableType, ValueType,
9};
10pub use parity_wasm::SerializationError;
11pub use wasmi_validation::Error as ValidationError;
12
13use crate::value::Value;
14use crate::wasi::WasiFunction;
15
16pub const PAGE_SIZE: u32 = 64 * 1024; #[derive(Debug, Fail)]
19pub enum LoadError {
20 #[fail(display = "Error while loading file: {}", _0)]
21 SerializationError(#[fail(cause)] SerializationError),
22 #[fail(display = "Error while validating file: {}", _0)]
23 ValidationError(#[fail(cause)] ValidationError),
24}
25
26#[derive(Clone)]
27pub struct FunctionType {
28 type_ref: u32,
29 params: Vec<ValueType>,
30 return_type: Option<ValueType>,
31}
32
33impl FunctionType {
34 fn new(type_ref: u32, func_type: &pwasm::FunctionType) -> Self {
35 FunctionType {
36 type_ref,
37 params: Vec::from(func_type.params()),
38 return_type: func_type.return_type(),
39 }
40 }
41 pub fn type_ref(&self) -> u32 {
42 self.type_ref
43 }
44 pub fn params(&self) -> &[ValueType] {
45 &self.params
46 }
47 pub fn return_type(&self) -> Option<ValueType> {
48 self.return_type
49 }
50}
51
52impl fmt::Display for FunctionType {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 let params = self
55 .params
56 .iter()
57 .map(|t| t.to_string())
58 .collect::<Vec<String>>()
59 .join(", ");
60 let return_type = match self.return_type {
61 Some(return_type) => return_type.to_string(),
62 None => String::from("()"),
63 };
64 write!(f, "fn ({}) -> {}", params, return_type)
65 }
66}
67
68pub struct Function {
69 name: String,
70 func_type: FunctionType,
71 is_imported: bool,
72 wasi_function: Option<WasiFunction>,
73 locals: Vec<ValueType>,
74 instructions: Vec<Instruction>,
75}
76
77impl Function {
78 fn new(
79 name: String,
80 func_type: FunctionType,
81 locals: Vec<ValueType>,
82 instructions: Vec<Instruction>,
83 ) -> Self {
84 Function {
85 name,
86 func_type,
87 is_imported: false,
88 wasi_function: None,
89 locals,
90 instructions,
91 }
92 }
93
94 fn new_imported(name: String, func_type: FunctionType) -> Self {
95 let wasi_function = if name.starts_with("wasi_unstable.") {
96 WasiFunction::from_name(&name["wasi_unstable.".len()..])
98 } else {
99 None
100 };
101 Function {
102 name,
103 func_type,
104 is_imported: true,
105 wasi_function,
106 locals: Vec::with_capacity(0),
107 instructions: Vec::with_capacity(0),
108 }
109 }
110
111 pub fn name(&self) -> &str {
112 &self.name
113 }
114 pub fn func_type(&self) -> &FunctionType {
115 &self.func_type
116 }
117 pub fn is_imported(&self) -> bool {
118 self.is_imported
119 }
120 pub fn wasi_function(&self) -> Option<WasiFunction> {
121 self.wasi_function
122 }
123 pub fn locals(&self) -> &[ValueType] {
124 &self.locals
125 }
126 pub fn instructions(&self) -> &[Instruction] {
127 &self.instructions
128 }
129}
130
131impl fmt::Display for Function {
132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133 write!(f, "fn {}{}", self.name, &self.func_type.to_string()[3..])
134 }
135}
136
137pub enum InitExpr {
138 Const(Value),
139 Global(u32),
140}
141
142impl From<&pwasm::InitExpr> for InitExpr {
143 fn from(init_expr: &pwasm::InitExpr) -> Self {
144 let instrs = init_expr.code();
145 assert!(
146 instrs.len() == 2,
147 "Init expr has invalid length: {}",
148 instrs.len()
149 );
150 assert!(
151 instrs[1] == Instruction::End,
152 "Init expr has multiple instructions"
153 );
154 match &instrs[0] {
155 Instruction::I32Const(val) => InitExpr::Const((*val).into()),
156 Instruction::I64Const(val) => InitExpr::Const((*val).into()),
157 Instruction::F32Const(val) => InitExpr::Const((*val).into()),
158 Instruction::F64Const(val) => InitExpr::Const((*val).into()),
159 Instruction::GetGlobal(index) => InitExpr::Global(*index),
160 other => panic!("Invalid instruction in init expr: {}", other),
161 }
162 }
163}
164
165pub struct Global {
166 name: String,
167 is_imported: bool,
168 is_mutable: bool,
169 value_type: ValueType,
170 init_expr: InitExpr,
171}
172
173impl Global {
174 fn from_parity(name: String, global: &pwasm::GlobalEntry) -> Self {
175 let global_type = global.global_type();
176 Global {
177 name,
178 is_imported: false,
179 is_mutable: global_type.is_mutable(),
180 value_type: global_type.content_type(),
181 init_expr: global.init_expr().into(),
182 }
183 }
184 pub fn name(&self) -> &str {
185 &self.name
186 }
187 pub fn is_imported(&self) -> bool {
188 self.is_imported
189 }
190 pub fn is_mutable(&self) -> bool {
191 self.is_mutable
192 }
193 pub fn value_type(&self) -> ValueType {
194 self.value_type
195 }
196 pub fn init_expr(&self) -> &InitExpr {
197 &self.init_expr
198 }
199}
200
201impl fmt::Display for Global {
202 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203 let const_str = if self.is_mutable() { "mut " } else { "const" };
204 let init_str = match self.init_expr() {
205 InitExpr::Const(val) => format!("{}", val),
206 InitExpr::Global(index) => format!("global {}", index),
207 };
208 write!(f, "{} {:15} = {}", const_str, self.name(), init_str)
209 }
210}
211
212pub struct ElementSegment {
213 index: u32,
214 offset: InitExpr,
215 members: Vec<u32>,
216}
217
218impl ElementSegment {
219 pub fn index(&self) -> u32 {
220 self.index
221 }
222 pub fn offset(&self) -> &InitExpr {
223 &self.offset
224 }
225 pub fn members(&self) -> &[u32] {
226 &self.members
227 }
228}
229
230impl From<&pwasm::ElementSegment> for ElementSegment {
231 fn from(seg: &pwasm::ElementSegment) -> Self {
232 ElementSegment {
233 index: seg.index(),
234 offset: seg.offset().as_ref().unwrap().into(),
235 members: Vec::from(seg.members()),
236 }
237 }
238}
239
240pub struct DataSegment {
241 index: u32,
242 offset: InitExpr,
243 value: Vec<u8>,
244}
245
246impl DataSegment {
247 pub fn index(&self) -> u32 {
248 self.index
249 }
250 pub fn offset(&self) -> &InitExpr {
251 &self.offset
252 }
253 pub fn value(&self) -> &[u8] {
254 &self.value
255 }
256}
257
258impl From<&pwasm::DataSegment> for DataSegment {
259 fn from(seg: &pwasm::DataSegment) -> Self {
260 DataSegment {
261 index: seg.index(),
262 offset: seg.offset().as_ref().unwrap().into(),
263 value: Vec::from(seg.value()),
264 }
265 }
266}
267
268pub struct Module {
269 types: Vec<FunctionType>,
270 imports: Vec<ImportEntry>,
271 exports: Vec<ExportEntry>,
272 functions: Vec<Function>,
273 globals: Vec<Global>,
274 tables: Vec<TableType>,
275 memories: Vec<MemoryType>,
276 element_entries: Vec<ElementSegment>,
277 data_entries: Vec<DataSegment>,
278 start_func: Option<u32>,
279 custom_sections: Vec<CustomSection>,
280}
281
282impl Module {
283 pub fn from_file(file_path: &str) -> Result<Self, LoadError> {
284 match parity_wasm::deserialize_file(file_path) {
285 Ok(module) => {
286 if let Err(error) =
287 wasmi_validation::validate_module::<wasmi_validation::PlainValidator>(&module)
288 {
289 return Err(LoadError::ValidationError(error));
290 }
291 Ok(Module::from_parity_module(module))
292 }
293 Err(error) => Err(LoadError::SerializationError(error)),
294 }
295 }
296
297 fn from_parity_module(module: parity_wasm::elements::Module) -> Self {
298 let module = match module.parse_names() {
300 Ok(module) => module,
301 Err((errors, module)) => {
302 for (_, error) in errors {
303 println!("Failed to parse name section: {}", error);
304 }
305 module
306 }
307 };
308
309 let mut types = Vec::new();
310 if let Some(type_sec) = module.type_section() {
311 for (i, t) in type_sec.types().iter().enumerate() {
312 let pwasm::Type::Function(func_type) = t;
313 types.push(FunctionType::new(i as u32, func_type));
314 }
315 }
316
317 let mut globals = Vec::new();
318 if let Some(global_sec) = module.global_section() {
319 for (i, global) in global_sec.entries().iter().enumerate() {
320 let name = format!("g{}", i);
321 globals.push(Global::from_parity(name, global));
322 }
323 }
324
325 let mut element_entries = Vec::new();
326 if let Some(element_sec) = module.elements_section() {
327 for entry in element_sec.entries() {
328 element_entries.push(entry.into());
329 }
330 }
331
332 let mut data_entries = Vec::new();
333 if let Some(data_sec) = module.data_section() {
334 for entry in data_sec.entries() {
335 data_entries.push(entry.into());
336 }
337 }
338
339 let func_count = module
340 .function_section()
341 .map(|sec| sec.entries().len())
342 .unwrap_or(0);
343 let mut functions = Vec::with_capacity(func_count);
344
345 if let Some(import_sec) = module.import_section() {
346 for entry in import_sec.entries() {
347 if let pwasm::External::Function(type_ref) = entry.external() {
348 let name = format!("{}.{}", entry.module(), entry.field());
349 let func_type = types[*type_ref as usize].clone();
350 functions.push(Function::new_imported(name, func_type))
351 } else {
352 println!("Unsupported import: {:?}", entry);
353 }
354 }
355 }
356
357 if let Some(func_sec) = module.function_section() {
358 let func_bodies = module.code_section().map(|sec| sec.bodies()).unwrap_or(&[]);
359 for (type_ref, body) in func_sec.entries().iter().zip(func_bodies.iter()) {
360 let type_ref = type_ref.type_ref();
361 let name = format!("f{}", functions.len());
362 let func_type = types[type_ref as usize].clone();
363 let locals = body
364 .locals()
365 .iter()
366 .flat_map(|locals| {
367 iter::repeat(locals.value_type()).take(locals.count() as usize)
368 })
369 .collect();
370 let instructions = Vec::from(body.code().elements());
371 functions.push(Function::new(name, func_type, locals, instructions));
372 }
373 }
374
375 let imports = Vec::from(
376 module
377 .import_section()
378 .map(|sec| sec.entries())
379 .unwrap_or(&[]),
380 );
381 let exports = Vec::from(
382 module
383 .export_section()
384 .map(|sec| sec.entries())
385 .unwrap_or(&[]),
386 );
387 let tables = Vec::from(
388 module
389 .table_section()
390 .map(|sec| sec.entries())
391 .unwrap_or(&[]),
392 );
393 let memories = Vec::from(
394 module
395 .memory_section()
396 .map(|sec| sec.entries())
397 .unwrap_or(&[]),
398 );
399
400 for export in &exports {
401 match export.internal() {
402 Internal::Function(index) => {
403 functions[*index as usize].name = export.field().to_string()
404 }
405 Internal::Global(index) => {
406 globals[*index as usize].name = export.field().to_string()
407 }
408 _ => (),
409 }
410 }
411
412 if let Some(name_sec) = module.names_section() {
413 if let Some(func_names) = name_sec.functions() {
414 for (i, name) in func_names.names() {
415 functions[i as usize].name = name.clone();
416 }
417 }
418 }
419
420 let start_func = module.start_section().or_else(|| {
421 for export in &exports {
422 if export.field() == "_start" {
423 if let Internal::Function(index) = export.internal() {
424 let index = *index;
425 let func_type = functions[index as usize].func_type();
426 if func_type.params().is_empty() && func_type.return_type().is_none() {
427 return Some(index);
428 }
429 }
430 }
431 }
432 None
433 });
434
435 Module {
436 types,
437 imports,
438 exports,
439 functions,
440 globals,
441 tables,
442 memories,
443 element_entries,
444 data_entries,
445 start_func,
446 custom_sections: Vec::from_iter(module.custom_sections().cloned()),
447 }
448 }
449
450 pub fn types(&self) -> &[FunctionType] {
451 &self.types
452 }
453
454 pub fn imports(&self) -> &[ImportEntry] {
455 &self.imports
456 }
457
458 pub fn exports(&self) -> &[ExportEntry] {
459 &self.exports
460 }
461
462 pub fn functions(&self) -> &[Function] {
463 &self.functions
464 }
465
466 pub fn get_func(&self, index: u32) -> Option<&Function> {
467 self.functions.get(index as usize)
468 }
469
470 pub fn globals(&self) -> &[Global] {
471 &self.globals
472 }
473
474 pub fn tables(&self) -> &[TableType] {
475 &self.tables
476 }
477
478 pub fn memories(&self) -> &[MemoryType] {
479 &self.memories
480 }
481
482 pub fn element_entries(&self) -> &[ElementSegment] {
483 &self.element_entries
484 }
485
486 pub fn data_entries(&self) -> &[DataSegment] {
487 &self.data_entries
488 }
489
490 pub fn start_func(&self) -> Option<u32> {
491 self.start_func
492 }
493
494 pub fn custom_sections(&self) -> &[CustomSection] {
495 &self.custom_sections
496 }
497}