parity-wasm/src/elements/section.rs

467 lines
13 KiB
Rust
Raw Normal View History

2017-03-29 18:16:58 +03:00
use std::io;
2017-03-30 23:57:36 +03:00
use super::{
Deserialize,
Unparsed,
Error,
VarUint7,
VarUint32,
CountedList,
ImportEntry,
MemoryType,
TableType,
2017-03-31 01:54:04 +03:00
ExportEntry,
2017-03-31 17:31:33 +03:00
GlobalEntry,
2017-04-03 13:18:50 +03:00
FuncBody,
2017-03-30 23:57:36 +03:00
};
2017-03-29 23:13:54 +03:00
use super::types::Type;
2017-03-29 18:16:58 +03:00
2017-03-29 23:13:54 +03:00
pub enum Section {
Unparsed {
id: u8,
payload: Vec<u8>,
},
Custom(Vec<u8>),
Type(TypeSection),
2017-03-30 20:55:25 +03:00
Import(ImportSection),
2017-03-30 23:23:54 +03:00
Function(FunctionsSection),
2017-03-30 23:57:36 +03:00
Table(TableSection),
Memory(MemorySection),
2017-03-31 17:31:33 +03:00
Global(GlobalSection),
2017-03-31 01:54:04 +03:00
Export(ExportSection),
2017-03-31 03:28:03 +03:00
Start(u32),
2017-03-31 04:04:51 +03:00
Code(CodeSection),
2017-03-29 18:16:58 +03:00
}
impl Deserialize for Section {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
2017-03-29 19:40:51 +03:00
let id = match VarUint7::deserialize(reader) {
// todo: be more selective detecting no more section
Err(_) => { return Err(Error::UnexpectedEof); },
Ok(id) => id,
};
2017-03-29 23:13:54 +03:00
Ok(
match id.into() {
0 => {
Section::Custom(Unparsed::deserialize(reader)?.into())
},
1 => {
Section::Type(TypeSection::deserialize(reader)?)
},
2017-03-30 20:55:25 +03:00
2 => {
Section::Import(ImportSection::deserialize(reader)?)
},
2017-03-30 23:23:54 +03:00
3 => {
Section::Function(FunctionsSection::deserialize(reader)?)
},
2017-03-30 23:57:36 +03:00
4 => {
Section::Table(TableSection::deserialize(reader)?)
},
5 => {
Section::Memory(MemorySection::deserialize(reader)?)
2017-03-31 01:54:04 +03:00
},
2017-03-31 17:31:33 +03:00
6 => {
Section::Global(GlobalSection::deserialize(reader)?)
},
2017-03-31 01:54:04 +03:00
7 => {
Section::Export(ExportSection::deserialize(reader)?)
},
2017-03-31 03:28:03 +03:00
8 => {
let _section_length = VarUint32::deserialize(reader)?;
Section::Start(VarUint32::deserialize(reader)?.into())
},
2017-03-31 04:04:51 +03:00
10 => {
Section::Code(CodeSection::deserialize(reader)?)
},
2017-03-29 23:13:54 +03:00
_ => {
Section::Unparsed { id: id.into(), payload: Unparsed::deserialize(reader)?.into() }
}
}
)
2017-03-29 18:16:58 +03:00
}
2017-03-29 23:13:54 +03:00
}
2017-03-30 20:55:25 +03:00
pub struct TypeSection(Vec<Type>);
2017-03-29 23:13:54 +03:00
impl TypeSection {
2017-03-30 20:55:25 +03:00
pub fn types(&self) -> &[Type] {
&self.0
2017-03-29 23:13:54 +03:00
}
}
impl Deserialize for TypeSection {
2017-03-30 20:55:25 +03:00
type Error = Error;
2017-03-29 23:13:54 +03:00
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
// todo: maybe use reader.take(section_length)
let _section_length = VarUint32::deserialize(reader)?;
let types: Vec<Type> = CountedList::deserialize(reader)?.into_inner();
2017-03-30 20:55:25 +03:00
Ok(TypeSection(types))
}
}
pub struct ImportSection(Vec<ImportEntry>);
impl ImportSection {
pub fn entries(&self) -> &[ImportEntry] {
&self.0
}
}
impl Deserialize for ImportSection {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
// todo: maybe use reader.take(section_length)
let _section_length = VarUint32::deserialize(reader)?;
let entries: Vec<ImportEntry> = CountedList::deserialize(reader)?.into_inner();
Ok(ImportSection(entries))
2017-03-29 23:13:54 +03:00
}
}
2017-03-30 23:23:54 +03:00
/// Function signature (type reference)
pub struct Function(pub u32);
2017-03-30 23:49:26 +03:00
impl Function {
2017-03-30 23:57:36 +03:00
pub fn type_ref(&self) -> u32 {
2017-03-30 23:49:26 +03:00
self.0
}
}
2017-03-30 23:23:54 +03:00
pub struct FunctionsSection(Vec<Function>);
impl FunctionsSection {
pub fn entries(&self) -> &[Function] {
&self.0
}
}
impl Deserialize for FunctionsSection {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
// todo: maybe use reader.take(section_length)
let _section_length = VarUint32::deserialize(reader)?;
let funcs: Vec<Function> = CountedList::<VarUint32>::deserialize(reader)?
.into_inner()
.into_iter()
.map(|f| Function(f.into()))
.collect();
Ok(FunctionsSection(funcs))
}
}
2017-03-30 23:57:36 +03:00
pub struct TableSection(Vec<TableType>);
impl TableSection {
pub fn entries(&self) -> &[TableType] {
&self.0
}
}
impl Deserialize for TableSection {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
// todo: maybe use reader.take(section_length)
let _section_length = VarUint32::deserialize(reader)?;
let entries: Vec<TableType> = CountedList::deserialize(reader)?.into_inner();
Ok(TableSection(entries))
}
}
pub struct MemorySection(Vec<MemoryType>);
impl MemorySection {
pub fn entries(&self) -> &[MemoryType] {
&self.0
}
}
impl Deserialize for MemorySection {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
// todo: maybe use reader.take(section_length)
let _section_length = VarUint32::deserialize(reader)?;
let entries: Vec<MemoryType> = CountedList::deserialize(reader)?.into_inner();
Ok(MemorySection(entries))
}
}
2017-03-30 23:23:54 +03:00
2017-03-31 17:31:33 +03:00
pub struct GlobalSection(Vec<GlobalEntry>);
impl GlobalSection {
pub fn entries(&self) -> &[GlobalEntry] {
&self.0
}
}
impl Deserialize for GlobalSection {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
// todo: maybe use reader.take(section_length)
let _section_length = VarUint32::deserialize(reader)?;
let entries: Vec<GlobalEntry> = CountedList::deserialize(reader)?.into_inner();
Ok(GlobalSection(entries))
}
}
2017-03-31 01:54:04 +03:00
pub struct ExportSection(Vec<ExportEntry>);
impl ExportSection {
pub fn entries(&self) -> &[ExportEntry] {
&self.0
}
}
impl Deserialize for ExportSection {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
// todo: maybe use reader.take(section_length)
let _section_length = VarUint32::deserialize(reader)?;
let entries: Vec<ExportEntry> = CountedList::deserialize(reader)?.into_inner();
Ok(ExportSection(entries))
}
}
2017-04-03 13:18:50 +03:00
pub struct CodeSection(Vec<FuncBody>);
2017-03-31 04:04:51 +03:00
impl CodeSection {
2017-04-03 13:18:50 +03:00
pub fn bodies(&self) -> &[FuncBody] {
2017-03-31 04:04:51 +03:00
&self.0
}
}
impl Deserialize for CodeSection {
type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
// todo: maybe use reader.take(section_length)
let _section_length = VarUint32::deserialize(reader)?;
2017-04-03 13:18:50 +03:00
let entries: Vec<FuncBody> = CountedList::deserialize(reader)?.into_inner();
2017-03-31 04:04:51 +03:00
Ok(CodeSection(entries))
}
}
2017-03-29 23:13:54 +03:00
#[cfg(test)]
mod tests {
2017-03-30 23:49:26 +03:00
use super::super::{deserialize_buffer, deserialize_file, ValueType};
2017-03-30 20:55:25 +03:00
use super::{Section, TypeSection, Type};
#[test]
fn import_section() {
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
let mut found = false;
for section in module.sections() {
match section {
&Section::Import(ref import_section) => {
assert_eq!(25, import_section.entries().len());
found = true
},
_ => { }
}
}
assert!(found, "There should be import section in test5.wasm");
}
2017-03-29 23:13:54 +03:00
2017-03-30 23:49:26 +03:00
fn functions_test_payload() -> Vec<u8> {
vec![
// functions section id
0x03u8,
// functions section length
0x87, 0x80, 0x80, 0x80, 0x0,
// number of functions
0x04,
// type reference 1
0x01,
// type reference 2
0x86, 0x80, 0x00,
// type reference 3
0x09,
// type reference 4
0x33
]
}
2017-03-29 23:13:54 +03:00
#[test]
2017-03-30 23:49:26 +03:00
fn fn_section_detect() {
let section: Section =
deserialize_buffer(functions_test_payload()).expect("section to be deserialized");
match section {
Section::Function(_) => {},
_ => {
panic!("Payload should be recognized as functions section")
}
}
}
#[test]
fn fn_section_number() {
let section: Section =
deserialize_buffer(functions_test_payload()).expect("section to be deserialized");
match section {
Section::Function(fn_section) => {
assert_eq!(4, fn_section.entries().len(), "There should be 4 functions total");
},
_ => {
// will be catched by dedicated test
}
}
}
#[test]
fn fn_section_ref() {
let section: Section =
deserialize_buffer(functions_test_payload()).expect("section to be deserialized");
match section {
Section::Function(fn_section) => {
assert_eq!(6, fn_section.entries()[1].type_ref());
},
_ => {
// will be catched by dedicated test
}
}
}
fn types_test_payload() -> Vec<u8> {
vec![
// section length
148u8, 0x80, 0x80, 0x80, 0x0,
// 2 functions
130u8, 0x80, 0x80, 0x80, 0x0,
// func 1, form =1
2017-03-29 23:13:54 +03:00
0x01,
// param_count=1
129u8, 0x80, 0x80, 0x80, 0x0,
// first param
0x7e, // i64
// no return params
2017-03-30 23:49:26 +03:00
0x00,
// func 2, form=1
0x01,
// param_count=1
130u8, 0x80, 0x80, 0x80, 0x0,
// first param
0x7e,
// second param
0x7d,
// return param (is_present, param_type)
0x01, 0x7e
]
}
#[test]
fn type_section_len() {
let type_section: TypeSection =
deserialize_buffer(types_test_payload()).expect("type_section be deserialized");
assert_eq!(type_section.types().len(), 2);
}
2017-03-29 23:13:54 +03:00
2017-03-30 23:49:26 +03:00
#[test]
fn type_section_infer() {
2017-03-29 23:13:54 +03:00
let type_section: TypeSection =
2017-03-30 23:49:26 +03:00
deserialize_buffer(types_test_payload()).expect("type_section be deserialized");
2017-03-29 23:13:54 +03:00
2017-03-30 23:49:26 +03:00
let t1 = match &type_section.types()[1] {
2017-03-30 23:57:36 +03:00
&Type::Function(ref func_type) => func_type
2017-03-30 23:49:26 +03:00
};
assert_eq!(Some(ValueType::I64), t1.return_type());
assert_eq!(2, t1.params().len());
2017-03-29 23:13:54 +03:00
}
2017-03-31 01:54:04 +03:00
fn export_payload() -> Vec<u8> {
vec![
// section id
0x07,
// section length
148u8, 0x80, 0x80, 0x80, 0x0,
// 6 entries
134u8, 0x80, 0x80, 0x80, 0x0,
// func "A", index 6
// [name_len(1-5 bytes), name_bytes(name_len, internal_kind(1byte), internal_index(1-5 bytes)])
2017-03-31 04:39:31 +03:00
0x01, 0x41, 0x01, 0x86, 0x80, 0x00,
2017-03-31 01:54:04 +03:00
// func "B", index 8
2017-03-31 04:39:31 +03:00
0x01, 0x42, 0x01, 0x86, 0x00,
2017-03-31 01:54:04 +03:00
// func "C", index 7
2017-03-31 04:39:31 +03:00
0x01, 0x43, 0x01, 0x07,
2017-03-31 01:54:04 +03:00
// memory "D", index 0
2017-03-31 04:39:31 +03:00
0x01, 0x44, 0x02, 0x00,
2017-03-31 01:54:04 +03:00
// func "E", index 1
2017-03-31 04:39:31 +03:00
0x01, 0x45, 0x01, 0x01,
2017-03-31 01:54:04 +03:00
// func "F", index 2
2017-03-31 04:39:31 +03:00
0x01, 0x46, 0x01, 0x02
2017-03-31 01:54:04 +03:00
]
}
#[test]
fn export_detect() {
let section: Section =
deserialize_buffer(export_payload()).expect("section to be deserialized");
match section {
Section::Export(_) => {},
_ => {
panic!("Payload should be recognized as export section")
}
}
}
2017-03-31 04:04:51 +03:00
fn code_payload() -> Vec<u8> {
vec![
// sectionid
0x0Au8,
// section length, 32
0x20,
// body count
0x01,
// body 1, length 30
0x1E,
0x01, 0x01, 0x7F, // local i32 (one collection of length one of type i32)
0x02, 0x7F, // block i32
0x23, 0x00, // get_global 0
0x21, 0x01, // set_local 1
0x23, 0x00, // get_global 0
0x20, 0x00, // get_local 0
0x6A, // i32.add
0x24, 0x00, // set_global 0
0x23, 0x00, // get_global 0
0x41, 0x0F, // i32.const 15
0x6A, // i32.add
0x41, 0x70, // i32.const -16
0x71, // i32.and
0x24, 0x00, // set_global 0
0x20, 0x01, // get_local 1
0x0B,
0x0B,
]
}
#[test]
fn code_detect() {
let section: Section =
deserialize_buffer(code_payload()).expect("section to be deserialized");
match section {
Section::Code(_) => {},
_ => {
panic!("Payload should be recognized as a code section")
}
}
}
2017-03-29 18:16:58 +03:00
}