From f2cd79c49efcb5e2c6df88e465aa1de63a467f5e Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Wed, 5 Jun 2019 19:00:34 +1000 Subject: [PATCH 01/22] wasm-parser: remove parity-wasm dependency --- kernel-ewasm/validator/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel-ewasm/validator/Cargo.toml b/kernel-ewasm/validator/Cargo.toml index 1cddcf1..8460fcb 100644 --- a/kernel-ewasm/validator/Cargo.toml +++ b/kernel-ewasm/validator/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Daohub Inc "] edition = "2018" [dependencies] -parity-wasm = { version = "0.35", default-features = false } +# parity-wasm = { version = "0.35", default-features = false } pwasm-std = {version = "0.13", default-features = false} pwasm-ethereum = {version = "0.8", default-features = false} @@ -18,7 +18,7 @@ default-features = false [features] default = ["std"] -std = ["parity-wasm/std", "pwasm-std/std", "pwasm-ethereum/std", "pwasm-test/std"] +std = ["pwasm-std/std", "pwasm-ethereum/std", "pwasm-test/std"] [lib] name = "validator" From dc5b0edccb3da129b2851fb0a89ec8e561639e28 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Wed, 5 Jun 2019 19:32:28 +1000 Subject: [PATCH 02/22] wasm-parser: proof of basic idea --- kernel-ewasm/validator/src/lib.rs | 576 ++++++++++++++++++------------ 1 file changed, 352 insertions(+), 224 deletions(-) diff --git a/kernel-ewasm/validator/src/lib.rs b/kernel-ewasm/validator/src/lib.rs index 303ee49..b7e917d 100644 --- a/kernel-ewasm/validator/src/lib.rs +++ b/kernel-ewasm/validator/src/lib.rs @@ -1,15 +1,15 @@ -#![no_std] +// #![no_std] use pwasm_std; -use parity_wasm; +// use parity_wasm; -pub use parity_wasm::elements::{ImportEntry, Module}; -use parity_wasm::elements::Instruction; -use parity_wasm::elements::{ValueType}; +// pub use parity_wasm::elements::{ImportEntry, Module}; +// use parity_wasm::elements::Instruction; +// use parity_wasm::elements::{ValueType}; use pwasm_std::vec::Vec; -pub use parity_wasm::deserialize_buffer; +// pub use parity_wasm::deserialize_buffer; /// As per the wasm spec: /// @@ -49,50 +49,50 @@ pub trait Listed { fn listing(&self) -> Listing; } -impl Listed for ImportEntry { - fn listing(&self) -> Listing { - // Nothing should need to be imported from outside "env", but let's - // blacklist it just in case. - if self.module() != "env" { - Listing::Black - } else { - // Tehcnically we don't have to list blacklisted items here, but we - // do just for clarity. - match self.field() { - "memory" => Listing::White, - "storage_read" => Listing::White, - "storage_write" => Listing::Black, - "ret" => Listing::White, - "gas" => Listing::White, - "input_length" => Listing::White, - "fetch_input" => Listing::White, - "panic" => Listing::White, - "debug" => Listing::White, - "ccall" => Listing::Black, - "dcall" => Listing::Grey, - "scall" => Listing::White, - "value" => Listing::White, - "create" => Listing::Black, - "suicide" => Listing::White, - "blockhash" => Listing::White, - "blocknumber" => Listing::White, - "coinbase" => Listing::White, - "difficulty" => Listing::White, - "gaslimit" => Listing::White, - "timestamp" => Listing::White, - "address" => Listing::White, - "sender" => Listing::White, - "origin" => Listing::White, - "elog" => Listing::Black, - "extcodesize" => Listing::White, - "extcodecopy" => Listing::White, - "create2" => Listing::Black, - "gasleft" => Listing::White, - _ => Listing::Black, - } - } - } -} +// impl Listed for ImportEntry { +// fn listing(&self) -> Listing { +// // Nothing should need to be imported from outside "env", but let's +// // blacklist it just in case. +// if self.module() != "env" { +// Listing::Black +// } else { +// // Tehcnically we don't have to list blacklisted items here, but we +// // do just for clarity. +// match self.field() { +// "memory" => Listing::White, +// "storage_read" => Listing::White, +// "storage_write" => Listing::Black, +// "ret" => Listing::White, +// "gas" => Listing::White, +// "input_length" => Listing::White, +// "fetch_input" => Listing::White, +// "panic" => Listing::White, +// "debug" => Listing::White, +// "ccall" => Listing::Black, +// "dcall" => Listing::Grey, +// "scall" => Listing::White, +// "value" => Listing::White, +// "create" => Listing::Black, +// "suicide" => Listing::White, +// "blockhash" => Listing::White, +// "blocknumber" => Listing::White, +// "coinbase" => Listing::White, +// "difficulty" => Listing::White, +// "gaslimit" => Listing::White, +// "timestamp" => Listing::White, +// "address" => Listing::White, +// "sender" => Listing::White, +// "origin" => Listing::White, +// "elog" => Listing::Black, +// "extcodesize" => Listing::White, +// "extcodecopy" => Listing::White, +// "create2" => Listing::Black, +// "gasleft" => Listing::White, +// _ => Listing::Black, +// } +// } +// } +// } /// Information on why the contract was considered invalid. #[derive(Debug)] @@ -102,9 +102,9 @@ pub struct ValidityReport { #[derive(Debug)] pub enum ValidityError { - BlacklistedImport(ImportEntry), + // BlacklistedImport(ImportEntry), UnsafeGreylistedCall { - import: ImportEntry, + // import: ImportEntry, function_index: u32, instruction_index: u32, }, @@ -116,180 +116,309 @@ pub trait Validity { fn validity(&self) -> ValidityReport; } -impl Validity for Module { +// Seek does not seem to be implemented in core, so we'll reimplement what we +// need. +#[derive(Debug)] +struct Cursor { + i: usize, + // data: &'a [u8], +} + +impl<'a> Cursor { + // Read the byte at the cusor, and increment the pointer by 1. + fn read(&mut self, data: &'a [u8]) -> &'a u8 { + let val = &data[self.i]; + self.i += 1; + val + } + + fn read_n(&mut self, n: usize, data: &'a [u8]) -> &'a [u8] { + let val = &data[self.i..(self.i+n)]; + self.i += n; + val + } +} + +impl Validity for &[u8] { fn is_valid(&self) -> bool { self.validity().validation_errors.len() == 0 } fn validity(&self) -> ValidityReport { - let imports = get_imports(self); + // let imports = get_imports(self); let mut report = ValidityReport { validation_errors: Vec::new() }; - // TODO: this i value needs to be checked to ensure it is as defined by - // the standard. - for (import_index, import) in imports.iter().enumerate() { - match import.listing() { - Listing::White => (), - Listing::Grey => { - // Check that this grey import is called safely, wherever is - // is called. - for (function_index,instruction_index) in check_grey(self, import_index) { - report.validation_errors.push(ValidityError::UnsafeGreylistedCall { - import: import.clone(), - function_index, - instruction_index, - }); - } - }, - Listing::Black => { - report.validation_errors.push(ValidityError::BlacklistedImport(import.clone())); - }, - } + // First we create a cursor from out data. + + println!("data: {:?}", self); + let mut sections = Vec::new(); + // Set an index value, which is our offset into the wasm bytes. + let mut cursor = Cursor { + i: 0, + // data: self, + }; + // Take the magic number, check that it matches + if cursor.read_n(4, &self) != &[0, 97, 115, 109] { + panic!("magic number not found"); + } + + // println!("cursor4: {:?}", cursor.read_n(4)); + + // Take the version, check that it matches + if cursor.read_n(4, &self) != &[1, 0, 0, 0] { + panic!("proper version number not found"); + } + + // Now we should be at the first section + while cursor.i < self.len() { + // let section: Section = parse_section(&mut i, &self[d..]); + // println!("i: {:?}", cursor.i); + let section: Section = parse_section(&mut cursor, &self); + println!("section: {:?}", section); + sections.push(section); } + if cursor.i != self.len() { + panic!("mismatched length"); + } + + // for (import_index, import) in imports.iter().enumerate() { + // match import.listing() { + // Listing::White => (), + // Listing::Grey => { + // // Check that this grey import is called safely, wherever is + // // is called. + // for (function_index,instruction_index) in check_grey(self, import_index) { + // report.validation_errors.push(ValidityError::UnsafeGreylistedCall { + // import: import.clone(), + // function_index, + // instruction_index, + // }); + // } + // }, + // Listing::Black => { + // report.validation_errors.push(ValidityError::BlacklistedImport(import.clone())); + // }, + // } + // } report } } -fn get_imports(module: &Module) -> Vec { - if let Some(import_section) = module.import_section() { - import_section.entries().to_vec() - } else { - Vec::new() - } +#[derive(Debug)] +enum SectionType { + Custom, + Type, + Import, + Function, + Table, + Memory, + Global, + Export, + Start, + Element, + Code, + Data, } -fn check_grey(module: &Module, grey_index: usize) -> Vec<(u32, u32)> { - let mut uses = Vec::new(); - let code_section = module.code_section().unwrap(); - let codes = Vec::from(code_section.bodies()); - // If the instruction Call(grey_index) exists in the body of the function, that is a dangerous function. - let this_call = parity_wasm::elements::Instruction::Call(grey_index as u32); - for (func_index, func_body) in codes.iter().enumerate() { - for (instruction_index, instruction) in func_body.code().elements().iter().enumerate() { - if instruction == &this_call && !is_syscall(module, func_index as u32) { - uses.push((func_index as u32, instruction_index as u32)); - } - } - } - uses +#[derive(Debug)] +struct Section<'a> { + type_: SectionType, + data: &'a [u8], } -// Find the function index of an import -pub fn find_import(module: &Module, mod_name: &str, field_name: &str) -> Option { - let imports = module.import_section().unwrap().entries(); - for (i,import) in imports.iter().enumerate() { - if import.module() == mod_name && import.field() == field_name { - return Some(i as u32); - } - } - return None; +fn parse_section<'a>(cursor: &mut Cursor, data: &'a [u8]) -> Section<'a> { + let type_n = cursor.read(data); + // println!("type_n: {:?}", type_n); + let size_n = parse_varuint_32(cursor, data); + // println!("size_n: {:?}", size_n); + let type_ = n_to_section(type_n); + let section = Section { + type_, + // data: &cursor.data[0..0], + data: &data[(cursor.i)..(cursor.i+size_n as usize)], + }; + cursor.i += size_n as usize; + section } -pub fn is_syscall(module: &Module, function_index: u32) -> bool { - - let function_section = module.function_section().unwrap(); - let functions = Vec::from(function_section.entries()); - let function = functions.get(function_index as usize).unwrap(); - let type_index = function.type_ref(); - - let type_section = module.type_section().unwrap(); - let types = Vec::from(type_section.types()); - let this_type = types.get(type_index as usize).unwrap(); - - let code_section = module.code_section().unwrap(); - let codes = Vec::from(code_section.bodies()); - let code = codes.get(function_index as usize).unwrap(); - let instructions = Vec::from(code.code().elements()); - - // First we need to check that the instructions are correct, that is: - // 0. call $a - // 1. call $b - // 2. get_local 0 - // 3. get_local 1 - // 4. get_local 2 - // 5. get_local 3 - // 6. call $c - // $a, $b, and $c will be used later. - // First we simply check the length - if instructions.len() != 8 { - return false; - } - // 0. call gasleft - if let Instruction::Call(f_ind) = instructions[0] { - // Check that f_ind is the function index of "gasleft" - let gasleft_index = find_import(module, "env", "gasleft"); - if Some(f_ind) != gasleft_index { - return false; - } - } else { - return false; - } - // 1. call sender - if let Instruction::Call(f_ind) = instructions[1] { - // Check that f_ind is the function index of "sender" - let sender_index = find_import(module, "env", "sender"); - if Some(f_ind) != sender_index { - return false; - } - } else { - return false; - } - // 2. get_local 0 - if let Instruction::GetLocal(0) = instructions[2] { - } else { - return false; - } - // 3. get_local 1 - if let Instruction::GetLocal(1) = instructions[3] { - } else { - return false; - } - // 4. get_local 2 - if let Instruction::GetLocal(2) = instructions[4] { - } else { - return false; - } - // 5. get_local 3 - if let Instruction::GetLocal(3) = instructions[5] { - } else { - return false; +fn n_to_section(byte: &u8) -> SectionType { + match byte { + 0 => SectionType::Custom, + 1 => SectionType::Type, + 2 => SectionType::Import, + 3 => SectionType::Function, + 4 => SectionType::Table, + 5 => SectionType::Memory, + 6 => SectionType::Global, + 7 => SectionType::Export, + 8 => SectionType::Start, + 9 => SectionType::Element, + 10 => SectionType::Code, + 11 => SectionType::Data, + _ => panic!("invalid section type"), } +} + +fn parse_varuint_32(cursor: &mut Cursor, data: &[u8]) -> u32 { + let mut res = 0; + let mut shift = 0; + loop { + if shift > 31 { panic!("invalid varuint32"); } - // 6. call dcall - if let Instruction::Call(f_ind) = instructions[6] { - // Check that f_ind is the function index of "dcall" - let dcall_index = find_import(module, "env", "dcall"); - if Some(f_ind) != dcall_index { - return false; + let b = cursor.read(data).clone() as u32; + res |= (b & 0x7f).checked_shl(shift).expect("invalid varuint32"); + shift += 7; + if (b >> 7) == 0 { + if shift >= 32 && (b as u8).leading_zeros() < 4 { + panic!("invalid varuint32"); + } + break; } - } else { - return false; - } - // 7. END - if let Instruction::End = instructions[7] { - } else { - return false; } + res +} - // Check that no locals are used - if code.locals().len() > 0 { - return false; - } - // Check that the type signature is correct - let parity_wasm::elements::Type::Function(f_type) = this_type; - if f_type.return_type() != Some(ValueType::I32) { - return false; - } - if f_type.params() != [ ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32] { - return false; - } - if f_type.form() != 0x60 { - return false; - } - true -} +// fn get_imports(module: &Module) -> Vec { +// if let Some(import_section) = module.import_section() { +// import_section.entries().to_vec() +// } else { +// Vec::new() +// } +// } + +// fn check_grey(module: &Module, grey_index: usize) -> Vec<(u32, u32)> { +// let mut uses = Vec::new(); +// let code_section = module.code_section().unwrap(); +// let codes = Vec::from(code_section.bodies()); +// // If the instruction Call(grey_index) exists in the body of the function, that is a dangerous function. +// let this_call = parity_wasm::elements::Instruction::Call(grey_index as u32); +// for (func_index, func_body) in codes.iter().enumerate() { +// for (instruction_index, instruction) in func_body.code().elements().iter().enumerate() { +// if instruction == &this_call && !is_syscall(module, func_index as u32) { +// uses.push((func_index as u32, instruction_index as u32)); +// } +// } +// } +// uses +// } + +// // Find the function index of an import +// pub fn find_import(module: &Module, mod_name: &str, field_name: &str) -> Option { +// let imports = module.import_section().unwrap().entries(); +// for (i,import) in imports.iter().enumerate() { +// if import.module() == mod_name && import.field() == field_name { +// return Some(i as u32); +// } +// } +// return None; +// } + +// pub fn is_syscall(module: &Module, function_index: u32) -> bool { + +// let function_section = module.function_section().unwrap(); +// let functions = Vec::from(function_section.entries()); +// let function = functions.get(function_index as usize).unwrap(); +// let type_index = function.type_ref(); + +// let type_section = module.type_section().unwrap(); +// let types = Vec::from(type_section.types()); +// let this_type = types.get(type_index as usize).unwrap(); + +// let code_section = module.code_section().unwrap(); +// let codes = Vec::from(code_section.bodies()); +// let code = codes.get(function_index as usize).unwrap(); +// let instructions = Vec::from(code.code().elements()); + +// // First we need to check that the instructions are correct, that is: +// // 0. call $a +// // 1. call $b +// // 2. get_local 0 +// // 3. get_local 1 +// // 4. get_local 2 +// // 5. get_local 3 +// // 6. call $c +// // $a, $b, and $c will be used later. +// // First we simply check the length +// if instructions.len() != 8 { +// return false; +// } +// // 0. call gasleft +// if let Instruction::Call(f_ind) = instructions[0] { +// // Check that f_ind is the function index of "gasleft" +// let gasleft_index = find_import(module, "env", "gasleft"); +// if Some(f_ind) != gasleft_index { +// return false; +// } +// } else { +// return false; +// } +// // 1. call sender +// if let Instruction::Call(f_ind) = instructions[1] { +// // Check that f_ind is the function index of "sender" +// let sender_index = find_import(module, "env", "sender"); +// if Some(f_ind) != sender_index { +// return false; +// } +// } else { +// return false; +// } +// // 2. get_local 0 +// if let Instruction::GetLocal(0) = instructions[2] { +// } else { +// return false; +// } +// // 3. get_local 1 +// if let Instruction::GetLocal(1) = instructions[3] { +// } else { +// return false; +// } +// // 4. get_local 2 +// if let Instruction::GetLocal(2) = instructions[4] { +// } else { +// return false; +// } +// // 5. get_local 3 +// if let Instruction::GetLocal(3) = instructions[5] { +// } else { +// return false; +// } + +// // 6. call dcall +// if let Instruction::Call(f_ind) = instructions[6] { +// // Check that f_ind is the function index of "dcall" +// let dcall_index = find_import(module, "env", "dcall"); +// if Some(f_ind) != dcall_index { +// return false; +// } +// } else { +// return false; +// } +// // 7. END +// if let Instruction::End = instructions[7] { +// } else { +// return false; +// } + +// // Check that no locals are used +// if code.locals().len() > 0 { +// return false; +// } +// // Check that the type signature is correct +// let parity_wasm::elements::Type::Function(f_type) = this_type; +// if f_type.return_type() != Some(ValueType::I32) { +// return false; +// } +// if f_type.params() != [ ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32] { +// return false; +// } +// if f_type.form() != 0x60 { +// return false; +// } + +// true +// } #[cfg(test)] mod tests { @@ -306,8 +435,8 @@ mod tests { fn module_only_pass() { let wat = "(module)"; let wasm = wat2wasm(wat).unwrap(); - let module: Module = parity_wasm::deserialize_buffer(wasm.as_slice()).expect("deserialise wasm"); - assert!(module.is_valid()); + // let module: Module = parity_wasm::deserialize_buffer(wasm.as_slice()).expect("deserialise wasm"); + assert!(wasm.as_slice().is_valid()); } #[test] @@ -321,29 +450,28 @@ mod tests { (export "call" (func $call))) "#; let wasm = wat2wasm(wat).unwrap(); - let module: Module = parity_wasm::deserialize_buffer(wasm.as_slice()).expect("deserialise wasm"); - assert!(module.is_valid()); + assert!(wasm.as_slice().is_valid()); } - #[test] - fn minimal_contract_with_write_fail() { - let wat = r#" -;; Minimal contract with a single storage write call -(module - (type $t0 (func)) - (type $t1 (func (param i32 i32))) - (import "env" "storage_write" (func $env.storage_write (type $t1))) - (func $call (type $t0) - i32.const 5 - i32.const 15 - call $env.storage_write - unreachable) - (export "call" (func $call))) -"#; - let wasm: pwasm_std::Vec = wat2wasm(wat).unwrap(); - let module: Module = parity_wasm::deserialize_buffer(wasm.as_slice()).expect("deserialise wasm"); - assert!(!module.is_valid()); - } +// #[test] +// fn minimal_contract_with_write_fail() { +// let wat = r#" +// ;; Minimal contract with a single storage write call +// (module +// (type $t0 (func)) +// (type $t1 (func (param i32 i32))) +// (import "env" "storage_write" (func $env.storage_write (type $t1))) +// (func $call (type $t0) +// i32.const 5 +// i32.const 15 +// call $env.storage_write +// unreachable) +// (export "call" (func $call))) +// "#; +// let wasm: pwasm_std::Vec = wat2wasm(wat).unwrap(); +// let module: Module = parity_wasm::deserialize_buffer(wasm.as_slice()).expect("deserialise wasm"); +// assert!(!module.is_valid()); +// } // #[test] // fn should_reject_invalid_address() { From 607af05314c6f5cbeba6e8c9e936bb293383f519 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 14:22:13 +1000 Subject: [PATCH 03/22] wasm-parser: import instruction mappings from parity-wasm --- kernel-ewasm/validator/src/instructions.rs | 2805 +++++++++++++++++++ kernel-ewasm/validator/src/io.rs | 127 + kernel-ewasm/validator/src/lib.rs | 559 +++- kernel-ewasm/validator/src/primitives.rs | 926 ++++++ kernel-ewasm/validator/src/serialization.rs | 220 ++ kernel-ewasm/validator/src/types.rs | 263 ++ 6 files changed, 4815 insertions(+), 85 deletions(-) create mode 100644 kernel-ewasm/validator/src/instructions.rs create mode 100644 kernel-ewasm/validator/src/io.rs create mode 100644 kernel-ewasm/validator/src/primitives.rs create mode 100644 kernel-ewasm/validator/src/serialization.rs create mode 100644 kernel-ewasm/validator/src/types.rs diff --git a/kernel-ewasm/validator/src/instructions.rs b/kernel-ewasm/validator/src/instructions.rs new file mode 100644 index 0000000..9efeac9 --- /dev/null +++ b/kernel-ewasm/validator/src/instructions.rs @@ -0,0 +1,2805 @@ +// This file is based on parity-wasm from parity, MIT & Apache Licensed + + +use pwasm_std; +// use parity_wasm; + +// pub use parity_wasm::elements::{ImportEntry, Module}; +// use parity_wasm::elements::Instruction; +// use parity_wasm::elements::{ValueType}; + +use pwasm_std::vec::Vec; + +// use crate::rust::{fmt, vec::Vec, boxed::Box}; +use crate::io; +// mod primitives; +use crate::{ + Serialize, Deserialize, + Uint8, VarUint32, CountedList, + Uint32, Uint64, CountedListWriter, + VarInt32, VarInt64, +}; +use crate::types::{BlockType}; +use crate::serialization::{Error}; + +// /// List of instructions (usually inside a block section). +// #[derive(Debug, Clone, PartialEq)] +// pub struct Instructions(Vec); + +// impl Instructions { +// /// New list of instructions from vector of instructions. +// pub fn new(elements: Vec) -> Self { +// Instructions(elements) +// } + +// /// Empty expression with only `Instruction::End` instruction. +// pub fn empty() -> Self { +// Instructions(vec![Instruction::End]) +// } + +// /// List of individual instructions. +// pub fn elements(&self) -> &[Instruction] { &self.0 } + +// /// Individual instructions, mutable. +// pub fn elements_mut(&mut self) -> &mut Vec { &mut self.0 } +// } + +// impl Deserialize for Instructions { +// type Error = Error; + +// fn deserialize(reader: &mut R) -> Result { +// let mut instructions = Vec::new(); +// let mut block_count = 1usize; + +// loop { +// let instruction = Instruction::deserialize(reader)?; +// if instruction.is_terminal() { +// block_count -= 1; +// } else if instruction.is_block() { +// block_count = block_count.checked_add(1).ok_or(Error::Other("too many instructions"))?; +// } + +// instructions.push(instruction); +// if block_count == 0 { +// break; +// } +// } + +// Ok(Instructions(instructions)) +// } +// } + +// /// Initialization expression. +// #[derive(Debug, Clone, PartialEq)] +// pub struct InitExpr(Vec); + +// impl InitExpr { +// /// New initialization expression from instruction list. +// /// +// /// `code` must end with the `Instruction::End` instruction! +// pub fn new(code: Vec) -> Self { +// InitExpr(code) +// } + +// /// Empty expression with only `Instruction::End` instruction. +// pub fn empty() -> Self { +// InitExpr(vec![Instruction::End]) +// } + +// /// List of instructions used in the expression. +// pub fn code(&self) -> &[Instruction] { +// &self.0 +// } + +// /// List of instructions used in the expression. +// pub fn code_mut(&mut self) -> &mut Vec { +// &mut self.0 +// } +// } + +// impl Deserialize for InitExpr { +// type Error = Error; + +// fn deserialize(reader: &mut R) -> Result { +// let mut instructions = Vec::new(); + +// loop { +// let instruction = Instruction::deserialize(reader)?; +// let is_terminal = instruction.is_terminal(); +// instructions.push(instruction); +// if is_terminal { +// break; +// } +// } + +// Ok(InitExpr(instructions)) +// } +// } + +/// Instruction. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Instruction { + Unreachable, + Nop, + Block(BlockType), + Loop(BlockType), + If(BlockType), + Else, + End, + Br(u32), + BrIf(u32), + BrTable(Box), + Return, + + Call(u32), + CallIndirect(u32, u8), + + Drop, + Select, + + GetLocal(u32), + SetLocal(u32), + TeeLocal(u32), + GetGlobal(u32), + SetGlobal(u32), + + // All store/load instructions operate with 'memory immediates' + // which represented here as (flag, offset) tuple + I32Load(u32, u32), + I64Load(u32, u32), + F32Load(u32, u32), + F64Load(u32, u32), + I32Load8S(u32, u32), + I32Load8U(u32, u32), + I32Load16S(u32, u32), + I32Load16U(u32, u32), + I64Load8S(u32, u32), + I64Load8U(u32, u32), + I64Load16S(u32, u32), + I64Load16U(u32, u32), + I64Load32S(u32, u32), + I64Load32U(u32, u32), + I32Store(u32, u32), + I64Store(u32, u32), + F32Store(u32, u32), + F64Store(u32, u32), + I32Store8(u32, u32), + I32Store16(u32, u32), + I64Store8(u32, u32), + I64Store16(u32, u32), + I64Store32(u32, u32), + + CurrentMemory(u8), + GrowMemory(u8), + + I32Const(i32), + I64Const(i64), + F32Const(u32), + F64Const(u64), + + I32Eqz, + I32Eq, + I32Ne, + I32LtS, + I32LtU, + I32GtS, + I32GtU, + I32LeS, + I32LeU, + I32GeS, + I32GeU, + + I64Eqz, + I64Eq, + I64Ne, + I64LtS, + I64LtU, + I64GtS, + I64GtU, + I64LeS, + I64LeU, + I64GeS, + I64GeU, + + F32Eq, + F32Ne, + F32Lt, + F32Gt, + F32Le, + F32Ge, + + F64Eq, + F64Ne, + F64Lt, + F64Gt, + F64Le, + F64Ge, + + I32Clz, + I32Ctz, + I32Popcnt, + I32Add, + I32Sub, + I32Mul, + I32DivS, + I32DivU, + I32RemS, + I32RemU, + I32And, + I32Or, + I32Xor, + I32Shl, + I32ShrS, + I32ShrU, + I32Rotl, + I32Rotr, + + I64Clz, + I64Ctz, + I64Popcnt, + I64Add, + I64Sub, + I64Mul, + I64DivS, + I64DivU, + I64RemS, + I64RemU, + I64And, + I64Or, + I64Xor, + I64Shl, + I64ShrS, + I64ShrU, + I64Rotl, + I64Rotr, + F32Abs, + F32Neg, + F32Ceil, + F32Floor, + F32Trunc, + F32Nearest, + F32Sqrt, + F32Add, + F32Sub, + F32Mul, + F32Div, + F32Min, + F32Max, + F32Copysign, + F64Abs, + F64Neg, + F64Ceil, + F64Floor, + F64Trunc, + F64Nearest, + F64Sqrt, + F64Add, + F64Sub, + F64Mul, + F64Div, + F64Min, + F64Max, + F64Copysign, + + I32WrapI64, + I32TruncSF32, + I32TruncUF32, + I32TruncSF64, + I32TruncUF64, + I64ExtendSI32, + I64ExtendUI32, + I64TruncSF32, + I64TruncUF32, + I64TruncSF64, + I64TruncUF64, + F32ConvertSI32, + F32ConvertUI32, + F32ConvertSI64, + F32ConvertUI64, + F32DemoteF64, + F64ConvertSI32, + F64ConvertUI32, + F64ConvertSI64, + F64ConvertUI64, + F64PromoteF32, + + I32ReinterpretF32, + I64ReinterpretF64, + F32ReinterpretI32, + F64ReinterpretI64, + + I32Extend8S, + I32Extend16S, + I64Extend8S, + I64Extend16S, + I64Extend32S, + + AtomicWake(MemArg), + I32AtomicWait(MemArg), + I64AtomicWait(MemArg), + + I32AtomicLoad(MemArg), + I64AtomicLoad(MemArg), + I32AtomicLoad8u(MemArg), + I32AtomicLoad16u(MemArg), + I64AtomicLoad8u(MemArg), + I64AtomicLoad16u(MemArg), + I64AtomicLoad32u(MemArg), + I32AtomicStore(MemArg), + I64AtomicStore(MemArg), + I32AtomicStore8u(MemArg), + I32AtomicStore16u(MemArg), + I64AtomicStore8u(MemArg), + I64AtomicStore16u(MemArg), + I64AtomicStore32u(MemArg), + + I32AtomicRmwAdd(MemArg), + I64AtomicRmwAdd(MemArg), + I32AtomicRmwAdd8u(MemArg), + I32AtomicRmwAdd16u(MemArg), + I64AtomicRmwAdd8u(MemArg), + I64AtomicRmwAdd16u(MemArg), + I64AtomicRmwAdd32u(MemArg), + + I32AtomicRmwSub(MemArg), + I64AtomicRmwSub(MemArg), + I32AtomicRmwSub8u(MemArg), + I32AtomicRmwSub16u(MemArg), + I64AtomicRmwSub8u(MemArg), + I64AtomicRmwSub16u(MemArg), + I64AtomicRmwSub32u(MemArg), + + I32AtomicRmwAnd(MemArg), + I64AtomicRmwAnd(MemArg), + I32AtomicRmwAnd8u(MemArg), + I32AtomicRmwAnd16u(MemArg), + I64AtomicRmwAnd8u(MemArg), + I64AtomicRmwAnd16u(MemArg), + I64AtomicRmwAnd32u(MemArg), + + I32AtomicRmwOr(MemArg), + I64AtomicRmwOr(MemArg), + I32AtomicRmwOr8u(MemArg), + I32AtomicRmwOr16u(MemArg), + I64AtomicRmwOr8u(MemArg), + I64AtomicRmwOr16u(MemArg), + I64AtomicRmwOr32u(MemArg), + + I32AtomicRmwXor(MemArg), + I64AtomicRmwXor(MemArg), + I32AtomicRmwXor8u(MemArg), + I32AtomicRmwXor16u(MemArg), + I64AtomicRmwXor8u(MemArg), + I64AtomicRmwXor16u(MemArg), + I64AtomicRmwXor32u(MemArg), + + I32AtomicRmwXchg(MemArg), + I64AtomicRmwXchg(MemArg), + I32AtomicRmwXchg8u(MemArg), + I32AtomicRmwXchg16u(MemArg), + I64AtomicRmwXchg8u(MemArg), + I64AtomicRmwXchg16u(MemArg), + I64AtomicRmwXchg32u(MemArg), + + I32AtomicRmwCmpxchg(MemArg), + I64AtomicRmwCmpxchg(MemArg), + I32AtomicRmwCmpxchg8u(MemArg), + I32AtomicRmwCmpxchg16u(MemArg), + I64AtomicRmwCmpxchg8u(MemArg), + I64AtomicRmwCmpxchg16u(MemArg), + I64AtomicRmwCmpxchg32u(MemArg), + + V128Const(Box<[u8; 16]>), + V128Load(MemArg), + V128Store(MemArg), + I8x16Splat, + I16x8Splat, + I32x4Splat, + I64x2Splat, + F32x4Splat, + F64x2Splat, + I8x16ExtractLaneS(u8), + I8x16ExtractLaneU(u8), + I16x8ExtractLaneS(u8), + I16x8ExtractLaneU(u8), + I32x4ExtractLane(u8), + I64x2ExtractLane(u8), + F32x4ExtractLane(u8), + F64x2ExtractLane(u8), + I8x16ReplaceLane(u8), + I16x8ReplaceLane(u8), + I32x4ReplaceLane(u8), + I64x2ReplaceLane(u8), + F32x4ReplaceLane(u8), + F64x2ReplaceLane(u8), + V8x16Shuffle(Box<[u8; 16]>), + I8x16Add, + I16x8Add, + I32x4Add, + I64x2Add, + I8x16Sub, + I16x8Sub, + I32x4Sub, + I64x2Sub, + I8x16Mul, + I16x8Mul, + I32x4Mul, + // I64x2Mul, + I8x16Neg, + I16x8Neg, + I32x4Neg, + I64x2Neg, + I8x16AddSaturateS, + I8x16AddSaturateU, + I16x8AddSaturateS, + I16x8AddSaturateU, + I8x16SubSaturateS, + I8x16SubSaturateU, + I16x8SubSaturateS, + I16x8SubSaturateU, + I8x16Shl, + I16x8Shl, + I32x4Shl, + I64x2Shl, + I8x16ShrS, + I8x16ShrU, + I16x8ShrS, + I16x8ShrU, + I32x4ShrS, + I32x4ShrU, + I64x2ShrS, + I64x2ShrU, + V128And, + V128Or, + V128Xor, + V128Not, + V128Bitselect, + I8x16AnyTrue, + I16x8AnyTrue, + I32x4AnyTrue, + I64x2AnyTrue, + I8x16AllTrue, + I16x8AllTrue, + I32x4AllTrue, + I64x2AllTrue, + I8x16Eq, + I16x8Eq, + I32x4Eq, + // I64x2Eq, + F32x4Eq, + F64x2Eq, + I8x16Ne, + I16x8Ne, + I32x4Ne, + // I64x2Ne, + F32x4Ne, + F64x2Ne, + I8x16LtS, + I8x16LtU, + I16x8LtS, + I16x8LtU, + I32x4LtS, + I32x4LtU, + // I64x2LtS, + // I64x2LtU, + F32x4Lt, + F64x2Lt, + I8x16LeS, + I8x16LeU, + I16x8LeS, + I16x8LeU, + I32x4LeS, + I32x4LeU, + // I64x2LeS, + // I64x2LeU, + F32x4Le, + F64x2Le, + I8x16GtS, + I8x16GtU, + I16x8GtS, + I16x8GtU, + I32x4GtS, + I32x4GtU, + // I64x2GtS, + // I64x2GtU, + F32x4Gt, + F64x2Gt, + I8x16GeS, + I8x16GeU, + I16x8GeS, + I16x8GeU, + I32x4GeS, + I32x4GeU, + // I64x2GeS, + // I64x2GeU, + F32x4Ge, + F64x2Ge, + F32x4Neg, + F64x2Neg, + F32x4Abs, + F64x2Abs, + F32x4Min, + F64x2Min, + F32x4Max, + F64x2Max, + F32x4Add, + F64x2Add, + F32x4Sub, + F64x2Sub, + F32x4Div, + F64x2Div, + F32x4Mul, + F64x2Mul, + F32x4Sqrt, + F64x2Sqrt, + F32x4ConvertSI32x4, + F32x4ConvertUI32x4, + F64x2ConvertSI64x2, + F64x2ConvertUI64x2, + I32x4TruncSF32x4Sat, + I32x4TruncUF32x4Sat, + I64x2TruncSF64x2Sat, + I64x2TruncUF64x2Sat, + + // https://github.com/WebAssembly/bulk-memory-operations + MemoryInit(u32), + MemoryDrop(u32), + MemoryCopy, + MemoryFill, + TableInit(u32), + TableDrop(u32), + TableCopy, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub struct MemArg { + pub align: u8, + pub offset: u32, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub struct BrTableData { + pub table: Box<[u32]>, + pub default: u32, +} + +impl Instruction { + /// Is this instruction starts the new block (which should end with terminal instruction). + pub fn is_block(&self) -> bool { + match self { + &Instruction::Block(_) | &Instruction::Loop(_) | &Instruction::If(_) => true, + _ => false, + } + } + + /// Is this instruction determines the termination of instruction sequence? + /// + /// `true` for `Instruction::End` + pub fn is_terminal(&self) -> bool { + match self { + &Instruction::End => true, + _ => false, + } + } +} + +#[allow(missing_docs)] +pub mod opcodes { + pub const UNREACHABLE: u8 = 0x00; + pub const NOP: u8 = 0x01; + pub const BLOCK: u8 = 0x02; + pub const LOOP: u8 = 0x03; + pub const IF: u8 = 0x04; + pub const ELSE: u8 = 0x05; + pub const END: u8 = 0x0b; + pub const BR: u8 = 0x0c; + pub const BRIF: u8 = 0x0d; + pub const BRTABLE: u8 = 0x0e; + pub const RETURN: u8 = 0x0f; + pub const CALL: u8 = 0x10; + pub const CALLINDIRECT: u8 = 0x11; + pub const DROP: u8 = 0x1a; + pub const SELECT: u8 = 0x1b; + pub const GETLOCAL: u8 = 0x20; + pub const SETLOCAL: u8 = 0x21; + pub const TEELOCAL: u8 = 0x22; + pub const GETGLOBAL: u8 = 0x23; + pub const SETGLOBAL: u8 = 0x24; + pub const I32LOAD: u8 = 0x28; + pub const I64LOAD: u8 = 0x29; + pub const F32LOAD: u8 = 0x2a; + pub const F64LOAD: u8 = 0x2b; + pub const I32LOAD8S: u8 = 0x2c; + pub const I32LOAD8U: u8 = 0x2d; + pub const I32LOAD16S: u8 = 0x2e; + pub const I32LOAD16U: u8 = 0x2f; + pub const I64LOAD8S: u8 = 0x30; + pub const I64LOAD8U: u8 = 0x31; + pub const I64LOAD16S: u8 = 0x32; + pub const I64LOAD16U: u8 = 0x33; + pub const I64LOAD32S: u8 = 0x34; + pub const I64LOAD32U: u8 = 0x35; + pub const I32STORE: u8 = 0x36; + pub const I64STORE: u8 = 0x37; + pub const F32STORE: u8 = 0x38; + pub const F64STORE: u8 = 0x39; + pub const I32STORE8: u8 = 0x3a; + pub const I32STORE16: u8 = 0x3b; + pub const I64STORE8: u8 = 0x3c; + pub const I64STORE16: u8 = 0x3d; + pub const I64STORE32: u8 = 0x3e; + pub const CURRENTMEMORY: u8 = 0x3f; + pub const GROWMEMORY: u8 = 0x40; + pub const I32CONST: u8 = 0x41; + pub const I64CONST: u8 = 0x42; + pub const F32CONST: u8 = 0x43; + pub const F64CONST: u8 = 0x44; + pub const I32EQZ: u8 = 0x45; + pub const I32EQ: u8 = 0x46; + pub const I32NE: u8 = 0x47; + pub const I32LTS: u8 = 0x48; + pub const I32LTU: u8 = 0x49; + pub const I32GTS: u8 = 0x4a; + pub const I32GTU: u8 = 0x4b; + pub const I32LES: u8 = 0x4c; + pub const I32LEU: u8 = 0x4d; + pub const I32GES: u8 = 0x4e; + pub const I32GEU: u8 = 0x4f; + pub const I64EQZ: u8 = 0x50; + pub const I64EQ: u8 = 0x51; + pub const I64NE: u8 = 0x52; + pub const I64LTS: u8 = 0x53; + pub const I64LTU: u8 = 0x54; + pub const I64GTS: u8 = 0x55; + pub const I64GTU: u8 = 0x56; + pub const I64LES: u8 = 0x57; + pub const I64LEU: u8 = 0x58; + pub const I64GES: u8 = 0x59; + pub const I64GEU: u8 = 0x5a; + + pub const F32EQ: u8 = 0x5b; + pub const F32NE: u8 = 0x5c; + pub const F32LT: u8 = 0x5d; + pub const F32GT: u8 = 0x5e; + pub const F32LE: u8 = 0x5f; + pub const F32GE: u8 = 0x60; + + pub const F64EQ: u8 = 0x61; + pub const F64NE: u8 = 0x62; + pub const F64LT: u8 = 0x63; + pub const F64GT: u8 = 0x64; + pub const F64LE: u8 = 0x65; + pub const F64GE: u8 = 0x66; + + pub const I32CLZ: u8 = 0x67; + pub const I32CTZ: u8 = 0x68; + pub const I32POPCNT: u8 = 0x69; + pub const I32ADD: u8 = 0x6a; + pub const I32SUB: u8 = 0x6b; + pub const I32MUL: u8 = 0x6c; + pub const I32DIVS: u8 = 0x6d; + pub const I32DIVU: u8 = 0x6e; + pub const I32REMS: u8 = 0x6f; + pub const I32REMU: u8 = 0x70; + pub const I32AND: u8 = 0x71; + pub const I32OR: u8 = 0x72; + pub const I32XOR: u8 = 0x73; + pub const I32SHL: u8 = 0x74; + pub const I32SHRS: u8 = 0x75; + pub const I32SHRU: u8 = 0x76; + pub const I32ROTL: u8 = 0x77; + pub const I32ROTR: u8 = 0x78; + + pub const I64CLZ: u8 = 0x79; + pub const I64CTZ: u8 = 0x7a; + pub const I64POPCNT: u8 = 0x7b; + pub const I64ADD: u8 = 0x7c; + pub const I64SUB: u8 = 0x7d; + pub const I64MUL: u8 = 0x7e; + pub const I64DIVS: u8 = 0x7f; + pub const I64DIVU: u8 = 0x80; + pub const I64REMS: u8 = 0x81; + pub const I64REMU: u8 = 0x82; + pub const I64AND: u8 = 0x83; + pub const I64OR: u8 = 0x84; + pub const I64XOR: u8 = 0x85; + pub const I64SHL: u8 = 0x86; + pub const I64SHRS: u8 = 0x87; + pub const I64SHRU: u8 = 0x88; + pub const I64ROTL: u8 = 0x89; + pub const I64ROTR: u8 = 0x8a; + pub const F32ABS: u8 = 0x8b; + pub const F32NEG: u8 = 0x8c; + pub const F32CEIL: u8 = 0x8d; + pub const F32FLOOR: u8 = 0x8e; + pub const F32TRUNC: u8 = 0x8f; + pub const F32NEAREST: u8 = 0x90; + pub const F32SQRT: u8 = 0x91; + pub const F32ADD: u8 = 0x92; + pub const F32SUB: u8 = 0x93; + pub const F32MUL: u8 = 0x94; + pub const F32DIV: u8 = 0x95; + pub const F32MIN: u8 = 0x96; + pub const F32MAX: u8 = 0x97; + pub const F32COPYSIGN: u8 = 0x98; + pub const F64ABS: u8 = 0x99; + pub const F64NEG: u8 = 0x9a; + pub const F64CEIL: u8 = 0x9b; + pub const F64FLOOR: u8 = 0x9c; + pub const F64TRUNC: u8 = 0x9d; + pub const F64NEAREST: u8 = 0x9e; + pub const F64SQRT: u8 = 0x9f; + pub const F64ADD: u8 = 0xa0; + pub const F64SUB: u8 = 0xa1; + pub const F64MUL: u8 = 0xa2; + pub const F64DIV: u8 = 0xa3; + pub const F64MIN: u8 = 0xa4; + pub const F64MAX: u8 = 0xa5; + pub const F64COPYSIGN: u8 = 0xa6; + + pub const I32WRAPI64: u8 = 0xa7; + pub const I32TRUNCSF32: u8 = 0xa8; + pub const I32TRUNCUF32: u8 = 0xa9; + pub const I32TRUNCSF64: u8 = 0xaa; + pub const I32TRUNCUF64: u8 = 0xab; + pub const I64EXTENDSI32: u8 = 0xac; + pub const I64EXTENDUI32: u8 = 0xad; + pub const I64TRUNCSF32: u8 = 0xae; + pub const I64TRUNCUF32: u8 = 0xaf; + pub const I64TRUNCSF64: u8 = 0xb0; + pub const I64TRUNCUF64: u8 = 0xb1; + pub const F32CONVERTSI32: u8 = 0xb2; + pub const F32CONVERTUI32: u8 = 0xb3; + pub const F32CONVERTSI64: u8 = 0xb4; + pub const F32CONVERTUI64: u8 = 0xb5; + pub const F32DEMOTEF64: u8 = 0xb6; + pub const F64CONVERTSI32: u8 = 0xb7; + pub const F64CONVERTUI32: u8 = 0xb8; + pub const F64CONVERTSI64: u8 = 0xb9; + pub const F64CONVERTUI64: u8 = 0xba; + pub const F64PROMOTEF32: u8 = 0xbb; + + pub const I32REINTERPRETF32: u8 = 0xbc; + pub const I64REINTERPRETF64: u8 = 0xbd; + pub const F32REINTERPRETI32: u8 = 0xbe; + pub const F64REINTERPRETI64: u8 = 0xbf; + + pub const I32_EXTEND8_S: u8 = 0xc0; + pub const I32_EXTEND16_S: u8 = 0xc1; + pub const I64_EXTEND8_S: u8 = 0xc2; + pub const I64_EXTEND16_S: u8 = 0xc3; + pub const I64_EXTEND32_S: u8 = 0xc4; + + pub const ATOMIC_PREFIX: u8 = 0xfe; + pub const ATOMIC_WAKE: u8 = 0x00; + pub const I32_ATOMIC_WAIT: u8 = 0x01; + pub const I64_ATOMIC_WAIT: u8 = 0x02; + + pub const I32_ATOMIC_LOAD: u8 = 0x10; + pub const I64_ATOMIC_LOAD: u8 = 0x11; + pub const I32_ATOMIC_LOAD8U: u8 = 0x12; + pub const I32_ATOMIC_LOAD16U: u8 = 0x13; + pub const I64_ATOMIC_LOAD8U: u8 = 0x14; + pub const I64_ATOMIC_LOAD16U: u8 = 0x15; + pub const I64_ATOMIC_LOAD32U: u8 = 0x16; + pub const I32_ATOMIC_STORE: u8 = 0x17; + pub const I64_ATOMIC_STORE: u8 = 0x18; + pub const I32_ATOMIC_STORE8U: u8 = 0x19; + pub const I32_ATOMIC_STORE16U: u8 = 0x1a; + pub const I64_ATOMIC_STORE8U: u8 = 0x1b; + pub const I64_ATOMIC_STORE16U: u8 = 0x1c; + pub const I64_ATOMIC_STORE32U: u8 = 0x1d; + + pub const I32_ATOMIC_RMW_ADD: u8 = 0x1e; + pub const I64_ATOMIC_RMW_ADD: u8 = 0x1f; + pub const I32_ATOMIC_RMW_ADD8U: u8 = 0x20; + pub const I32_ATOMIC_RMW_ADD16U: u8 = 0x21; + pub const I64_ATOMIC_RMW_ADD8U: u8 = 0x22; + pub const I64_ATOMIC_RMW_ADD16U: u8 = 0x23; + pub const I64_ATOMIC_RMW_ADD32U: u8 = 0x24; + + pub const I32_ATOMIC_RMW_SUB: u8 = 0x25; + pub const I64_ATOMIC_RMW_SUB: u8 = 0x26; + pub const I32_ATOMIC_RMW_SUB8U: u8 = 0x27; + pub const I32_ATOMIC_RMW_SUB16U: u8 = 0x28; + pub const I64_ATOMIC_RMW_SUB8U: u8 = 0x29; + pub const I64_ATOMIC_RMW_SUB16U: u8 = 0x2a; + pub const I64_ATOMIC_RMW_SUB32U: u8 = 0x2b; + + pub const I32_ATOMIC_RMW_AND: u8 = 0x2c; + pub const I64_ATOMIC_RMW_AND: u8 = 0x2d; + pub const I32_ATOMIC_RMW_AND8U: u8 = 0x2e; + pub const I32_ATOMIC_RMW_AND16U: u8 = 0x2f; + pub const I64_ATOMIC_RMW_AND8U: u8 = 0x30; + pub const I64_ATOMIC_RMW_AND16U: u8 = 0x31; + pub const I64_ATOMIC_RMW_AND32U: u8 = 0x32; + + pub const I32_ATOMIC_RMW_OR: u8 = 0x33; + pub const I64_ATOMIC_RMW_OR: u8 = 0x34; + pub const I32_ATOMIC_RMW_OR8U: u8 = 0x35; + pub const I32_ATOMIC_RMW_OR16U: u8 = 0x36; + pub const I64_ATOMIC_RMW_OR8U: u8 = 0x37; + pub const I64_ATOMIC_RMW_OR16U: u8 = 0x38; + pub const I64_ATOMIC_RMW_OR32U: u8 = 0x39; + + pub const I32_ATOMIC_RMW_XOR: u8 = 0x3a; + pub const I64_ATOMIC_RMW_XOR: u8 = 0x3b; + pub const I32_ATOMIC_RMW_XOR8U: u8 = 0x3c; + pub const I32_ATOMIC_RMW_XOR16U: u8 = 0x3d; + pub const I64_ATOMIC_RMW_XOR8U: u8 = 0x3e; + pub const I64_ATOMIC_RMW_XOR16U: u8 = 0x3f; + pub const I64_ATOMIC_RMW_XOR32U: u8 = 0x40; + + pub const I32_ATOMIC_RMW_XCHG: u8 = 0x41; + pub const I64_ATOMIC_RMW_XCHG: u8 = 0x42; + pub const I32_ATOMIC_RMW_XCHG8U: u8 = 0x43; + pub const I32_ATOMIC_RMW_XCHG16U: u8 = 0x44; + pub const I64_ATOMIC_RMW_XCHG8U: u8 = 0x45; + pub const I64_ATOMIC_RMW_XCHG16U: u8 = 0x46; + pub const I64_ATOMIC_RMW_XCHG32U: u8 = 0x47; + + pub const I32_ATOMIC_RMW_CMPXCHG: u8 = 0x48; + pub const I64_ATOMIC_RMW_CMPXCHG: u8 = 0x49; + pub const I32_ATOMIC_RMW_CMPXCHG8U: u8 = 0x4a; + pub const I32_ATOMIC_RMW_CMPXCHG16U: u8 = 0x4b; + pub const I64_ATOMIC_RMW_CMPXCHG8U: u8 = 0x4c; + pub const I64_ATOMIC_RMW_CMPXCHG16U: u8 = 0x4d; + pub const I64_ATOMIC_RMW_CMPXCHG32U: u8 = 0x4e; + + // https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md + pub const SIMD_PREFIX: u8 = 0xfd; + + pub const V128_LOAD: u32 = 0x00; + pub const V128_STORE: u32 = 0x01; + pub const V128_CONST: u32 = 0x02; + pub const V8X16_SHUFFLE: u32 = 0x03; + + pub const I8X16_SPLAT: u32 = 0x04; + pub const I8X16_EXTRACT_LANE_S: u32 = 0x05; + pub const I8X16_EXTRACT_LANE_U: u32 = 0x06; + pub const I8X16_REPLACE_LANE: u32 = 0x07; + pub const I16X8_SPLAT: u32 = 0x08; + pub const I16X8_EXTRACT_LANE_S: u32 = 0x09; + pub const I16X8_EXTRACT_LANE_U: u32 = 0xa; + pub const I16X8_REPLACE_LANE: u32 = 0x0b; + pub const I32X4_SPLAT: u32 = 0x0c; + pub const I32X4_EXTRACT_LANE: u32 = 0x0d; + pub const I32X4_REPLACE_LANE: u32 = 0x0e; + pub const I64X2_SPLAT: u32 = 0x0f; + pub const I64X2_EXTRACT_LANE: u32 = 0x10; + pub const I64X2_REPLACE_LANE: u32 = 0x11; + pub const F32X4_SPLAT: u32 = 0x12; + pub const F32X4_EXTRACT_LANE: u32 = 0x13; + pub const F32X4_REPLACE_LANE: u32 = 0x14; + pub const F64X2_SPLAT: u32 = 0x15; + pub const F64X2_EXTRACT_LANE: u32 = 0x16; + pub const F64X2_REPLACE_LANE: u32 = 0x17; + + pub const I8X16_EQ: u32 = 0x18; + pub const I8X16_NE: u32 = 0x19; + pub const I8X16_LT_S: u32 = 0x1a; + pub const I8X16_LT_U: u32 = 0x1b; + pub const I8X16_GT_S: u32 = 0x1c; + pub const I8X16_GT_U: u32 = 0x1d; + pub const I8X16_LE_S: u32 = 0x1e; + pub const I8X16_LE_U: u32 = 0x1f; + pub const I8X16_GE_S: u32 = 0x20; + pub const I8X16_GE_U: u32 = 0x21; + + pub const I16X8_EQ: u32 = 0x22; + pub const I16X8_NE: u32 = 0x23; + pub const I16X8_LT_S: u32 = 0x24; + pub const I16X8_LT_U: u32 = 0x25; + pub const I16X8_GT_S: u32 = 0x26; + pub const I16X8_GT_U: u32 = 0x27; + pub const I16X8_LE_S: u32 = 0x28; + pub const I16X8_LE_U: u32 = 0x29; + pub const I16X8_GE_S: u32 = 0x2a; + pub const I16X8_GE_U: u32 = 0x2b; + + pub const I32X4_EQ: u32 = 0x2c; + pub const I32X4_NE: u32 = 0x2d; + pub const I32X4_LT_S: u32 = 0x2e; + pub const I32X4_LT_U: u32 = 0x2f; + pub const I32X4_GT_S: u32 = 0x30; + pub const I32X4_GT_U: u32 = 0x31; + pub const I32X4_LE_S: u32 = 0x32; + pub const I32X4_LE_U: u32 = 0x33; + pub const I32X4_GE_S: u32 = 0x34; + pub const I32X4_GE_U: u32 = 0x35; + + pub const F32X4_EQ: u32 = 0x40; + pub const F32X4_NE: u32 = 0x41; + pub const F32X4_LT: u32 = 0x42; + pub const F32X4_GT: u32 = 0x43; + pub const F32X4_LE: u32 = 0x44; + pub const F32X4_GE: u32 = 0x45; + + pub const F64X2_EQ: u32 = 0x46; + pub const F64X2_NE: u32 = 0x47; + pub const F64X2_LT: u32 = 0x48; + pub const F64X2_GT: u32 = 0x49; + pub const F64X2_LE: u32 = 0x4a; + pub const F64X2_GE: u32 = 0x4b; + + pub const V128_NOT: u32 = 0x4c; + pub const V128_AND: u32 = 0x4d; + pub const V128_OR: u32 = 0x4e; + pub const V128_XOR: u32 = 0x4f; + pub const V128_BITSELECT: u32 = 0x50; + + pub const I8X16_NEG: u32 = 0x51; + pub const I8X16_ANY_TRUE: u32 = 0x52; + pub const I8X16_ALL_TRUE: u32 = 0x53; + pub const I8X16_SHL: u32 = 0x54; + pub const I8X16_SHR_S: u32 = 0x55; + pub const I8X16_SHR_U: u32 = 0x56; + pub const I8X16_ADD: u32 = 0x57; + pub const I8X16_ADD_SATURATE_S: u32 = 0x58; + pub const I8X16_ADD_SATURATE_U: u32 = 0x59; + pub const I8X16_SUB: u32 = 0x5a; + pub const I8X16_SUB_SATURATE_S: u32 = 0x5b; + pub const I8X16_SUB_SATURATE_U: u32 = 0x5c; + pub const I8X16_MUL: u32 = 0x5d; + + pub const I16X8_NEG: u32 = 0x62; + pub const I16X8_ANY_TRUE: u32 = 0x63; + pub const I16X8_ALL_TRUE: u32 = 0x64; + pub const I16X8_SHL: u32 = 0x65; + pub const I16X8_SHR_S: u32 = 0x66; + pub const I16X8_SHR_U: u32 = 0x67; + pub const I16X8_ADD: u32 = 0x68; + pub const I16X8_ADD_SATURATE_S: u32 = 0x69; + pub const I16X8_ADD_SATURATE_U: u32 = 0x6a; + pub const I16X8_SUB: u32 = 0x6b; + pub const I16X8_SUB_SATURATE_S: u32 = 0x6c; + pub const I16X8_SUB_SATURATE_U: u32 = 0x6d; + pub const I16X8_MUL: u32 = 0x6e; + + pub const I32X4_NEG: u32 = 0x73; + pub const I32X4_ANY_TRUE: u32 = 0x74; + pub const I32X4_ALL_TRUE: u32 = 0x75; + pub const I32X4_SHL: u32 = 0x76; + pub const I32X4_SHR_S: u32 = 0x77; + pub const I32X4_SHR_U: u32 = 0x78; + pub const I32X4_ADD: u32 = 0x79; + pub const I32X4_ADD_SATURATE_S: u32 = 0x7a; + pub const I32X4_ADD_SATURATE_U: u32 = 0x7b; + pub const I32X4_SUB: u32 = 0x7c; + pub const I32X4_SUB_SATURATE_S: u32 = 0x7d; + pub const I32X4_SUB_SATURATE_U: u32 = 0x7e; + pub const I32X4_MUL: u32 = 0x7f; + + pub const I64X2_NEG: u32 = 0x84; + pub const I64X2_ANY_TRUE: u32 = 0x85; + pub const I64X2_ALL_TRUE: u32 = 0x86; + pub const I64X2_SHL: u32 = 0x87; + pub const I64X2_SHR_S: u32 = 0x88; + pub const I64X2_SHR_U: u32 = 0x89; + pub const I64X2_ADD: u32 = 0x8a; + pub const I64X2_SUB: u32 = 0x8d; + + pub const F32X4_ABS: u32 = 0x95; + pub const F32X4_NEG: u32 = 0x96; + pub const F32X4_SQRT: u32 = 0x97; + pub const F32X4_ADD: u32 = 0x9a; + pub const F32X4_SUB: u32 = 0x9b; + pub const F32X4_MUL: u32 = 0x9c; + pub const F32X4_DIV: u32 = 0x9d; + pub const F32X4_MIN: u32 = 0x9e; + pub const F32X4_MAX: u32 = 0x9f; + + pub const F64X2_ABS: u32 = 0xa0; + pub const F64X2_NEG: u32 = 0xa1; + pub const F64X2_SQRT: u32 = 0xa2; + pub const F64X2_ADD: u32 = 0xa5; + pub const F64X2_SUB: u32 = 0xa6; + pub const F64X2_MUL: u32 = 0xa7; + pub const F64X2_DIV: u32 = 0xa8; + pub const F64X2_MIN: u32 = 0xa9; + pub const F64X2_MAX: u32 = 0xaa; + + pub const I32X4_TRUNC_S_F32X4_SAT: u32 = 0xab; + pub const I32X4_TRUNC_U_F32X4_SAT: u32 = 0xac; + pub const I64X2_TRUNC_S_F64X2_SAT: u32 = 0xad; + pub const I64X2_TRUNC_U_F64X2_SAT: u32 = 0xae; + + pub const F32X4_CONVERT_S_I32X4: u32 = 0xaf; + pub const F32X4_CONVERT_U_I32X4: u32 = 0xb0; + pub const F64X2_CONVERT_S_I64X2: u32 = 0xb1; + pub const F64X2_CONVERT_U_I64X2: u32 = 0xb2; + + pub const BULK_PREFIX: u8 = 0xfc; + pub const MEMORY_INIT: u8 = 0x08; + pub const MEMORY_DROP: u8 = 0x09; + pub const MEMORY_COPY: u8 = 0x0a; + pub const MEMORY_FILL: u8 = 0x0b; + pub const TABLE_INIT: u8 = 0x0c; + pub const TABLE_DROP: u8 = 0x0d; + pub const TABLE_COPY: u8 = 0x0e; +} + +impl Deserialize for Instruction { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + use self::Instruction::*; + use self::opcodes::*; + + let val: u8 = Uint8::deserialize(reader)?.into(); + + Ok( + match val { + UNREACHABLE => Unreachable, + NOP => Nop, + BLOCK => Block(BlockType::deserialize(reader)?), + LOOP => Loop(BlockType::deserialize(reader)?), + IF => If(BlockType::deserialize(reader)?), + ELSE => Else, + END => End, + + BR => Br(VarUint32::deserialize(reader)?.into()), + BRIF => BrIf(VarUint32::deserialize(reader)?.into()), + BRTABLE => { + let t1: Vec = CountedList::::deserialize(reader)? + .into_inner() + .into_iter() + .map(Into::into) + .collect(); + + BrTable(Box::new(BrTableData { + table: t1.into_boxed_slice(), + default: VarUint32::deserialize(reader)?.into(), + })) + }, + RETURN => Return, + CALL => Call(VarUint32::deserialize(reader)?.into()), + CALLINDIRECT => { + let signature: u32 = VarUint32::deserialize(reader)?.into(); + let table_ref: u8 = Uint8::deserialize(reader)?.into(); + if table_ref != 0 { return Err(Error::InvalidTableReference(table_ref)); } + + CallIndirect( + signature, + table_ref, + ) + }, + DROP => Drop, + SELECT => Select, + + GETLOCAL => GetLocal(VarUint32::deserialize(reader)?.into()), + SETLOCAL => SetLocal(VarUint32::deserialize(reader)?.into()), + TEELOCAL => TeeLocal(VarUint32::deserialize(reader)?.into()), + GETGLOBAL => GetGlobal(VarUint32::deserialize(reader)?.into()), + SETGLOBAL => SetGlobal(VarUint32::deserialize(reader)?.into()), + + I32LOAD => I32Load( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64LOAD => I64Load( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + F32LOAD => F32Load( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + F64LOAD => F64Load( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I32LOAD8S => I32Load8S( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I32LOAD8U => I32Load8U( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I32LOAD16S => I32Load16S( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I32LOAD16U => I32Load16U( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64LOAD8S => I64Load8S( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64LOAD8U => I64Load8U( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64LOAD16S => I64Load16S( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64LOAD16U => I64Load16U( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64LOAD32S => I64Load32S( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64LOAD32U => I64Load32U( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I32STORE => I32Store( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64STORE => I64Store( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + F32STORE => F32Store( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + F64STORE => F64Store( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I32STORE8 => I32Store8( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I32STORE16 => I32Store16( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64STORE8 => I64Store8( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64STORE16 => I64Store16( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64STORE32 => I64Store32( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + + CURRENTMEMORY => { + let mem_ref: u8 = Uint8::deserialize(reader)?.into(); + if mem_ref != 0 { return Err(Error::InvalidMemoryReference(mem_ref)); } + CurrentMemory(mem_ref) + }, + GROWMEMORY => { + let mem_ref: u8 = Uint8::deserialize(reader)?.into(); + if mem_ref != 0 { return Err(Error::InvalidMemoryReference(mem_ref)); } + GrowMemory(mem_ref) + } + + I32CONST => I32Const(VarInt32::deserialize(reader)?.into()), + I64CONST => I64Const(VarInt64::deserialize(reader)?.into()), + F32CONST => F32Const(Uint32::deserialize(reader)?.into()), + F64CONST => F64Const(Uint64::deserialize(reader)?.into()), + I32EQZ => I32Eqz, + I32EQ => I32Eq, + I32NE => I32Ne, + I32LTS => I32LtS, + I32LTU => I32LtU, + I32GTS => I32GtS, + I32GTU => I32GtU, + I32LES => I32LeS, + I32LEU => I32LeU, + I32GES => I32GeS, + I32GEU => I32GeU, + + I64EQZ => I64Eqz, + I64EQ => I64Eq, + I64NE => I64Ne, + I64LTS => I64LtS, + I64LTU => I64LtU, + I64GTS => I64GtS, + I64GTU => I64GtU, + I64LES => I64LeS, + I64LEU => I64LeU, + I64GES => I64GeS, + I64GEU => I64GeU, + + F32EQ => F32Eq, + F32NE => F32Ne, + F32LT => F32Lt, + F32GT => F32Gt, + F32LE => F32Le, + F32GE => F32Ge, + + F64EQ => F64Eq, + F64NE => F64Ne, + F64LT => F64Lt, + F64GT => F64Gt, + F64LE => F64Le, + F64GE => F64Ge, + + I32CLZ => I32Clz, + I32CTZ => I32Ctz, + I32POPCNT => I32Popcnt, + I32ADD => I32Add, + I32SUB => I32Sub, + I32MUL => I32Mul, + I32DIVS => I32DivS, + I32DIVU => I32DivU, + I32REMS => I32RemS, + I32REMU => I32RemU, + I32AND => I32And, + I32OR => I32Or, + I32XOR => I32Xor, + I32SHL => I32Shl, + I32SHRS => I32ShrS, + I32SHRU => I32ShrU, + I32ROTL => I32Rotl, + I32ROTR => I32Rotr, + + I64CLZ => I64Clz, + I64CTZ => I64Ctz, + I64POPCNT => I64Popcnt, + I64ADD => I64Add, + I64SUB => I64Sub, + I64MUL => I64Mul, + I64DIVS => I64DivS, + I64DIVU => I64DivU, + I64REMS => I64RemS, + I64REMU => I64RemU, + I64AND => I64And, + I64OR => I64Or, + I64XOR => I64Xor, + I64SHL => I64Shl, + I64SHRS => I64ShrS, + I64SHRU => I64ShrU, + I64ROTL => I64Rotl, + I64ROTR => I64Rotr, + F32ABS => F32Abs, + F32NEG => F32Neg, + F32CEIL => F32Ceil, + F32FLOOR => F32Floor, + F32TRUNC => F32Trunc, + F32NEAREST => F32Nearest, + F32SQRT => F32Sqrt, + F32ADD => F32Add, + F32SUB => F32Sub, + F32MUL => F32Mul, + F32DIV => F32Div, + F32MIN => F32Min, + F32MAX => F32Max, + F32COPYSIGN => F32Copysign, + F64ABS => F64Abs, + F64NEG => F64Neg, + F64CEIL => F64Ceil, + F64FLOOR => F64Floor, + F64TRUNC => F64Trunc, + F64NEAREST => F64Nearest, + F64SQRT => F64Sqrt, + F64ADD => F64Add, + F64SUB => F64Sub, + F64MUL => F64Mul, + F64DIV => F64Div, + F64MIN => F64Min, + F64MAX => F64Max, + F64COPYSIGN => F64Copysign, + + I32WRAPI64 => I32WrapI64, + I32TRUNCSF32 => I32TruncSF32, + I32TRUNCUF32 => I32TruncUF32, + I32TRUNCSF64 => I32TruncSF64, + I32TRUNCUF64 => I32TruncUF64, + I64EXTENDSI32 => I64ExtendSI32, + I64EXTENDUI32 => I64ExtendUI32, + I64TRUNCSF32 => I64TruncSF32, + I64TRUNCUF32 => I64TruncUF32, + I64TRUNCSF64 => I64TruncSF64, + I64TRUNCUF64 => I64TruncUF64, + F32CONVERTSI32 => F32ConvertSI32, + F32CONVERTUI32 => F32ConvertUI32, + F32CONVERTSI64 => F32ConvertSI64, + F32CONVERTUI64 => F32ConvertUI64, + F32DEMOTEF64 => F32DemoteF64, + F64CONVERTSI32 => F64ConvertSI32, + F64CONVERTUI32 => F64ConvertUI32, + F64CONVERTSI64 => F64ConvertSI64, + F64CONVERTUI64 => F64ConvertUI64, + F64PROMOTEF32 => F64PromoteF32, + + I32REINTERPRETF32 => I32ReinterpretF32, + I64REINTERPRETF64 => I64ReinterpretF64, + F32REINTERPRETI32 => F32ReinterpretI32, + F64REINTERPRETI64 => F64ReinterpretI64, + I32_EXTEND8_S => I32Extend8S, + I32_EXTEND16_S => I32Extend16S, + I64_EXTEND8_S => I64Extend8S, + I64_EXTEND16_S => I64Extend16S, + I64_EXTEND32_S => I64Extend32S, + + ATOMIC_PREFIX => return deserialize_atomic(reader), + SIMD_PREFIX => return deserialize_simd(reader), + + BULK_PREFIX => return deserialize_bulk(reader), + + _ => { return Err(Error::UnknownOpcode(val)); } + } + ) + } +} + +fn deserialize_atomic(reader: &mut R) -> Result { + use self::Instruction::*; + use self::opcodes::*; + + let val: u8 = Uint8::deserialize(reader)?.into(); + let mem = MemArg::deserialize(reader)?; + Ok(match val { + ATOMIC_WAKE => AtomicWake(mem), + I32_ATOMIC_WAIT => I32AtomicWait(mem), + I64_ATOMIC_WAIT => I64AtomicWait(mem), + + I32_ATOMIC_LOAD => I32AtomicLoad(mem), + I64_ATOMIC_LOAD => I64AtomicLoad(mem), + I32_ATOMIC_LOAD8U => I32AtomicLoad8u(mem), + I32_ATOMIC_LOAD16U => I32AtomicLoad16u(mem), + I64_ATOMIC_LOAD8U => I64AtomicLoad8u(mem), + I64_ATOMIC_LOAD16U => I64AtomicLoad16u(mem), + I64_ATOMIC_LOAD32U => I64AtomicLoad32u(mem), + I32_ATOMIC_STORE => I32AtomicStore(mem), + I64_ATOMIC_STORE => I64AtomicStore(mem), + I32_ATOMIC_STORE8U => I32AtomicStore8u(mem), + I32_ATOMIC_STORE16U => I32AtomicStore16u(mem), + I64_ATOMIC_STORE8U => I64AtomicStore8u(mem), + I64_ATOMIC_STORE16U => I64AtomicStore16u(mem), + I64_ATOMIC_STORE32U => I64AtomicStore32u(mem), + + I32_ATOMIC_RMW_ADD => I32AtomicRmwAdd(mem), + I64_ATOMIC_RMW_ADD => I64AtomicRmwAdd(mem), + I32_ATOMIC_RMW_ADD8U => I32AtomicRmwAdd8u(mem), + I32_ATOMIC_RMW_ADD16U => I32AtomicRmwAdd16u(mem), + I64_ATOMIC_RMW_ADD8U => I64AtomicRmwAdd8u(mem), + I64_ATOMIC_RMW_ADD16U => I64AtomicRmwAdd16u(mem), + I64_ATOMIC_RMW_ADD32U => I64AtomicRmwAdd32u(mem), + + I32_ATOMIC_RMW_SUB => I32AtomicRmwSub(mem), + I64_ATOMIC_RMW_SUB => I64AtomicRmwSub(mem), + I32_ATOMIC_RMW_SUB8U => I32AtomicRmwSub8u(mem), + I32_ATOMIC_RMW_SUB16U => I32AtomicRmwSub16u(mem), + I64_ATOMIC_RMW_SUB8U => I64AtomicRmwSub8u(mem), + I64_ATOMIC_RMW_SUB16U => I64AtomicRmwSub16u(mem), + I64_ATOMIC_RMW_SUB32U => I64AtomicRmwSub32u(mem), + + I32_ATOMIC_RMW_OR => I32AtomicRmwOr(mem), + I64_ATOMIC_RMW_OR => I64AtomicRmwOr(mem), + I32_ATOMIC_RMW_OR8U => I32AtomicRmwOr8u(mem), + I32_ATOMIC_RMW_OR16U => I32AtomicRmwOr16u(mem), + I64_ATOMIC_RMW_OR8U => I64AtomicRmwOr8u(mem), + I64_ATOMIC_RMW_OR16U => I64AtomicRmwOr16u(mem), + I64_ATOMIC_RMW_OR32U => I64AtomicRmwOr32u(mem), + + I32_ATOMIC_RMW_XOR => I32AtomicRmwXor(mem), + I64_ATOMIC_RMW_XOR => I64AtomicRmwXor(mem), + I32_ATOMIC_RMW_XOR8U => I32AtomicRmwXor8u(mem), + I32_ATOMIC_RMW_XOR16U => I32AtomicRmwXor16u(mem), + I64_ATOMIC_RMW_XOR8U => I64AtomicRmwXor8u(mem), + I64_ATOMIC_RMW_XOR16U => I64AtomicRmwXor16u(mem), + I64_ATOMIC_RMW_XOR32U => I64AtomicRmwXor32u(mem), + + I32_ATOMIC_RMW_XCHG => I32AtomicRmwXchg(mem), + I64_ATOMIC_RMW_XCHG => I64AtomicRmwXchg(mem), + I32_ATOMIC_RMW_XCHG8U => I32AtomicRmwXchg8u(mem), + I32_ATOMIC_RMW_XCHG16U => I32AtomicRmwXchg16u(mem), + I64_ATOMIC_RMW_XCHG8U => I64AtomicRmwXchg8u(mem), + I64_ATOMIC_RMW_XCHG16U => I64AtomicRmwXchg16u(mem), + I64_ATOMIC_RMW_XCHG32U => I64AtomicRmwXchg32u(mem), + + I32_ATOMIC_RMW_CMPXCHG => I32AtomicRmwCmpxchg(mem), + I64_ATOMIC_RMW_CMPXCHG => I64AtomicRmwCmpxchg(mem), + I32_ATOMIC_RMW_CMPXCHG8U => I32AtomicRmwCmpxchg8u(mem), + I32_ATOMIC_RMW_CMPXCHG16U => I32AtomicRmwCmpxchg16u(mem), + I64_ATOMIC_RMW_CMPXCHG8U => I64AtomicRmwCmpxchg8u(mem), + I64_ATOMIC_RMW_CMPXCHG16U => I64AtomicRmwCmpxchg16u(mem), + I64_ATOMIC_RMW_CMPXCHG32U => I64AtomicRmwCmpxchg32u(mem), + + _ => return Err(Error::UnknownOpcode(val)), + }) +} + +fn deserialize_simd(reader: &mut R) -> Result { + use self::Instruction::*; + use self::opcodes::*; + + let val = VarUint32::deserialize(reader)?.into(); + Ok(match val { + V128_CONST => { + let mut buf = [0; 16]; + reader.read(&mut buf)?; + V128Const(Box::new(buf)) + } + V128_LOAD => V128Load(MemArg::deserialize(reader)?), + V128_STORE => V128Store(MemArg::deserialize(reader)?), + I8X16_SPLAT => I8x16Splat, + I16X8_SPLAT => I16x8Splat, + I32X4_SPLAT => I32x4Splat, + I64X2_SPLAT => I64x2Splat, + F32X4_SPLAT => F32x4Splat, + F64X2_SPLAT => F64x2Splat, + I8X16_EXTRACT_LANE_S => I8x16ExtractLaneS(Uint8::deserialize(reader)?.into()), + I8X16_EXTRACT_LANE_U => I8x16ExtractLaneU(Uint8::deserialize(reader)?.into()), + I16X8_EXTRACT_LANE_S => I16x8ExtractLaneS(Uint8::deserialize(reader)?.into()), + I16X8_EXTRACT_LANE_U => I16x8ExtractLaneU(Uint8::deserialize(reader)?.into()), + I32X4_EXTRACT_LANE => I32x4ExtractLane(Uint8::deserialize(reader)?.into()), + I64X2_EXTRACT_LANE => I64x2ExtractLane(Uint8::deserialize(reader)?.into()), + F32X4_EXTRACT_LANE => F32x4ExtractLane(Uint8::deserialize(reader)?.into()), + F64X2_EXTRACT_LANE => F64x2ExtractLane(Uint8::deserialize(reader)?.into()), + I8X16_REPLACE_LANE => I8x16ReplaceLane(Uint8::deserialize(reader)?.into()), + I16X8_REPLACE_LANE => I16x8ReplaceLane(Uint8::deserialize(reader)?.into()), + I32X4_REPLACE_LANE => I32x4ReplaceLane(Uint8::deserialize(reader)?.into()), + I64X2_REPLACE_LANE => I64x2ReplaceLane(Uint8::deserialize(reader)?.into()), + F32X4_REPLACE_LANE => F32x4ReplaceLane(Uint8::deserialize(reader)?.into()), + F64X2_REPLACE_LANE => F64x2ReplaceLane(Uint8::deserialize(reader)?.into()), + V8X16_SHUFFLE => { + let mut buf = [0; 16]; + reader.read(&mut buf)?; + V8x16Shuffle(Box::new(buf)) + } + I8X16_ADD => I8x16Add, + I16X8_ADD => I16x8Add, + I32X4_ADD => I32x4Add, + I64X2_ADD => I64x2Add, + I8X16_SUB => I8x16Sub, + I16X8_SUB => I16x8Sub, + I32X4_SUB => I32x4Sub, + I64X2_SUB => I64x2Sub, + I8X16_MUL => I8x16Mul, + I16X8_MUL => I16x8Mul, + I32X4_MUL => I32x4Mul, + // I64X2_MUL => I64x2Mul, + I8X16_NEG => I8x16Neg, + I16X8_NEG => I16x8Neg, + I32X4_NEG => I32x4Neg, + I64X2_NEG => I64x2Neg, + + I8X16_ADD_SATURATE_S => I8x16AddSaturateS, + I8X16_ADD_SATURATE_U => I8x16AddSaturateU, + I16X8_ADD_SATURATE_S => I16x8AddSaturateS, + I16X8_ADD_SATURATE_U => I16x8AddSaturateU, + I8X16_SUB_SATURATE_S => I8x16SubSaturateS, + I8X16_SUB_SATURATE_U => I8x16SubSaturateU, + I16X8_SUB_SATURATE_S => I16x8SubSaturateS, + I16X8_SUB_SATURATE_U => I16x8SubSaturateU, + I8X16_SHL => I8x16Shl, + I16X8_SHL => I16x8Shl, + I32X4_SHL => I32x4Shl, + I64X2_SHL => I64x2Shl, + I8X16_SHR_S => I8x16ShrS, + I8X16_SHR_U => I8x16ShrU, + I16X8_SHR_S => I16x8ShrS, + I16X8_SHR_U => I16x8ShrU, + I32X4_SHR_S => I32x4ShrS, + I32X4_SHR_U => I32x4ShrU, + I64X2_SHR_S => I64x2ShrS, + I64X2_SHR_U => I64x2ShrU, + V128_AND => V128And, + V128_OR => V128Or, + V128_XOR => V128Xor, + V128_NOT => V128Not, + V128_BITSELECT => V128Bitselect, + I8X16_ANY_TRUE => I8x16AnyTrue, + I16X8_ANY_TRUE => I16x8AnyTrue, + I32X4_ANY_TRUE => I32x4AnyTrue, + I64X2_ANY_TRUE => I64x2AnyTrue, + I8X16_ALL_TRUE => I8x16AllTrue, + I16X8_ALL_TRUE => I16x8AllTrue, + I32X4_ALL_TRUE => I32x4AllTrue, + I64X2_ALL_TRUE => I64x2AllTrue, + I8X16_EQ => I8x16Eq, + I16X8_EQ => I16x8Eq, + I32X4_EQ => I32x4Eq, + // I64X2_EQ => I64x2Eq, + F32X4_EQ => F32x4Eq, + F64X2_EQ => F64x2Eq, + I8X16_NE => I8x16Ne, + I16X8_NE => I16x8Ne, + I32X4_NE => I32x4Ne, + // I64X2_NE => I64x2Ne, + F32X4_NE => F32x4Ne, + F64X2_NE => F64x2Ne, + I8X16_LT_S => I8x16LtS, + I8X16_LT_U => I8x16LtU, + I16X8_LT_S => I16x8LtS, + I16X8_LT_U => I16x8LtU, + I32X4_LT_S => I32x4LtS, + I32X4_LT_U => I32x4LtU, + // I64X2_LT_S => I64x2LtS, + // I64X2_LT_U => I64x2LtU, + F32X4_LT => F32x4Lt, + F64X2_LT => F64x2Lt, + I8X16_LE_S => I8x16LeS, + I8X16_LE_U => I8x16LeU, + I16X8_LE_S => I16x8LeS, + I16X8_LE_U => I16x8LeU, + I32X4_LE_S => I32x4LeS, + I32X4_LE_U => I32x4LeU, + // I64X2_LE_S => I64x2LeS, + // I64X2_LE_U => I64x2LeU, + F32X4_LE => F32x4Le, + F64X2_LE => F64x2Le, + I8X16_GT_S => I8x16GtS, + I8X16_GT_U => I8x16GtU, + I16X8_GT_S => I16x8GtS, + I16X8_GT_U => I16x8GtU, + I32X4_GT_S => I32x4GtS, + I32X4_GT_U => I32x4GtU, + // I64X2_GT_S => I64x2GtS, + // I64X2_GT_U => I64x2GtU, + F32X4_GT => F32x4Gt, + F64X2_GT => F64x2Gt, + I8X16_GE_S => I8x16GeS, + I8X16_GE_U => I8x16GeU, + I16X8_GE_S => I16x8GeS, + I16X8_GE_U => I16x8GeU, + I32X4_GE_S => I32x4GeS, + I32X4_GE_U => I32x4GeU, + // I64X2_GE_S => I64x2GeS, + // I64X2_GE_U => I64x2GeU, + F32X4_GE => F32x4Ge, + F64X2_GE => F64x2Ge, + F32X4_NEG => F32x4Neg, + F64X2_NEG => F64x2Neg, + F32X4_ABS => F32x4Abs, + F64X2_ABS => F64x2Abs, + F32X4_MIN => F32x4Min, + F64X2_MIN => F64x2Min, + F32X4_MAX => F32x4Max, + F64X2_MAX => F64x2Max, + F32X4_ADD => F32x4Add, + F64X2_ADD => F64x2Add, + F32X4_SUB => F32x4Sub, + F64X2_SUB => F64x2Sub, + F32X4_DIV => F32x4Div, + F64X2_DIV => F64x2Div, + F32X4_MUL => F32x4Mul, + F64X2_MUL => F64x2Mul, + F32X4_SQRT => F32x4Sqrt, + F64X2_SQRT => F64x2Sqrt, + F32X4_CONVERT_S_I32X4 => F32x4ConvertSI32x4, + F32X4_CONVERT_U_I32X4 => F32x4ConvertUI32x4, + F64X2_CONVERT_S_I64X2 => F64x2ConvertSI64x2, + F64X2_CONVERT_U_I64X2 => F64x2ConvertUI64x2, + I32X4_TRUNC_S_F32X4_SAT => I32x4TruncSF32x4Sat, + I32X4_TRUNC_U_F32X4_SAT => I32x4TruncUF32x4Sat, + I64X2_TRUNC_S_F64X2_SAT => I64x2TruncSF64x2Sat, + I64X2_TRUNC_U_F64X2_SAT => I64x2TruncUF64x2Sat, + + _ => return Err(Error::UnknownSimdOpcode(val)), + }) +} + +fn deserialize_bulk(reader: &mut R) -> Result { + use self::Instruction::*; + use self::opcodes::*; + + let val: u8 = Uint8::deserialize(reader)?.into(); + Ok(match val { + MEMORY_INIT => { + if u8::from(Uint8::deserialize(reader)?) != 0 { + return Err(Error::UnknownOpcode(val)) + } + MemoryInit(VarUint32::deserialize(reader)?.into()) + } + MEMORY_DROP => MemoryDrop(VarUint32::deserialize(reader)?.into()), + MEMORY_FILL => { + if u8::from(Uint8::deserialize(reader)?) != 0 { + return Err(Error::UnknownOpcode(val)) + } + MemoryFill + } + MEMORY_COPY => { + if u8::from(Uint8::deserialize(reader)?) != 0 { + return Err(Error::UnknownOpcode(val)) + } + MemoryCopy + } + + TABLE_INIT => { + if u8::from(Uint8::deserialize(reader)?) != 0 { + return Err(Error::UnknownOpcode(val)) + } + TableInit(VarUint32::deserialize(reader)?.into()) + } + TABLE_DROP => TableDrop(VarUint32::deserialize(reader)?.into()), + TABLE_COPY => { + if u8::from(Uint8::deserialize(reader)?) != 0 { + return Err(Error::UnknownOpcode(val)) + } + TableCopy + } + + _ => return Err(Error::UnknownOpcode(val)), + }) +} + +impl Deserialize for MemArg { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let align = Uint8::deserialize(reader)?; + let offset = VarUint32::deserialize(reader)?; + Ok(MemArg { align: align.into(), offset: offset.into() }) + } +} + +macro_rules! op { + ($writer: expr, $byte: expr) => ({ + let b: u8 = $byte; + $writer.write(&[b])?; + }); + ($writer: expr, $byte: expr, $s: block) => ({ + op!($writer, $byte); + $s; + }); +} + +macro_rules! atomic { + ($writer: expr, $byte: expr, $mem:expr) => ({ + $writer.write(&[ATOMIC_PREFIX, $byte])?; + MemArg::serialize($mem, $writer)?; + }); +} + +macro_rules! simd { + ($writer: expr, $byte: expr, $other:expr) => ({ + $writer.write(&[SIMD_PREFIX])?; + VarUint32::from($byte).serialize($writer)?; + $other; + }) +} + +macro_rules! bulk { + ($writer: expr, $byte: expr) => ({ + $writer.write(&[BULK_PREFIX, $byte])?; + }); + ($writer: expr, $byte: expr, $remaining:expr) => ({ + bulk!($writer, $byte); + $remaining; + }); +} + +// impl Serialize for Instruction { +// type Error = Error; + +// fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { +// use self::Instruction::*; +// use self::opcodes::*; + +// match self { +// Unreachable => op!(writer, UNREACHABLE), +// Nop => op!(writer, NOP), +// Block(block_type) => op!(writer, BLOCK, { +// block_type.serialize(writer)?; +// }), +// Loop(block_type) => op!(writer, LOOP, { +// block_type.serialize(writer)?; +// }), +// If(block_type) => op!(writer, IF, { +// block_type.serialize(writer)?; +// }), +// Else => op!(writer, ELSE), +// End => op!(writer, END), +// Br(idx) => op!(writer, BR, { +// VarUint32::from(idx).serialize(writer)?; +// }), +// BrIf(idx) => op!(writer, BRIF, { +// VarUint32::from(idx).serialize(writer)?; +// }), +// BrTable(ref table) => op!(writer, BRTABLE, { +// let list_writer = CountedListWriter::( +// table.table.len(), +// table.table.into_iter().map(|x| VarUint32::from(*x)), +// ); +// list_writer.serialize(writer)?; +// VarUint32::from(table.default).serialize(writer)?; +// }), +// Return => op!(writer, RETURN), +// Call(index) => op!(writer, CALL, { +// VarUint32::from(index).serialize(writer)?; +// }), +// CallIndirect(index, reserved) => op!(writer, CALLINDIRECT, { +// VarUint32::from(index).serialize(writer)?; +// Uint8::from(reserved).serialize(writer)?; +// }), +// Drop => op!(writer, DROP), +// Select => op!(writer, SELECT), +// GetLocal(index) => op!(writer, GETLOCAL, { +// VarUint32::from(index).serialize(writer)?; +// }), +// SetLocal(index) => op!(writer, SETLOCAL, { +// VarUint32::from(index).serialize(writer)?; +// }), +// TeeLocal(index) => op!(writer, TEELOCAL, { +// VarUint32::from(index).serialize(writer)?; +// }), +// GetGlobal(index) => op!(writer, GETGLOBAL, { +// VarUint32::from(index).serialize(writer)?; +// }), +// SetGlobal(index) => op!(writer, SETGLOBAL, { +// VarUint32::from(index).serialize(writer)?; +// }), +// I32Load(flags, offset) => op!(writer, I32LOAD, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I64Load(flags, offset) => op!(writer, I64LOAD, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// F32Load(flags, offset) => op!(writer, F32LOAD, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// F64Load(flags, offset) => op!(writer, F64LOAD, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I32Load8S(flags, offset) => op!(writer, I32LOAD8S, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I32Load8U(flags, offset) => op!(writer, I32LOAD8U, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I32Load16S(flags, offset) => op!(writer, I32LOAD16S, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I32Load16U(flags, offset) => op!(writer, I32LOAD16U, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I64Load8S(flags, offset) => op!(writer, I64LOAD8S, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I64Load8U(flags, offset) => op!(writer, I64LOAD8U, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I64Load16S(flags, offset) => op!(writer, I64LOAD16S, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I64Load16U(flags, offset) => op!(writer, I64LOAD16U, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I64Load32S(flags, offset) => op!(writer, I64LOAD32S, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I64Load32U(flags, offset) => op!(writer, I64LOAD32U, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I32Store(flags, offset) => op!(writer, I32STORE, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I64Store(flags, offset) => op!(writer, I64STORE, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// F32Store(flags, offset) => op!(writer, F32STORE, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// F64Store(flags, offset) => op!(writer, F64STORE, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I32Store8(flags, offset) => op!(writer, I32STORE8, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I32Store16(flags, offset) => op!(writer, I32STORE16, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I64Store8(flags, offset) => op!(writer, I64STORE8, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I64Store16(flags, offset) => op!(writer, I64STORE16, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// I64Store32(flags, offset) => op!(writer, I64STORE32, { +// VarUint32::from(flags).serialize(writer)?; +// VarUint32::from(offset).serialize(writer)?; +// }), +// CurrentMemory(flag) => op!(writer, CURRENTMEMORY, { +// Uint8::from(flag).serialize(writer)?; +// }), +// GrowMemory(flag) => op!(writer, GROWMEMORY, { +// Uint8::from(flag).serialize(writer)?; +// }), +// I32Const(def) => op!(writer, I32CONST, { +// VarInt32::from(def).serialize(writer)?; +// }), +// I64Const(def) => op!(writer, I64CONST, { +// VarInt64::from(def).serialize(writer)?; +// }), +// F32Const(def) => op!(writer, F32CONST, { +// Uint32::from(def).serialize(writer)?; +// }), +// F64Const(def) => op!(writer, F64CONST, { +// Uint64::from(def).serialize(writer)?; +// }), +// I32Eqz => op!(writer, I32EQZ), +// I32Eq => op!(writer, I32EQ), +// I32Ne => op!(writer, I32NE), +// I32LtS => op!(writer, I32LTS), +// I32LtU => op!(writer, I32LTU), +// I32GtS => op!(writer, I32GTS), +// I32GtU => op!(writer, I32GTU), +// I32LeS => op!(writer, I32LES), +// I32LeU => op!(writer, I32LEU), +// I32GeS => op!(writer, I32GES), +// I32GeU => op!(writer, I32GEU), + +// I64Eqz => op!(writer, I64EQZ), +// I64Eq => op!(writer, I64EQ), +// I64Ne => op!(writer, I64NE), +// I64LtS => op!(writer, I64LTS), +// I64LtU => op!(writer, I64LTU), +// I64GtS => op!(writer, I64GTS), +// I64GtU => op!(writer, I64GTU), +// I64LeS => op!(writer, I64LES), +// I64LeU => op!(writer, I64LEU), +// I64GeS => op!(writer, I64GES), +// I64GeU => op!(writer, I64GEU), + +// F32Eq => op!(writer, F32EQ), +// F32Ne => op!(writer, F32NE), +// F32Lt => op!(writer, F32LT), +// F32Gt => op!(writer, F32GT), +// F32Le => op!(writer, F32LE), +// F32Ge => op!(writer, F32GE), + +// F64Eq => op!(writer, F64EQ), +// F64Ne => op!(writer, F64NE), +// F64Lt => op!(writer, F64LT), +// F64Gt => op!(writer, F64GT), +// F64Le => op!(writer, F64LE), +// F64Ge => op!(writer, F64GE), + +// I32Clz => op!(writer, I32CLZ), +// I32Ctz => op!(writer, I32CTZ), +// I32Popcnt => op!(writer, I32POPCNT), +// I32Add => op!(writer, I32ADD), +// I32Sub => op!(writer, I32SUB), +// I32Mul => op!(writer, I32MUL), +// I32DivS => op!(writer, I32DIVS), +// I32DivU => op!(writer, I32DIVU), +// I32RemS => op!(writer, I32REMS), +// I32RemU => op!(writer, I32REMU), +// I32And => op!(writer, I32AND), +// I32Or => op!(writer, I32OR), +// I32Xor => op!(writer, I32XOR), +// I32Shl => op!(writer, I32SHL), +// I32ShrS => op!(writer, I32SHRS), +// I32ShrU => op!(writer, I32SHRU), +// I32Rotl => op!(writer, I32ROTL), +// I32Rotr => op!(writer, I32ROTR), + +// I64Clz => op!(writer, I64CLZ), +// I64Ctz => op!(writer, I64CTZ), +// I64Popcnt => op!(writer, I64POPCNT), +// I64Add => op!(writer, I64ADD), +// I64Sub => op!(writer, I64SUB), +// I64Mul => op!(writer, I64MUL), +// I64DivS => op!(writer, I64DIVS), +// I64DivU => op!(writer, I64DIVU), +// I64RemS => op!(writer, I64REMS), +// I64RemU => op!(writer, I64REMU), +// I64And => op!(writer, I64AND), +// I64Or => op!(writer, I64OR), +// I64Xor => op!(writer, I64XOR), +// I64Shl => op!(writer, I64SHL), +// I64ShrS => op!(writer, I64SHRS), +// I64ShrU => op!(writer, I64SHRU), +// I64Rotl => op!(writer, I64ROTL), +// I64Rotr => op!(writer, I64ROTR), +// F32Abs => op!(writer, F32ABS), +// F32Neg => op!(writer, F32NEG), +// F32Ceil => op!(writer, F32CEIL), +// F32Floor => op!(writer, F32FLOOR), +// F32Trunc => op!(writer, F32TRUNC), +// F32Nearest => op!(writer, F32NEAREST), +// F32Sqrt => op!(writer, F32SQRT), +// F32Add => op!(writer, F32ADD), +// F32Sub => op!(writer, F32SUB), +// F32Mul => op!(writer, F32MUL), +// F32Div => op!(writer, F32DIV), +// F32Min => op!(writer, F32MIN), +// F32Max => op!(writer, F32MAX), +// F32Copysign => op!(writer, F32COPYSIGN), +// F64Abs => op!(writer, F64ABS), +// F64Neg => op!(writer, F64NEG), +// F64Ceil => op!(writer, F64CEIL), +// F64Floor => op!(writer, F64FLOOR), +// F64Trunc => op!(writer, F64TRUNC), +// F64Nearest => op!(writer, F64NEAREST), +// F64Sqrt => op!(writer, F64SQRT), +// F64Add => op!(writer, F64ADD), +// F64Sub => op!(writer, F64SUB), +// F64Mul => op!(writer, F64MUL), +// F64Div => op!(writer, F64DIV), +// F64Min => op!(writer, F64MIN), +// F64Max => op!(writer, F64MAX), +// F64Copysign => op!(writer, F64COPYSIGN), + +// I32WrapI64 => op!(writer, I32WRAPI64), +// I32TruncSF32 => op!(writer, I32TRUNCSF32), +// I32TruncUF32 => op!(writer, I32TRUNCUF32), +// I32TruncSF64 => op!(writer, I32TRUNCSF64), +// I32TruncUF64 => op!(writer, I32TRUNCUF64), +// I64ExtendSI32 => op!(writer, I64EXTENDSI32), +// I64ExtendUI32 => op!(writer, I64EXTENDUI32), +// I64TruncSF32 => op!(writer, I64TRUNCSF32), +// I64TruncUF32 => op!(writer, I64TRUNCUF32), +// I64TruncSF64 => op!(writer, I64TRUNCSF64), +// I64TruncUF64 => op!(writer, I64TRUNCUF64), +// F32ConvertSI32 => op!(writer, F32CONVERTSI32), +// F32ConvertUI32 => op!(writer, F32CONVERTUI32), +// F32ConvertSI64 => op!(writer, F32CONVERTSI64), +// F32ConvertUI64 => op!(writer, F32CONVERTUI64), +// F32DemoteF64 => op!(writer, F32DEMOTEF64), +// F64ConvertSI32 => op!(writer, F64CONVERTSI32), +// F64ConvertUI32 => op!(writer, F64CONVERTUI32), +// F64ConvertSI64 => op!(writer, F64CONVERTSI64), +// F64ConvertUI64 => op!(writer, F64CONVERTUI64), +// F64PromoteF32 => op!(writer, F64PROMOTEF32), + +// I32ReinterpretF32 => op!(writer, I32REINTERPRETF32), +// I64ReinterpretF64 => op!(writer, I64REINTERPRETF64), +// F32ReinterpretI32 => op!(writer, F32REINTERPRETI32), +// F64ReinterpretI64 => op!(writer, F64REINTERPRETI64), + +// I32Extend8S => op!(writer, I32_EXTEND8_S), +// I32Extend16S => op!(writer, I32_EXTEND16_S), +// I64Extend8S => op!(writer, I64_EXTEND8_S), +// I64Extend16S => op!(writer, I64_EXTEND16_S), +// I64Extend32S => op!(writer, I64_EXTEND32_S), + +// AtomicWake(m) => atomic!(writer, ATOMIC_WAKE, m), +// I32AtomicWait(m) => atomic!(writer, I32_ATOMIC_WAIT, m), +// I64AtomicWait(m) => atomic!(writer, I64_ATOMIC_WAIT, m), + +// I32AtomicLoad(m) => atomic!(writer, I32_ATOMIC_LOAD, m), +// I64AtomicLoad(m) => atomic!(writer, I64_ATOMIC_LOAD, m), +// I32AtomicLoad8u(m) => atomic!(writer, I32_ATOMIC_LOAD8U, m), +// I32AtomicLoad16u(m) => atomic!(writer, I32_ATOMIC_LOAD16U, m), +// I64AtomicLoad8u(m) => atomic!(writer, I64_ATOMIC_LOAD8U, m), +// I64AtomicLoad16u(m) => atomic!(writer, I64_ATOMIC_LOAD16U, m), +// I64AtomicLoad32u(m) => atomic!(writer, I64_ATOMIC_LOAD32U, m), +// I32AtomicStore(m) => atomic!(writer, I32_ATOMIC_STORE, m), +// I64AtomicStore(m) => atomic!(writer, I64_ATOMIC_STORE, m), +// I32AtomicStore8u(m) => atomic!(writer, I32_ATOMIC_STORE8U, m), +// I32AtomicStore16u(m) => atomic!(writer, I32_ATOMIC_STORE16U, m), +// I64AtomicStore8u(m) => atomic!(writer, I64_ATOMIC_STORE8U, m), +// I64AtomicStore16u(m) => atomic!(writer, I64_ATOMIC_STORE16U, m), +// I64AtomicStore32u(m) => atomic!(writer, I64_ATOMIC_STORE32U, m), + +// I32AtomicRmwAdd(m) => atomic!(writer, I32_ATOMIC_RMW_ADD, m), +// I64AtomicRmwAdd(m) => atomic!(writer, I64_ATOMIC_RMW_ADD, m), +// I32AtomicRmwAdd8u(m) => atomic!(writer, I32_ATOMIC_RMW_ADD8U, m), +// I32AtomicRmwAdd16u(m) => atomic!(writer, I32_ATOMIC_RMW_ADD16U, m), +// I64AtomicRmwAdd8u(m) => atomic!(writer, I64_ATOMIC_RMW_ADD8U, m), +// I64AtomicRmwAdd16u(m) => atomic!(writer, I64_ATOMIC_RMW_ADD16U, m), +// I64AtomicRmwAdd32u(m) => atomic!(writer, I64_ATOMIC_RMW_ADD32U, m), + +// I32AtomicRmwSub(m) => atomic!(writer, I32_ATOMIC_RMW_SUB, m), +// I64AtomicRmwSub(m) => atomic!(writer, I64_ATOMIC_RMW_SUB, m), +// I32AtomicRmwSub8u(m) => atomic!(writer, I32_ATOMIC_RMW_SUB8U, m), +// I32AtomicRmwSub16u(m) => atomic!(writer, I32_ATOMIC_RMW_SUB16U, m), +// I64AtomicRmwSub8u(m) => atomic!(writer, I64_ATOMIC_RMW_SUB8U, m), +// I64AtomicRmwSub16u(m) => atomic!(writer, I64_ATOMIC_RMW_SUB16U, m), +// I64AtomicRmwSub32u(m) => atomic!(writer, I64_ATOMIC_RMW_SUB32U, m), + +// I32AtomicRmwAnd(m) => atomic!(writer, I32_ATOMIC_RMW_AND, m), +// I64AtomicRmwAnd(m) => atomic!(writer, I64_ATOMIC_RMW_AND, m), +// I32AtomicRmwAnd8u(m) => atomic!(writer, I32_ATOMIC_RMW_AND8U, m), +// I32AtomicRmwAnd16u(m) => atomic!(writer, I32_ATOMIC_RMW_AND16U, m), +// I64AtomicRmwAnd8u(m) => atomic!(writer, I64_ATOMIC_RMW_AND8U, m), +// I64AtomicRmwAnd16u(m) => atomic!(writer, I64_ATOMIC_RMW_AND16U, m), +// I64AtomicRmwAnd32u(m) => atomic!(writer, I64_ATOMIC_RMW_AND32U, m), + +// I32AtomicRmwOr(m) => atomic!(writer, I32_ATOMIC_RMW_OR, m), +// I64AtomicRmwOr(m) => atomic!(writer, I64_ATOMIC_RMW_OR, m), +// I32AtomicRmwOr8u(m) => atomic!(writer, I32_ATOMIC_RMW_OR8U, m), +// I32AtomicRmwOr16u(m) => atomic!(writer, I32_ATOMIC_RMW_OR16U, m), +// I64AtomicRmwOr8u(m) => atomic!(writer, I64_ATOMIC_RMW_OR8U, m), +// I64AtomicRmwOr16u(m) => atomic!(writer, I64_ATOMIC_RMW_OR16U, m), +// I64AtomicRmwOr32u(m) => atomic!(writer, I64_ATOMIC_RMW_OR32U, m), + +// I32AtomicRmwXor(m) => atomic!(writer, I32_ATOMIC_RMW_XOR, m), +// I64AtomicRmwXor(m) => atomic!(writer, I64_ATOMIC_RMW_XOR, m), +// I32AtomicRmwXor8u(m) => atomic!(writer, I32_ATOMIC_RMW_XOR8U, m), +// I32AtomicRmwXor16u(m) => atomic!(writer, I32_ATOMIC_RMW_XOR16U, m), +// I64AtomicRmwXor8u(m) => atomic!(writer, I64_ATOMIC_RMW_XOR8U, m), +// I64AtomicRmwXor16u(m) => atomic!(writer, I64_ATOMIC_RMW_XOR16U, m), +// I64AtomicRmwXor32u(m) => atomic!(writer, I64_ATOMIC_RMW_XOR32U, m), + +// I32AtomicRmwXchg(m) => atomic!(writer, I32_ATOMIC_RMW_XCHG, m), +// I64AtomicRmwXchg(m) => atomic!(writer, I64_ATOMIC_RMW_XCHG, m), +// I32AtomicRmwXchg8u(m) => atomic!(writer, I32_ATOMIC_RMW_XCHG8U, m), +// I32AtomicRmwXchg16u(m) => atomic!(writer, I32_ATOMIC_RMW_XCHG16U, m), +// I64AtomicRmwXchg8u(m) => atomic!(writer, I64_ATOMIC_RMW_XCHG8U, m), +// I64AtomicRmwXchg16u(m) => atomic!(writer, I64_ATOMIC_RMW_XCHG16U, m), +// I64AtomicRmwXchg32u(m) => atomic!(writer, I64_ATOMIC_RMW_XCHG32U, m), + +// I32AtomicRmwCmpxchg(m) => atomic!(writer, I32_ATOMIC_RMW_CMPXCHG, m), +// I64AtomicRmwCmpxchg(m) => atomic!(writer, I64_ATOMIC_RMW_CMPXCHG, m), +// I32AtomicRmwCmpxchg8u(m) => atomic!(writer, I32_ATOMIC_RMW_CMPXCHG8U, m), +// I32AtomicRmwCmpxchg16u(m) => atomic!(writer, I32_ATOMIC_RMW_CMPXCHG16U, m), +// I64AtomicRmwCmpxchg8u(m) => atomic!(writer, I64_ATOMIC_RMW_CMPXCHG8U, m), +// I64AtomicRmwCmpxchg16u(m) => atomic!(writer, I64_ATOMIC_RMW_CMPXCHG16U, m), +// I64AtomicRmwCmpxchg32u(m) => atomic!(writer, I64_ATOMIC_RMW_CMPXCHG32U, m), + +// V128Const(ref c) => simd!(writer, opcodes::V128_CONST, writer.write(&c[..])?), +// V128Load(m) => simd!(writer, opcodes::V128_LOAD, MemArg::serialize(m, writer)?), +// V128Store(m) => simd!(writer, opcodes::V128_STORE, MemArg::serialize(m, writer)?), +// I8x16Splat => simd!(writer, opcodes::I8X16_SPLAT, ()), +// I16x8Splat => simd!(writer, opcodes::I16X8_SPLAT, ()), +// I32x4Splat => simd!(writer, opcodes::I32X4_SPLAT, ()), +// I64x2Splat => simd!(writer, opcodes::I64X2_SPLAT, ()), +// F32x4Splat => simd!(writer, opcodes::F32X4_SPLAT, ()), +// F64x2Splat => simd!(writer, opcodes::F64X2_SPLAT, ()), +// I8x16ExtractLaneS(i) => simd!(writer, opcodes::I8X16_EXTRACT_LANE_S, writer.write(&[i])?), +// I8x16ExtractLaneU(i) => simd!(writer, opcodes::I8X16_EXTRACT_LANE_U, writer.write(&[i])?), +// I16x8ExtractLaneS(i) => simd!(writer, opcodes::I16X8_EXTRACT_LANE_S, writer.write(&[i])?), +// I16x8ExtractLaneU(i) => simd!(writer, opcodes::I16X8_EXTRACT_LANE_U, writer.write(&[i])?), +// I32x4ExtractLane(i) => simd!(writer, opcodes::I32X4_EXTRACT_LANE, writer.write(&[i])?), +// I64x2ExtractLane(i) => simd!(writer, opcodes::I64X2_EXTRACT_LANE, writer.write(&[i])?), +// F32x4ExtractLane(i) => simd!(writer, opcodes::F32X4_EXTRACT_LANE, writer.write(&[i])?), +// F64x2ExtractLane(i) => simd!(writer, opcodes::F64X2_EXTRACT_LANE, writer.write(&[i])?), +// I8x16ReplaceLane(i) => simd!(writer, opcodes::I8X16_REPLACE_LANE, writer.write(&[i])?), +// I16x8ReplaceLane(i) => simd!(writer, opcodes::I16X8_REPLACE_LANE, writer.write(&[i])?), +// I32x4ReplaceLane(i) => simd!(writer, opcodes::I32X4_REPLACE_LANE, writer.write(&[i])?), +// I64x2ReplaceLane(i) => simd!(writer, opcodes::I64X2_REPLACE_LANE, writer.write(&[i])?), +// F32x4ReplaceLane(i) => simd!(writer, opcodes::F32X4_REPLACE_LANE, writer.write(&[i])?), +// F64x2ReplaceLane(i) => simd!(writer, opcodes::F64X2_REPLACE_LANE, writer.write(&[i])?), +// V8x16Shuffle(ref i) => simd!(writer, opcodes::V8X16_SHUFFLE, writer.write(&i[..])?), +// I8x16Add => simd!(writer, opcodes::I8X16_ADD, ()), +// I16x8Add => simd!(writer, opcodes::I16X8_ADD, ()), +// I32x4Add => simd!(writer, opcodes::I32X4_ADD, ()), +// I64x2Add => simd!(writer, opcodes::I64X2_ADD, ()), +// I8x16Sub => simd!(writer, opcodes::I8X16_SUB, ()), +// I16x8Sub => simd!(writer, opcodes::I16X8_SUB, ()), +// I32x4Sub => simd!(writer, opcodes::I32X4_SUB, ()), +// I64x2Sub => simd!(writer, opcodes::I64X2_SUB, ()), +// I8x16Mul => simd!(writer, opcodes::I8X16_MUL, ()), +// I16x8Mul => simd!(writer, opcodes::I16X8_MUL, ()), +// I32x4Mul => simd!(writer, opcodes::I32X4_MUL, ()), +// // I64x2Mul => simd!(writer, opcodes::I64X2_MUL, ()), +// I8x16Neg => simd!(writer, opcodes::I8X16_NEG, ()), +// I16x8Neg => simd!(writer, opcodes::I16X8_NEG, ()), +// I32x4Neg => simd!(writer, opcodes::I32X4_NEG, ()), +// I64x2Neg => simd!(writer, opcodes::I64X2_NEG, ()), +// I8x16AddSaturateS => simd!(writer, opcodes::I8X16_ADD_SATURATE_S, ()), +// I8x16AddSaturateU => simd!(writer, opcodes::I8X16_ADD_SATURATE_U, ()), +// I16x8AddSaturateS => simd!(writer, opcodes::I16X8_ADD_SATURATE_S, ()), +// I16x8AddSaturateU => simd!(writer, opcodes::I16X8_ADD_SATURATE_U, ()), +// I8x16SubSaturateS => simd!(writer, opcodes::I8X16_SUB_SATURATE_S, ()), +// I8x16SubSaturateU => simd!(writer, opcodes::I8X16_SUB_SATURATE_U, ()), +// I16x8SubSaturateS => simd!(writer, opcodes::I16X8_SUB_SATURATE_S, ()), +// I16x8SubSaturateU => simd!(writer, opcodes::I16X8_SUB_SATURATE_U, ()), +// I8x16Shl => simd!(writer, opcodes::I8X16_SHL, ()), +// I16x8Shl => simd!(writer, opcodes::I16X8_SHL, ()), +// I32x4Shl => simd!(writer, opcodes::I32X4_SHL, ()), +// I64x2Shl => simd!(writer, opcodes::I64X2_SHL, ()), +// I8x16ShrS => simd!(writer, opcodes::I8X16_SHR_S, ()), +// I8x16ShrU => simd!(writer, opcodes::I8X16_SHR_U, ()), +// I16x8ShrS => simd!(writer, opcodes::I16X8_SHR_S, ()), +// I16x8ShrU => simd!(writer, opcodes::I16X8_SHR_U, ()), +// I32x4ShrU => simd!(writer, opcodes::I32X4_SHR_U, ()), +// I32x4ShrS => simd!(writer, opcodes::I32X4_SHR_S, ()), +// I64x2ShrU => simd!(writer, opcodes::I64X2_SHR_U, ()), +// I64x2ShrS => simd!(writer, opcodes::I64X2_SHR_S, ()), +// V128And => simd!(writer, opcodes::V128_AND, ()), +// V128Or => simd!(writer, opcodes::V128_OR, ()), +// V128Xor => simd!(writer, opcodes::V128_XOR, ()), +// V128Not => simd!(writer, opcodes::V128_NOT, ()), +// V128Bitselect => simd!(writer, opcodes::V128_BITSELECT, ()), +// I8x16AnyTrue => simd!(writer, opcodes::I8X16_ANY_TRUE, ()), +// I16x8AnyTrue => simd!(writer, opcodes::I16X8_ANY_TRUE, ()), +// I32x4AnyTrue => simd!(writer, opcodes::I32X4_ANY_TRUE, ()), +// I64x2AnyTrue => simd!(writer, opcodes::I64X2_ANY_TRUE, ()), +// I8x16AllTrue => simd!(writer, opcodes::I8X16_ALL_TRUE, ()), +// I16x8AllTrue => simd!(writer, opcodes::I16X8_ALL_TRUE, ()), +// I32x4AllTrue => simd!(writer, opcodes::I32X4_ALL_TRUE, ()), +// I64x2AllTrue => simd!(writer, opcodes::I64X2_ALL_TRUE, ()), +// I8x16Eq => simd!(writer, opcodes::I8X16_EQ, ()), +// I16x8Eq => simd!(writer, opcodes::I16X8_EQ, ()), +// I32x4Eq => simd!(writer, opcodes::I32X4_EQ, ()), +// // I64x2Eq => simd!(writer, opcodes::I64X2_EQ, ()), +// F32x4Eq => simd!(writer, opcodes::F32X4_EQ, ()), +// F64x2Eq => simd!(writer, opcodes::F64X2_EQ, ()), +// I8x16Ne => simd!(writer, opcodes::I8X16_NE, ()), +// I16x8Ne => simd!(writer, opcodes::I16X8_NE, ()), +// I32x4Ne => simd!(writer, opcodes::I32X4_NE, ()), +// // I64x2Ne => simd!(writer, opcodes::I64X2_NE, ()), +// F32x4Ne => simd!(writer, opcodes::F32X4_NE, ()), +// F64x2Ne => simd!(writer, opcodes::F64X2_NE, ()), +// I8x16LtS => simd!(writer, opcodes::I8X16_LT_S, ()), +// I8x16LtU => simd!(writer, opcodes::I8X16_LT_U, ()), +// I16x8LtS => simd!(writer, opcodes::I16X8_LT_S, ()), +// I16x8LtU => simd!(writer, opcodes::I16X8_LT_U, ()), +// I32x4LtS => simd!(writer, opcodes::I32X4_LT_S, ()), +// I32x4LtU => simd!(writer, opcodes::I32X4_LT_U, ()), +// // I64x2LtS => simd!(writer, opcodes::I64X2_LT_S, ()), +// // I64x2LtU => simd!(writer, opcodes::I64X2_LT_U, ()), +// F32x4Lt => simd!(writer, opcodes::F32X4_LT, ()), +// F64x2Lt => simd!(writer, opcodes::F64X2_LT, ()), +// I8x16LeS => simd!(writer, opcodes::I8X16_LE_S, ()), +// I8x16LeU => simd!(writer, opcodes::I8X16_LE_U, ()), +// I16x8LeS => simd!(writer, opcodes::I16X8_LE_S, ()), +// I16x8LeU => simd!(writer, opcodes::I16X8_LE_U, ()), +// I32x4LeS => simd!(writer, opcodes::I32X4_LE_S, ()), +// I32x4LeU => simd!(writer, opcodes::I32X4_LE_U, ()), +// // I64x2LeS => simd!(writer, opcodes::I64X2_LE_S, ()), +// // I64x2LeU => simd!(writer, opcodes::I64X2_LE_U, ()), +// F32x4Le => simd!(writer, opcodes::F32X4_LE, ()), +// F64x2Le => simd!(writer, opcodes::F64X2_LE, ()), +// I8x16GtS => simd!(writer, opcodes::I8X16_GT_S, ()), +// I8x16GtU => simd!(writer, opcodes::I8X16_GT_U, ()), +// I16x8GtS => simd!(writer, opcodes::I16X8_GT_S, ()), +// I16x8GtU => simd!(writer, opcodes::I16X8_GT_U, ()), +// I32x4GtS => simd!(writer, opcodes::I32X4_GT_S, ()), +// I32x4GtU => simd!(writer, opcodes::I32X4_GT_U, ()), +// // I64x2GtS => simd!(writer, opcodes::I64X2_GT_S, ()), +// // I64x2GtU => simd!(writer, opcodes::I64X2_GT_U, ()), +// F32x4Gt => simd!(writer, opcodes::F32X4_GT, ()), +// F64x2Gt => simd!(writer, opcodes::F64X2_GT, ()), +// I8x16GeS => simd!(writer, opcodes::I8X16_GE_S, ()), +// I8x16GeU => simd!(writer, opcodes::I8X16_GE_U, ()), +// I16x8GeS => simd!(writer, opcodes::I16X8_GE_S, ()), +// I16x8GeU => simd!(writer, opcodes::I16X8_GE_U, ()), +// I32x4GeS => simd!(writer, opcodes::I32X4_GE_S, ()), +// I32x4GeU => simd!(writer, opcodes::I32X4_GE_U, ()), +// // I64x2GeS => simd!(writer, opcodes::I64X2_GE_S, ()), +// // I64x2GeU => simd!(writer, opcodes::I64X2_GE_U, ()), +// F32x4Ge => simd!(writer, opcodes::F32X4_GE, ()), +// F64x2Ge => simd!(writer, opcodes::F64X2_GE, ()), +// F32x4Neg => simd!(writer, opcodes::F32X4_NEG, ()), +// F64x2Neg => simd!(writer, opcodes::F64X2_NEG, ()), +// F32x4Abs => simd!(writer, opcodes::F32X4_ABS, ()), +// F64x2Abs => simd!(writer, opcodes::F64X2_ABS, ()), +// F32x4Min => simd!(writer, opcodes::F32X4_MIN, ()), +// F64x2Min => simd!(writer, opcodes::F64X2_MIN, ()), +// F32x4Max => simd!(writer, opcodes::F32X4_MAX, ()), +// F64x2Max => simd!(writer, opcodes::F64X2_MAX, ()), +// F32x4Add => simd!(writer, opcodes::F32X4_ADD, ()), +// F64x2Add => simd!(writer, opcodes::F64X2_ADD, ()), +// F32x4Sub => simd!(writer, opcodes::F32X4_SUB, ()), +// F64x2Sub => simd!(writer, opcodes::F64X2_SUB, ()), +// F32x4Div => simd!(writer, opcodes::F32X4_DIV, ()), +// F64x2Div => simd!(writer, opcodes::F64X2_DIV, ()), +// F32x4Mul => simd!(writer, opcodes::F32X4_MUL, ()), +// F64x2Mul => simd!(writer, opcodes::F64X2_MUL, ()), +// F32x4Sqrt => simd!(writer, opcodes::F32X4_SQRT, ()), +// F64x2Sqrt => simd!(writer, opcodes::F64X2_SQRT, ()), +// F32x4ConvertSI32x4 => simd!(writer, opcodes::F32X4_CONVERT_S_I32X4, ()), +// F32x4ConvertUI32x4 => simd!(writer, opcodes::F32X4_CONVERT_U_I32X4, ()), +// F64x2ConvertSI64x2 => simd!(writer, opcodes::F64X2_CONVERT_S_I64X2, ()), +// F64x2ConvertUI64x2 => simd!(writer, opcodes::F64X2_CONVERT_U_I64X2, ()), +// I32x4TruncSF32x4Sat => simd!(writer, opcodes::I32X4_TRUNC_S_F32X4_SAT, ()), +// I32x4TruncUF32x4Sat => simd!(writer, opcodes::I32X4_TRUNC_U_F32X4_SAT, ()), +// I64x2TruncSF64x2Sat => simd!(writer, opcodes::I64X2_TRUNC_S_F64X2_SAT, ()), +// I64x2TruncUF64x2Sat => simd!(writer, opcodes::I64X2_TRUNC_U_F64X2_SAT, ()), + +// MemoryInit(seg) => bulk!(writer, MEMORY_INIT, { +// Uint8::from(0).serialize(writer)?; +// VarUint32::from(seg).serialize(writer)?; +// }), +// MemoryDrop(seg) => bulk!(writer, MEMORY_DROP, VarUint32::from(seg).serialize(writer)?), +// MemoryFill => bulk!(writer, MEMORY_FILL, Uint8::from(0).serialize(writer)?), +// MemoryCopy => bulk!(writer, MEMORY_COPY, Uint8::from(0).serialize(writer)?), +// TableInit(seg) => bulk!(writer, TABLE_INIT, { +// Uint8::from(0).serialize(writer)?; +// VarUint32::from(seg).serialize(writer)?; +// }), +// TableDrop(seg) => bulk!(writer, TABLE_DROP, VarUint32::from(seg).serialize(writer)?), +// TableCopy => bulk!(writer, TABLE_COPY, Uint8::from(0).serialize(writer)?), +// } + +// Ok(()) +// } +// } + +impl Serialize for MemArg { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + Uint8::from(self.align).serialize(writer)?; + VarUint32::from(self.offset).serialize(writer)?; + Ok(()) + } +} + +// macro_rules! fmt_op { +// ($f: expr, $mnemonic: expr) => ({ +// write!($f, "{}", $mnemonic) +// }); +// ($f: expr, $mnemonic: expr, $immediate: expr) => ({ +// write!($f, "{} {}", $mnemonic, $immediate) +// }); +// ($f: expr, $mnemonic: expr, $immediate1: expr, $immediate2: expr) => ({ +// write!($f, "{} {} {}", $mnemonic, $immediate1, $immediate2) +// }); +// } + +// impl fmt::Display for Instruction { +// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +// use self::Instruction::*; +// use super::BlockType; + +// match *self { +// Unreachable => fmt_op!(f, "unreachable"), +// Nop => fmt_op!(f, "nop"), +// Block(BlockType::NoResult) => fmt_op!(f, "block"), +// Block(BlockType::Value(value_type)) => fmt_op!(f, "block", value_type), +// Loop(BlockType::NoResult) => fmt_op!(f, "loop"), +// Loop(BlockType::Value(value_type)) => fmt_op!(f, "loop", value_type), +// If(BlockType::NoResult) => fmt_op!(f, "if"), +// If(BlockType::Value(value_type)) => fmt_op!(f, "if", value_type), +// Else => fmt_op!(f, "else"), +// End => fmt_op!(f, "end"), +// Br(idx) => fmt_op!(f, "br", idx), +// BrIf(idx) => fmt_op!(f, "br_if", idx), +// BrTable(ref table) => fmt_op!(f, "br_table", table.default), +// Return => fmt_op!(f, "return"), +// Call(index) => fmt_op!(f, "call", index), +// CallIndirect(index, _) => fmt_op!(f, "call_indirect", index), +// Drop => fmt_op!(f, "drop"), +// Select => fmt_op!(f, "select"), +// GetLocal(index) => fmt_op!(f, "get_local", index), +// SetLocal(index) => fmt_op!(f, "set_local", index), +// TeeLocal(index) => fmt_op!(f, "tee_local", index), +// GetGlobal(index) => fmt_op!(f, "get_global", index), +// SetGlobal(index) => fmt_op!(f, "set_global", index), + +// I32Load(_, 0) => write!(f, "i32.load"), +// I32Load(_, offset) => write!(f, "i32.load offset={}", offset), + +// I64Load(_, 0) => write!(f, "i64.load"), +// I64Load(_, offset) => write!(f, "i64.load offset={}", offset), + +// F32Load(_, 0) => write!(f, "f32.load"), +// F32Load(_, offset) => write!(f, "f32.load offset={}", offset), + +// F64Load(_, 0) => write!(f, "f64.load"), +// F64Load(_, offset) => write!(f, "f64.load offset={}", offset), + +// I32Load8S(_, 0) => write!(f, "i32.load8_s"), +// I32Load8S(_, offset) => write!(f, "i32.load8_s offset={}", offset), + +// I32Load8U(_, 0) => write!(f, "i32.load8_u"), +// I32Load8U(_, offset) => write!(f, "i32.load8_u offset={}", offset), + +// I32Load16S(_, 0) => write!(f, "i32.load16_s"), +// I32Load16S(_, offset) => write!(f, "i32.load16_s offset={}", offset), + +// I32Load16U(_, 0) => write!(f, "i32.load16_u"), +// I32Load16U(_, offset) => write!(f, "i32.load16_u offset={}", offset), + +// I64Load8S(_, 0) => write!(f, "i64.load8_s"), +// I64Load8S(_, offset) => write!(f, "i64.load8_s offset={}", offset), + +// I64Load8U(_, 0) => write!(f, "i64.load8_u"), +// I64Load8U(_, offset) => write!(f, "i64.load8_u offset={}", offset), + +// I64Load16S(_, 0) => write!(f, "i64.load16_s"), +// I64Load16S(_, offset) => write!(f, "i64.load16_s offset={}", offset), + +// I64Load16U(_, 0) => write!(f, "i64.load16_u"), +// I64Load16U(_, offset) => write!(f, "i64.load16_u offset={}", offset), + +// I64Load32S(_, 0) => write!(f, "i64.load32_s"), +// I64Load32S(_, offset) => write!(f, "i64.load32_s offset={}", offset), + +// I64Load32U(_, 0) => write!(f, "i64.load32_u"), +// I64Load32U(_, offset) => write!(f, "i64.load32_u offset={}", offset), + +// I32Store(_, 0) => write!(f, "i32.store"), +// I32Store(_, offset) => write!(f, "i32.store offset={}", offset), + +// I64Store(_, 0) => write!(f, "i64.store"), +// I64Store(_, offset) => write!(f, "i64.store offset={}", offset), + +// F32Store(_, 0) => write!(f, "f32.store"), +// F32Store(_, offset) => write!(f, "f32.store offset={}", offset), + +// F64Store(_, 0) => write!(f, "f64.store"), +// F64Store(_, offset) => write!(f, "f64.store offset={}", offset), + +// I32Store8(_, 0) => write!(f, "i32.store8"), +// I32Store8(_, offset) => write!(f, "i32.store8 offset={}", offset), + +// I32Store16(_, 0) => write!(f, "i32.store16"), +// I32Store16(_, offset) => write!(f, "i32.store16 offset={}", offset), + +// I64Store8(_, 0) => write!(f, "i64.store8"), +// I64Store8(_, offset) => write!(f, "i64.store8 offset={}", offset), + +// I64Store16(_, 0) => write!(f, "i64.store16"), +// I64Store16(_, offset) => write!(f, "i64.store16 offset={}", offset), + +// I64Store32(_, 0) => write!(f, "i64.store32"), +// I64Store32(_, offset) => write!(f, "i64.store32 offset={}", offset), + +// CurrentMemory(_) => fmt_op!(f, "current_memory"), +// GrowMemory(_) => fmt_op!(f, "grow_memory"), + +// I32Const(def) => fmt_op!(f, "i32.const", def), +// I64Const(def) => fmt_op!(f, "i64.const", def), +// F32Const(def) => fmt_op!(f, "f32.const", def), +// F64Const(def) => fmt_op!(f, "f64.const", def), + +// I32Eq => write!(f, "i32.eq"), +// I32Eqz => write!(f, "i32.eqz"), +// I32Ne => write!(f, "i32.ne"), +// I32LtS => write!(f, "i32.lt_s"), +// I32LtU => write!(f, "i32.lt_u"), +// I32GtS => write!(f, "i32.gt_s"), +// I32GtU => write!(f, "i32.gt_u"), +// I32LeS => write!(f, "i32.le_s"), +// I32LeU => write!(f, "i32.le_u"), +// I32GeS => write!(f, "i32.ge_s"), +// I32GeU => write!(f, "i32.ge_u"), + +// I64Eq => write!(f, "i64.eq"), +// I64Eqz => write!(f, "i64.eqz"), +// I64Ne => write!(f, "i64.ne"), +// I64LtS => write!(f, "i64.lt_s"), +// I64LtU => write!(f, "i64.lt_u"), +// I64GtS => write!(f, "i64.gt_s"), +// I64GtU => write!(f, "i64.gt_u"), +// I64LeS => write!(f, "i64.le_s"), +// I64LeU => write!(f, "i64.le_u"), +// I64GeS => write!(f, "i64.ge_s"), +// I64GeU => write!(f, "i64.ge_u"), + +// F32Eq => write!(f, "f32.eq"), +// F32Ne => write!(f, "f32.ne"), +// F32Lt => write!(f, "f32.lt"), +// F32Gt => write!(f, "f32.gt"), +// F32Le => write!(f, "f32.le"), +// F32Ge => write!(f, "f32.ge"), + +// F64Eq => write!(f, "f64.eq"), +// F64Ne => write!(f, "f64.ne"), +// F64Lt => write!(f, "f64.lt"), +// F64Gt => write!(f, "f64.gt"), +// F64Le => write!(f, "f64.le"), +// F64Ge => write!(f, "f64.ge"), + +// I32Clz => write!(f, "i32.clz"), +// I32Ctz => write!(f, "i32.ctz"), +// I32Popcnt => write!(f, "i32.popcnt"), +// I32Add => write!(f, "i32.add"), +// I32Sub => write!(f, "i32.sub"), +// I32Mul => write!(f, "i32.mul"), +// I32DivS => write!(f, "i32.div_s"), +// I32DivU => write!(f, "i32.div_u"), +// I32RemS => write!(f, "i32.rem_s"), +// I32RemU => write!(f, "i32.rem_u"), +// I32And => write!(f, "i32.and"), +// I32Or => write!(f, "i32.or"), +// I32Xor => write!(f, "i32.xor"), +// I32Shl => write!(f, "i32.shl"), +// I32ShrS => write!(f, "i32.shr_s"), +// I32ShrU => write!(f, "i32.shr_u"), +// I32Rotl => write!(f, "i32.rotl"), +// I32Rotr => write!(f, "i32.rotr"), + +// I64Clz => write!(f, "i64.clz"), +// I64Ctz => write!(f, "i64.ctz"), +// I64Popcnt => write!(f, "i64.popcnt"), +// I64Add => write!(f, "i64.add"), +// I64Sub => write!(f, "i64.sub"), +// I64Mul => write!(f, "i64.mul"), +// I64DivS => write!(f, "i64.div_s"), +// I64DivU => write!(f, "i64.div_u"), +// I64RemS => write!(f, "i64.rem_s"), +// I64RemU => write!(f, "i64.rem_u"), +// I64And => write!(f, "i64.and"), +// I64Or => write!(f, "i64.or"), +// I64Xor => write!(f, "i64.xor"), +// I64Shl => write!(f, "i64.shl"), +// I64ShrS => write!(f, "i64.shr_s"), +// I64ShrU => write!(f, "i64.shr_u"), +// I64Rotl => write!(f, "i64.rotl"), +// I64Rotr => write!(f, "i64.rotr"), + +// F32Abs => write!(f, "f32.abs"), +// F32Neg => write!(f, "f32.neg"), +// F32Ceil => write!(f, "f32.ceil"), +// F32Floor => write!(f, "f32.floor"), +// F32Trunc => write!(f, "f32.trunc"), +// F32Nearest => write!(f, "f32.nearest"), +// F32Sqrt => write!(f, "f32.sqrt"), +// F32Add => write!(f, "f32.add"), +// F32Sub => write!(f, "f32.sub"), +// F32Mul => write!(f, "f32.mul"), +// F32Div => write!(f, "f32.div"), +// F32Min => write!(f, "f32.min"), +// F32Max => write!(f, "f32.max"), +// F32Copysign => write!(f, "f32.copysign"), + +// F64Abs => write!(f, "f64.abs"), +// F64Neg => write!(f, "f64.neg"), +// F64Ceil => write!(f, "f64.ceil"), +// F64Floor => write!(f, "f64.floor"), +// F64Trunc => write!(f, "f64.trunc"), +// F64Nearest => write!(f, "f64.nearest"), +// F64Sqrt => write!(f, "f64.sqrt"), +// F64Add => write!(f, "f64.add"), +// F64Sub => write!(f, "f64.sub"), +// F64Mul => write!(f, "f64.mul"), +// F64Div => write!(f, "f64.div"), +// F64Min => write!(f, "f64.min"), +// F64Max => write!(f, "f64.max"), +// F64Copysign => write!(f, "f64.copysign"), + +// I32WrapI64 => write!(f, "i32.wrap/i64"), +// I32TruncSF32 => write!(f, "i32.trunc_s/f32"), +// I32TruncUF32 => write!(f, "i32.trunc_u/f32"), +// I32TruncSF64 => write!(f, "i32.trunc_s/f64"), +// I32TruncUF64 => write!(f, "i32.trunc_u/f64"), + +// I64ExtendSI32 => write!(f, "i64.extend_s/i32"), +// I64ExtendUI32 => write!(f, "i64.extend_u/i32"), + +// I64TruncSF32 => write!(f, "i64.trunc_s/f32"), +// I64TruncUF32 => write!(f, "i64.trunc_u/f32"), +// I64TruncSF64 => write!(f, "i64.trunc_s/f64"), +// I64TruncUF64 => write!(f, "i64.trunc_u/f64"), + +// F32ConvertSI32 => write!(f, "f32.convert_s/i32"), +// F32ConvertUI32 => write!(f, "f32.convert_u/i32"), +// F32ConvertSI64 => write!(f, "f32.convert_s/i64"), +// F32ConvertUI64 => write!(f, "f32.convert_u/i64"), +// F32DemoteF64 => write!(f, "f32.demote/f64"), + +// F64ConvertSI32 => write!(f, "f64.convert_s/i32"), +// F64ConvertUI32 => write!(f, "f64.convert_u/i32"), +// F64ConvertSI64 => write!(f, "f64.convert_s/i64"), +// F64ConvertUI64 => write!(f, "f64.convert_u/i64"), +// F64PromoteF32 => write!(f, "f64.promote/f32"), + +// I32ReinterpretF32 => write!(f, "i32.reinterpret/f32"), +// I64ReinterpretF64 => write!(f, "i64.reinterpret/f64"), +// F32ReinterpretI32 => write!(f, "f32.reinterpret/i32"), +// F64ReinterpretI64 => write!(f, "f64.reinterpret/i64"), + +// I32Extend8S => write!(f, "i32.extend8_s"), +// I32Extend16S => write!(f, "i32.extend16_s"), +// I64Extend8S => write!(f, "i64.extend8_s"), +// I64Extend16S => write!(f, "i64.extend16_s"), +// I64Extend32S => write!(f, "i64.extend32_s"), + +// AtomicWake(_) => write!(f, "atomic.wake"), +// I32AtomicWait(_) => write!(f, "i32.atomic.wait"), +// I64AtomicWait(_) => write!(f, "i64.atomic.wait"), + +// I32AtomicLoad(_) => write!(f, "i32.atomic.load"), +// I64AtomicLoad(_) => write!(f, "i64.atomic.load"), +// I32AtomicLoad8u(_) => write!(f, "i32.atomic.load8_u"), +// I32AtomicLoad16u(_) => write!(f, "i32.atomic.load16_u"), +// I64AtomicLoad8u(_) => write!(f, "i64.atomic.load8_u"), +// I64AtomicLoad16u(_) => write!(f, "i64.atomic.load16_u"), +// I64AtomicLoad32u(_) => write!(f, "i64.atomic.load32_u"), +// I32AtomicStore(_) => write!(f, "i32.atomic.store"), +// I64AtomicStore(_) => write!(f, "i64.atomic.store"), +// I32AtomicStore8u(_) => write!(f, "i32.atomic.store8_u"), +// I32AtomicStore16u(_) => write!(f, "i32.atomic.store16_u"), +// I64AtomicStore8u(_) => write!(f, "i64.atomic.store8_u"), +// I64AtomicStore16u(_) => write!(f, "i64.atomic.store16_u"), +// I64AtomicStore32u(_) => write!(f, "i64.atomic.store32_u"), + +// I32AtomicRmwAdd(_) => write!(f, "i32.atomic.rmw.add"), +// I64AtomicRmwAdd(_) => write!(f, "i64.atomic.rmw.add"), +// I32AtomicRmwAdd8u(_) => write!(f, "i32.atomic.rmw8_u.add"), +// I32AtomicRmwAdd16u(_) => write!(f, "i32.atomic.rmw16_u.add"), +// I64AtomicRmwAdd8u(_) => write!(f, "i64.atomic.rmw8_u.add"), +// I64AtomicRmwAdd16u(_) => write!(f, "i64.atomic.rmw16_u.add"), +// I64AtomicRmwAdd32u(_) => write!(f, "i64.atomic.rmw32_u.add"), + +// I32AtomicRmwSub(_) => write!(f, "i32.atomic.rmw.sub"), +// I64AtomicRmwSub(_) => write!(f, "i64.atomic.rmw.sub"), +// I32AtomicRmwSub8u(_) => write!(f, "i32.atomic.rmw8_u.sub"), +// I32AtomicRmwSub16u(_) => write!(f, "i32.atomic.rmw16_u.sub"), +// I64AtomicRmwSub8u(_) => write!(f, "i64.atomic.rmw8_u.sub"), +// I64AtomicRmwSub16u(_) => write!(f, "i64.atomic.rmw16_u.sub"), +// I64AtomicRmwSub32u(_) => write!(f, "i64.atomic.rmw32_u.sub"), + +// I32AtomicRmwAnd(_) => write!(f, "i32.atomic.rmw.and"), +// I64AtomicRmwAnd(_) => write!(f, "i64.atomic.rmw.and"), +// I32AtomicRmwAnd8u(_) => write!(f, "i32.atomic.rmw8_u.and"), +// I32AtomicRmwAnd16u(_) => write!(f, "i32.atomic.rmw16_u.and"), +// I64AtomicRmwAnd8u(_) => write!(f, "i64.atomic.rmw8_u.and"), +// I64AtomicRmwAnd16u(_) => write!(f, "i64.atomic.rmw16_u.and"), +// I64AtomicRmwAnd32u(_) => write!(f, "i64.atomic.rmw32_u.and"), + +// I32AtomicRmwOr(_) => write!(f, "i32.atomic.rmw.or"), +// I64AtomicRmwOr(_) => write!(f, "i64.atomic.rmw.or"), +// I32AtomicRmwOr8u(_) => write!(f, "i32.atomic.rmw8_u.or"), +// I32AtomicRmwOr16u(_) => write!(f, "i32.atomic.rmw16_u.or"), +// I64AtomicRmwOr8u(_) => write!(f, "i64.atomic.rmw8_u.or"), +// I64AtomicRmwOr16u(_) => write!(f, "i64.atomic.rmw16_u.or"), +// I64AtomicRmwOr32u(_) => write!(f, "i64.atomic.rmw32_u.or"), + +// I32AtomicRmwXor(_) => write!(f, "i32.atomic.rmw.xor"), +// I64AtomicRmwXor(_) => write!(f, "i64.atomic.rmw.xor"), +// I32AtomicRmwXor8u(_) => write!(f, "i32.atomic.rmw8_u.xor"), +// I32AtomicRmwXor16u(_) => write!(f, "i32.atomic.rmw16_u.xor"), +// I64AtomicRmwXor8u(_) => write!(f, "i64.atomic.rmw8_u.xor"), +// I64AtomicRmwXor16u(_) => write!(f, "i64.atomic.rmw16_u.xor"), +// I64AtomicRmwXor32u(_) => write!(f, "i64.atomic.rmw32_u.xor"), + +// I32AtomicRmwXchg(_) => write!(f, "i32.atomic.rmw.xchg"), +// I64AtomicRmwXchg(_) => write!(f, "i64.atomic.rmw.xchg"), +// I32AtomicRmwXchg8u(_) => write!(f, "i32.atomic.rmw8_u.xchg"), +// I32AtomicRmwXchg16u(_) => write!(f, "i32.atomic.rmw16_u.xchg"), +// I64AtomicRmwXchg8u(_) => write!(f, "i64.atomic.rmw8_u.xchg"), +// I64AtomicRmwXchg16u(_) => write!(f, "i64.atomic.rmw16_u.xchg"), +// I64AtomicRmwXchg32u(_) => write!(f, "i64.atomic.rmw32_u.xchg"), + +// I32AtomicRmwCmpxchg(_) => write!(f, "i32.atomic.rmw.cmpxchg"), +// I64AtomicRmwCmpxchg(_) => write!(f, "i64.atomic.rmw.cmpxchg"), +// I32AtomicRmwCmpxchg8u(_) => write!(f, "i32.atomic.rmw8_u.cmpxchg"), +// I32AtomicRmwCmpxchg16u(_) => write!(f, "i32.atomic.rmw16_u.cmpxchg"), +// I64AtomicRmwCmpxchg8u(_) => write!(f, "i64.atomic.rmw8_u.cmpxchg"), +// I64AtomicRmwCmpxchg16u(_) => write!(f, "i64.atomic.rmw16_u.cmpxchg"), +// I64AtomicRmwCmpxchg32u(_) => write!(f, "i64.atomic.rmw32_u.cmpxchg"), + +// V128Const(_) => write!(f, "v128.const"), +// V128Load(_) => write!(f, "v128.load"), +// V128Store(_) => write!(f, "v128.store"), +// I8x16Splat => write!(f, "i8x16.splat"), +// I16x8Splat => write!(f, "i16x8.splat"), +// I32x4Splat => write!(f, "i32x4.splat"), +// I64x2Splat => write!(f, "i64x2.splat"), +// F32x4Splat => write!(f, "f32x4.splat"), +// F64x2Splat => write!(f, "f64x2.splat"), +// I8x16ExtractLaneS(_) => write!(f, "i8x16.extract_lane_s"), +// I8x16ExtractLaneU(_) => write!(f, "i8x16.extract_lane_u"), +// I16x8ExtractLaneS(_) => write!(f, "i16x8.extract_lane_s"), +// I16x8ExtractLaneU(_) => write!(f, "i16x8.extract_lane_u"), +// I32x4ExtractLane(_) => write!(f, "i32x4.extract_lane"), +// I64x2ExtractLane(_) => write!(f, "i64x2.extract_lane"), +// F32x4ExtractLane(_) => write!(f, "f32x4.extract_lane"), +// F64x2ExtractLane(_) => write!(f, "f64x2.extract_lane"), +// I8x16ReplaceLane(_) => write!(f, "i8x16.replace_lane"), +// I16x8ReplaceLane(_) => write!(f, "i16x8.replace_lane"), +// I32x4ReplaceLane(_) => write!(f, "i32x4.replace_lane"), +// I64x2ReplaceLane(_) => write!(f, "i64x2.replace_lane"), +// F32x4ReplaceLane(_) => write!(f, "f32x4.replace_lane"), +// F64x2ReplaceLane(_) => write!(f, "f64x2.replace_lane"), +// V8x16Shuffle(_) => write!(f, "v8x16.shuffle"), +// I8x16Add => write!(f, "i8x16.add"), +// I16x8Add => write!(f, "i16x8.add"), +// I32x4Add => write!(f, "i32x4.add"), +// I64x2Add => write!(f, "i64x2.add"), +// I8x16Sub => write!(f, "i8x16.sub"), +// I16x8Sub => write!(f, "i16x8.sub"), +// I32x4Sub => write!(f, "i32x4.sub"), +// I64x2Sub => write!(f, "i64x2.sub"), +// I8x16Mul => write!(f, "i8x16.mul"), +// I16x8Mul => write!(f, "i16x8.mul"), +// I32x4Mul => write!(f, "i32x4.mul"), +// // I64x2Mul => write!(f, "i64x2.mul"), +// I8x16Neg => write!(f, "i8x16.neg"), +// I16x8Neg => write!(f, "i16x8.neg"), +// I32x4Neg => write!(f, "i32x4.neg"), +// I64x2Neg => write!(f, "i64x2.neg"), +// I8x16AddSaturateS => write!(f, "i8x16.add_saturate_s"), +// I8x16AddSaturateU => write!(f, "i8x16.add_saturate_u"), +// I16x8AddSaturateS => write!(f, "i16x8.add_saturate_S"), +// I16x8AddSaturateU => write!(f, "i16x8.add_saturate_u"), +// I8x16SubSaturateS => write!(f, "i8x16.sub_saturate_S"), +// I8x16SubSaturateU => write!(f, "i8x16.sub_saturate_u"), +// I16x8SubSaturateS => write!(f, "i16x8.sub_saturate_S"), +// I16x8SubSaturateU => write!(f, "i16x8.sub_saturate_u"), +// I8x16Shl => write!(f, "i8x16.shl"), +// I16x8Shl => write!(f, "i16x8.shl"), +// I32x4Shl => write!(f, "i32x4.shl"), +// I64x2Shl => write!(f, "i64x2.shl"), +// I8x16ShrS => write!(f, "i8x16.shr_s"), +// I8x16ShrU => write!(f, "i8x16.shr_u"), +// I16x8ShrS => write!(f, "i16x8.shr_s"), +// I16x8ShrU => write!(f, "i16x8.shr_u"), +// I32x4ShrS => write!(f, "i32x4.shr_s"), +// I32x4ShrU => write!(f, "i32x4.shr_u"), +// I64x2ShrS => write!(f, "i64x2.shr_s"), +// I64x2ShrU => write!(f, "i64x2.shr_u"), +// V128And => write!(f, "v128.and"), +// V128Or => write!(f, "v128.or"), +// V128Xor => write!(f, "v128.xor"), +// V128Not => write!(f, "v128.not"), +// V128Bitselect => write!(f, "v128.bitselect"), +// I8x16AnyTrue => write!(f, "i8x16.any_true"), +// I16x8AnyTrue => write!(f, "i16x8.any_true"), +// I32x4AnyTrue => write!(f, "i32x4.any_true"), +// I64x2AnyTrue => write!(f, "i64x2.any_true"), +// I8x16AllTrue => write!(f, "i8x16.all_true"), +// I16x8AllTrue => write!(f, "i16x8.all_true"), +// I32x4AllTrue => write!(f, "i32x4.all_true"), +// I64x2AllTrue => write!(f, "i64x2.all_true"), +// I8x16Eq => write!(f, "i8x16.eq"), +// I16x8Eq => write!(f, "i16x8.eq"), +// I32x4Eq => write!(f, "i32x4.eq"), +// // I64x2Eq => write!(f, "i64x2.eq"), +// F32x4Eq => write!(f, "f32x4.eq"), +// F64x2Eq => write!(f, "f64x2.eq"), +// I8x16Ne => write!(f, "i8x16.ne"), +// I16x8Ne => write!(f, "i16x8.ne"), +// I32x4Ne => write!(f, "i32x4.ne"), +// // I64x2Ne => write!(f, "i64x2.ne"), +// F32x4Ne => write!(f, "f32x4.ne"), +// F64x2Ne => write!(f, "f64x2.ne"), +// I8x16LtS => write!(f, "i8x16.lt_s"), +// I8x16LtU => write!(f, "i8x16.lt_u"), +// I16x8LtS => write!(f, "i16x8.lt_s"), +// I16x8LtU => write!(f, "i16x8.lt_u"), +// I32x4LtS => write!(f, "i32x4.lt_s"), +// I32x4LtU => write!(f, "i32x4.lt_u"), +// // I64x2LtS => write!(f, "// I64x2.lt_s"), +// // I64x2LtU => write!(f, "// I64x2.lt_u"), +// F32x4Lt => write!(f, "f32x4.lt"), +// F64x2Lt => write!(f, "f64x2.lt"), +// I8x16LeS => write!(f, "i8x16.le_s"), +// I8x16LeU => write!(f, "i8x16.le_u"), +// I16x8LeS => write!(f, "i16x8.le_s"), +// I16x8LeU => write!(f, "i16x8.le_u"), +// I32x4LeS => write!(f, "i32x4.le_s"), +// I32x4LeU => write!(f, "i32x4.le_u"), +// // I64x2LeS => write!(f, "// I64x2.le_s"), +// // I64x2LeU => write!(f, "// I64x2.le_u"), +// F32x4Le => write!(f, "f32x4.le"), +// F64x2Le => write!(f, "f64x2.le"), +// I8x16GtS => write!(f, "i8x16.gt_s"), +// I8x16GtU => write!(f, "i8x16.gt_u"), +// I16x8GtS => write!(f, "i16x8.gt_s"), +// I16x8GtU => write!(f, "i16x8.gt_u"), +// I32x4GtS => write!(f, "i32x4.gt_s"), +// I32x4GtU => write!(f, "i32x4.gt_u"), +// // I64x2GtS => write!(f, "// I64x2.gt_s"), +// // I64x2GtU => write!(f, "// I64x2.gt_u"), +// F32x4Gt => write!(f, "f32x4.gt"), +// F64x2Gt => write!(f, "f64x2.gt"), +// I8x16GeS => write!(f, "i8x16.ge_s"), +// I8x16GeU => write!(f, "i8x16.ge_u"), +// I16x8GeS => write!(f, "i16x8.ge_s"), +// I16x8GeU => write!(f, "i16x8.ge_u"), +// I32x4GeS => write!(f, "i32x4.ge_s"), +// I32x4GeU => write!(f, "i32x4.ge_u"), +// // I64x2GeS => write!(f, "// I64x2.ge_s"), +// // I64x2GeU => write!(f, "// I64x2.ge_u"), +// F32x4Ge => write!(f, "f32x4.ge"), +// F64x2Ge => write!(f, "f64x2.ge"), +// F32x4Neg => write!(f, "f32x4.neg"), +// F64x2Neg => write!(f, "f64x2.neg"), +// F32x4Abs => write!(f, "f32x4.abs"), +// F64x2Abs => write!(f, "f64x2.abs"), +// F32x4Min => write!(f, "f32x4.min"), +// F64x2Min => write!(f, "f64x2.min"), +// F32x4Max => write!(f, "f32x4.max"), +// F64x2Max => write!(f, "f64x2.max"), +// F32x4Add => write!(f, "f32x4.add"), +// F64x2Add => write!(f, "f64x2.add"), +// F32x4Sub => write!(f, "f32x4.sub"), +// F64x2Sub => write!(f, "f64x2.sub"), +// F32x4Div => write!(f, "f32x4.div"), +// F64x2Div => write!(f, "f64x2.div"), +// F32x4Mul => write!(f, "f32x4.mul"), +// F64x2Mul => write!(f, "f64x2.mul"), +// F32x4Sqrt => write!(f, "f32x4.sqrt"), +// F64x2Sqrt => write!(f, "f64x2.sqrt"), +// F32x4ConvertSI32x4 => write!(f, "f32x4.convert_s/i32x4"), +// F32x4ConvertUI32x4 => write!(f, "f32x4.convert_u/i32x4"), +// F64x2ConvertSI64x2 => write!(f, "f64x2.convert_s/i64x2"), +// F64x2ConvertUI64x2 => write!(f, "f64x2.convert_u/i64x2"), +// I32x4TruncSF32x4Sat => write!(f, "i32x4.trunc_s/f32x4:sat"), +// I32x4TruncUF32x4Sat => write!(f, "i32x4.trunc_u/f32x4:sat"), +// I64x2TruncSF64x2Sat => write!(f, "i64x2.trunc_s/f64x2:sat"), +// I64x2TruncUF64x2Sat => write!(f, "i64x2.trunc_u/f64x2:sat"), + +// MemoryInit(_) => write!(f, "memory.init"), +// MemoryDrop(_) => write!(f, "memory.drop"), +// MemoryFill => write!(f, "memory.fill"), +// MemoryCopy => write!(f, "memory.copy"), +// TableInit(_) => write!(f, "table.init"), +// TableDrop(_) => write!(f, "table.drop"), +// TableCopy => write!(f, "table.copy"), +// } +// } +// } + +// impl Serialize for Instructions { +// type Error = Error; + +// fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { +// for op in self.0.into_iter() { +// op.serialize(writer)?; +// } + +// Ok(()) +// } +// } + +// impl Serialize for InitExpr { +// type Error = Error; + +// fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { +// for op in self.0.into_iter() { +// op.serialize(writer)?; +// } + +// Ok(()) +// } +// } + +// #[test] +// fn ifelse() { +// // see if-else.wast/if-else.wasm +// let instruction_list = super::deserialize_buffer::(&[0x04, 0x7F, 0x41, 0x05, 0x05, 0x41, 0x07, 0x0B, 0x0B]) +// .expect("valid hex of if instruction"); +// let instructions = instruction_list.elements(); +// match &instructions[0] { +// &Instruction::If(_) => (), +// _ => panic!("Should be deserialized as if instruction"), +// } +// let before_else = instructions.iter().skip(1) +// .take_while(|op| match **op { Instruction::Else => false, _ => true }).count(); +// let after_else = instructions.iter().skip(1) +// .skip_while(|op| match **op { Instruction::Else => false, _ => true }) +// .take_while(|op| match **op { Instruction::End => false, _ => true }) +// .count() +// - 1; // minus Instruction::Else itself +// assert_eq!(before_else, after_else); +// } + +// #[test] +// fn display() { +// let instruction = Instruction::GetLocal(0); +// assert_eq!("get_local 0", format!("{}", instruction)); + +// let instruction = Instruction::F64Store(0, 24); +// assert_eq!("f64.store offset=24", format!("{}", instruction)); + +// let instruction = Instruction::I64Store(0, 0); +// assert_eq!("i64.store", format!("{}", instruction)); +// } + +// #[test] +// fn size_off() { +// assert!(::std::mem::size_of::() <= 24); +// } + +// #[test] +// fn instructions_hashset() { +// use self::Instruction::{Call, Block, Drop}; +// use super::types::{BlockType::Value, ValueType}; + +// let set: std::collections::HashSet = +// vec![Call(1), Block(Value(ValueType::I32)), Drop].into_iter().collect(); +// assert_eq!(set.contains(&Drop), true) +// } diff --git a/kernel-ewasm/validator/src/io.rs b/kernel-ewasm/validator/src/io.rs new file mode 100644 index 0000000..1c13cbd --- /dev/null +++ b/kernel-ewasm/validator/src/io.rs @@ -0,0 +1,127 @@ +//! Simple abstractions for the IO operations. +//! +//! Basically it just a replacement for the std::io that is usable from +//! the `no_std` environment. + +// use crate::rust::result; + +// #[cfg(feature="std")] +use std::io; + +// #[cfg(not(feature="std"))] +// use crate::rust::vec::Vec; + +/// IO specific error. +#[derive(Debug)] +pub enum Error { + /// Some unexpected data left in the buffer after reading all data. + TrailingData, + + /// Unexpected End-Of-File + UnexpectedEof, + + /// Invalid data is encountered. + InvalidData, + + #[cfg(feature = "std")] + IoError(io::Error), +} + +/// IO specific Result. +pub type Result = std::result::Result; + +pub trait Write { + /// Write a buffer of data into this write. + /// + /// All data is written at once. + fn write(&mut self, buf: &[u8]) -> Result<()>; +} + +pub trait Read { + /// Read a data from this read to a buffer. + /// + /// If there is not enough data in this read then `UnexpectedEof` will be returned. + fn read(&mut self, buf: &mut [u8]) -> Result<()>; +} + +/// Reader that saves the last position. +pub struct Cursor { + inner: T, + pos: usize, +} + +impl Cursor { + pub fn new(inner: T) -> Cursor { + Cursor { + inner, + pos: 0, + } + } + + pub fn position(&self) -> usize { + self.pos + } +} + +impl> Read for Cursor { + fn read(&mut self, buf: &mut [u8]) -> Result<()> { + let slice = self.inner.as_ref(); + let remainder = slice.len() - self.pos; + let requested = buf.len(); + if requested > remainder { + return Err(Error::UnexpectedEof); + } + buf.copy_from_slice(&slice[self.pos..(self.pos + requested)]); + self.pos += requested; + Ok(()) + } +} + +#[cfg(not(feature = "std"))] +impl Write for Vec { + fn write(&mut self, buf: &[u8]) -> Result<()> { + self.extend(buf); + Ok(()) + } +} + +#[cfg(feature = "std")] +impl Read for T { + fn read(&mut self, buf: &mut [u8]) -> Result<()> { + self.read_exact(buf) + .map_err(Error::IoError) + } +} + +#[cfg(feature = "std")] +impl Write for T { + fn write(&mut self, buf: &[u8]) -> Result<()> { + self.write_all(buf).map_err(Error::IoError) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn cursor() { + let mut cursor = Cursor::new(vec![0xFFu8, 0x7Fu8]); + assert_eq!(cursor.position(), 0); + + let mut buf = [0u8]; + assert!(cursor.read(&mut buf[..]).is_ok()); + assert_eq!(cursor.position(), 1); + assert_eq!(buf[0], 0xFFu8); + assert!(cursor.read(&mut buf[..]).is_ok()); + assert_eq!(buf[0], 0x7Fu8); + assert_eq!(cursor.position(), 2); + } + + #[test] + fn overflow_in_cursor() { + let mut cursor = Cursor::new(vec![0u8]); + let mut buf = [0, 1, 2]; + assert!(cursor.read(&mut buf[..]).is_err()); + } +} diff --git a/kernel-ewasm/validator/src/lib.rs b/kernel-ewasm/validator/src/lib.rs index b7e917d..375806b 100644 --- a/kernel-ewasm/validator/src/lib.rs +++ b/kernel-ewasm/validator/src/lib.rs @@ -9,6 +9,21 @@ use pwasm_std; use pwasm_std::vec::Vec; +mod instructions; +mod primitives; +pub mod io; +pub mod serialization; +pub mod types; + +pub use self::io::{Error}; +pub use self::serialization::{Serialize, Deserialize}; + + +pub use self::primitives::{ + VarUint32, VarUint7, Uint8, VarUint1, VarInt7, Uint32, VarInt32, VarInt64, + Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter, +}; + // pub use parity_wasm::deserialize_buffer; /// As per the wasm spec: @@ -49,51 +64,76 @@ pub trait Listed { fn listing(&self) -> Listing; } -// impl Listed for ImportEntry { -// fn listing(&self) -> Listing { -// // Nothing should need to be imported from outside "env", but let's -// // blacklist it just in case. -// if self.module() != "env" { -// Listing::Black -// } else { -// // Tehcnically we don't have to list blacklisted items here, but we -// // do just for clarity. -// match self.field() { -// "memory" => Listing::White, -// "storage_read" => Listing::White, -// "storage_write" => Listing::Black, -// "ret" => Listing::White, -// "gas" => Listing::White, -// "input_length" => Listing::White, -// "fetch_input" => Listing::White, -// "panic" => Listing::White, -// "debug" => Listing::White, -// "ccall" => Listing::Black, -// "dcall" => Listing::Grey, -// "scall" => Listing::White, -// "value" => Listing::White, -// "create" => Listing::Black, -// "suicide" => Listing::White, -// "blockhash" => Listing::White, -// "blocknumber" => Listing::White, -// "coinbase" => Listing::White, -// "difficulty" => Listing::White, -// "gaslimit" => Listing::White, -// "timestamp" => Listing::White, -// "address" => Listing::White, -// "sender" => Listing::White, -// "origin" => Listing::White, -// "elog" => Listing::Black, -// "extcodesize" => Listing::White, -// "extcodecopy" => Listing::White, -// "create2" => Listing::Black, -// "gasleft" => Listing::White, -// _ => Listing::Black, -// } -// } -// } +// A webassembly module is a series of sections. From reading the spec it seems +// that each section can occur only once, except for the custom sections, of +// which there may be multiple. +// struct Module { +// custom_sections: Vec
, +// Type, +// Import, +// Function, +// Table, +// Memory, +// Global, +// Export, +// Start, +// Element, +// Code, +// Data, // } +#[derive(Debug, Clone)] +pub struct ImportEntry { + index: u32, + mod_name: String, + field_name: String, +} + +impl Listed for ImportEntry { + fn listing(&self) -> Listing { + // Nothing should need to be imported from outside "env", but let's + // blacklist it just in case. + if self.mod_name != "env" { + Listing::Black + } else { + // Tehcnically we don't have to list blacklisted items here, but we + // do just for clarity. + match self.field_name.as_ref() { + "memory" => Listing::White, + "storage_read" => Listing::White, + "storage_write" => Listing::Black, + "ret" => Listing::White, + "gas" => Listing::White, + "input_length" => Listing::White, + "fetch_input" => Listing::White, + "panic" => Listing::White, + "debug" => Listing::White, + "ccall" => Listing::Black, + "dcall" => Listing::Grey, + "scall" => Listing::White, + "value" => Listing::White, + "create" => Listing::Black, + "suicide" => Listing::White, + "blockhash" => Listing::White, + "blocknumber" => Listing::White, + "coinbase" => Listing::White, + "difficulty" => Listing::White, + "gaslimit" => Listing::White, + "timestamp" => Listing::White, + "address" => Listing::White, + "sender" => Listing::White, + "origin" => Listing::White, + "elog" => Listing::Black, + "extcodesize" => Listing::White, + "extcodecopy" => Listing::White, + "create2" => Listing::Black, + "gasleft" => Listing::White, + _ => Listing::Black, + } + } + } +} + /// Information on why the contract was considered invalid. #[derive(Debug)] pub struct ValidityReport { @@ -113,7 +153,6 @@ pub enum ValidityError { /// Be able to determine a contracts validity. pub trait Validity { fn is_valid(&self) -> bool; - fn validity(&self) -> ValidityReport; } // Seek does not seem to be implemented in core, so we'll reimplement what we @@ -137,71 +176,213 @@ impl<'a> Cursor { self.i += n; val } + + fn skip(&mut self, n: usize) { + self.i += n; + } } impl Validity for &[u8] { fn is_valid(&self) -> bool { - self.validity().validation_errors.len() == 0 - } - - fn validity(&self) -> ValidityReport { - // let imports = get_imports(self); - let mut report = ValidityReport { - validation_errors: Vec::new() - }; - // First we create a cursor from out data. - - println!("data: {:?}", self); - let mut sections = Vec::new(); // Set an index value, which is our offset into the wasm bytes. let mut cursor = Cursor { i: 0, // data: self, }; + if self.len() < 100 { + println!("data: {:?}", &self); + } else { + println!("data: {:?}", &self[0..100]); + } // Take the magic number, check that it matches if cursor.read_n(4, &self) != &[0, 97, 115, 109] { panic!("magic number not found"); } - // println!("cursor4: {:?}", cursor.read_n(4)); // Take the version, check that it matches if cursor.read_n(4, &self) != &[1, 0, 0, 0] { panic!("proper version number not found"); } - // Now we should be at the first section + // Now we should be at the first section. We care about 4 sections: + // types, imports, functions, and code. The first thing we want to do is + // to find the offsets of these 4 sections. We assume the wasm is well + // formed and there are no duplicate sections and the like. It is also + // possible some of these sections don't exist. + let mut type_section_offset: Option = None; + let mut import_section_offset: Option = None; + let mut function_section_offset: Option = None; + let mut code_section_offset: Option = None; while cursor.i < self.len() { // let section: Section = parse_section(&mut i, &self[d..]); // println!("i: {:?}", cursor.i); let section: Section = parse_section(&mut cursor, &self); - println!("section: {:?}", section); - sections.push(section); + println!("section: {:?}: index: {}", section.type_, section.offset); + // There are many section types we don't care about, for example, + // Custom sections generally contain debugging symbols and + // meaningful function names which are irrelevant to the current + // process. We care only about types, imports, functions, and code. + match section.type_ { + SectionType::Type => { + if type_section_offset.is_some() {panic!("multiple type sections");} + type_section_offset = Some(section.offset); + }, + SectionType::Import => { + if import_section_offset.is_some() {panic!("multiple import sections");} + import_section_offset = Some(section.offset); + }, + SectionType::Function => { + if function_section_offset.is_some() {panic!("multiple function sections");} + function_section_offset = Some(section.offset); + }, + SectionType::Code => { + if code_section_offset.is_some() {panic!("multiple code sections");} + code_section_offset = Some(section.offset); + }, + // We ignore any section we are not interested in. + _ => (), + } } if cursor.i != self.len() { panic!("mismatched length"); } - // for (import_index, import) in imports.iter().enumerate() { - // match import.listing() { - // Listing::White => (), - // Listing::Grey => { - // // Check that this grey import is called safely, wherever is - // // is called. - // for (function_index,instruction_index) in check_grey(self, import_index) { - // report.validation_errors.push(ValidityError::UnsafeGreylistedCall { - // import: import.clone(), - // function_index, - // instruction_index, - // }); - // } - // }, - // Listing::Black => { - // report.validation_errors.push(ValidityError::BlacklistedImport(import.clone())); - // }, - // } - // } - report + // Now that we have our hooks into the module, let's iterate over the + // imports to determine white/grey/black listings. We need to remember + // where the function and code data starts. + + // There is only one greylisted item (dcall) so we will just reserve a + // place for that rather than maintain a list. + let mut dcall_index: Option = None; + if let Some(imports_offset) = import_section_offset { + // Make a new cursor for imports + let mut imports_cursor = Cursor {i:imports_offset}; + let section_size = parse_varuint_32(&mut imports_cursor, &self); + // How many imports do we have? + let n_imports = parse_varuint_32(&mut imports_cursor, &self); + println!("n_imports: {}", n_imports); + for i in 0..n_imports { + // let mut cursor = Cursor {i:0}; + + // Here we parse the names of the import, and its function + // index. + let import = parse_import(&mut imports_cursor, &self, i); + + println!("mod_name: {}, field_name: {}, f_index: {}, listing: {:?}", + import.mod_name, import.field_name, import.index, import.listing()); + match import.listing() { + Listing::White => (), + Listing::Grey => { + if dcall_index.is_some() {panic!("dcall imported multiple times");} + // Document here why this is the case + dcall_index = Some(import.index as usize); + }, + Listing::Black => { + // If we encounter a blacklisted import we can return + // early. + println!("{:?} is blacklisted", import); + // return false; + }, + } + } + } + + // The functions index into types. In fact the function section is just + // a vector of type ids. We don't care about types at this stage. + if let (Some(functions_offset), Some(code_offset)) = (function_section_offset, code_section_offset) { + // Make a new cursor for functions + let mut functions_cursor = Cursor {i:functions_offset}; + // Make a new cursor for code + let mut code_cursor = Cursor {i:code_offset}; + // We will have to try and update these in parallel + let function_section_size = parse_varuint_32(&mut functions_cursor, &self); + let code_section_size = parse_varuint_32(&mut code_cursor, &self); + println!("functions_offset: {:?}", functions_offset); + println!("code_offset: {:?}", code_offset); + let n_functions = parse_varuint_32(&mut functions_cursor, &self); + let n_bodies = parse_varuint_32(&mut code_cursor, &self); + + println!("functions_size: {:?}", function_section_size); + println!("code_size: {:?}", code_section_size); + + assert_eq!(n_functions,n_bodies); + + // Next we iterate through the function bodies and check if they + // violate any of our rules. + for i in 0..n_bodies { + let body_size = parse_varuint_32(&mut code_cursor, &self); + // First we check if it is a system call + if is_syscall(&self[(code_cursor.i)..(code_cursor.i+body_size as usize)]) { + // If the function is a system call we can continue past it + continue; + } + // let body = parse_varuint_32(&mut code_cursor, &self); + println!("function[{}] is {} bytes", i, body_size); + code_cursor.skip(body_size as usize); + // As the function is not a system call, it is not permitted to + // have a dcall in it, so we iterate through all the + // instructions. If we encounter a dcall, we return with a + // false, as this is invalid. + + + } + + // // How many imports do we have? + // let n_imports = parse_varuint_32(&mut imports_cursor, &self); + // for i in 0..n_imports { + // let mut cursor = Cursor {i:0}; + + // // Here we parse the names of the import, and its function + // // index. + // let import = parse_import(&mut cursor, data, n); + + // println!("mod_name: {}, field_name: {}, f_index: {}, listing: {:?}", + // import.mod_name, import.field_name, import.index, import.listing()); + // match import.listing() { + // Listing::White => (), + // Listing::Grey => { + // if dcall_index.is_some() {panic!("dcall imported multiple times");} + // // Document here why this is the case + // dcall_index = Some(import.index); + // }, + // Listing::Black => { + // // If we encounter a blacklisted import we can return + // // early. + // println!("{:?} is blacklisted", import); + // return false; + // }, + // } + // } + } + + // We now know the location of dcall, if there is one. + // We need to iterate over every function and read its code. A + // function can be one of three things: + // + // * A syscall that follows the format + // * A function which is not a syscall and features a greylisted call. + // * A function which does not contain a greylisted call or a blacklistd call. + // The possiblities are checked in that order. + + // Let's find the functions: + // for section in sections { + // } + + // for function in functions { + + // } + + + // for import in greys { + // // If the grey test does not pass return early with false. + // if !check_grey(&self, import.index) { + // return false; + // } + // } + + // All the tests have passed so we can return true. + true } } @@ -222,21 +403,25 @@ enum SectionType { } #[derive(Debug)] -struct Section<'a> { +struct Section { type_: SectionType, - data: &'a [u8], + // The offset is the byte offset of the start of this + // section, i.e. it points directly to the length byte. + offset: usize, } -fn parse_section<'a>(cursor: &mut Cursor, data: &'a [u8]) -> Section<'a> { +fn parse_section(cursor: &mut Cursor, data: &[u8]) -> Section { let type_n = cursor.read(data); + let offset = cursor.i; // println!("type_n: {:?}", type_n); let size_n = parse_varuint_32(cursor, data); - // println!("size_n: {:?}", size_n); + println!("size_n: {:?}", size_n); let type_ = n_to_section(type_n); let section = Section { type_, // data: &cursor.data[0..0], - data: &data[(cursor.i)..(cursor.i+size_n as usize)], + // data: &data[(cursor.i)..(cursor.i+size_n as usize)], + offset, }; cursor.i += size_n as usize; section @@ -279,6 +464,65 @@ fn parse_varuint_32(cursor: &mut Cursor, data: &[u8]) -> u32 { res } +fn parse_import(cursor: &mut Cursor, data: &[u8], index: u32) -> ImportEntry { + // An import comes in 3 sections, mod_name, field_name, and importdesc. + // Both mod_name and field_name are *names* which are vectors of bytes (UTF-8). + let mod_name = parse_name(cursor, data); + let field_name = parse_name(cursor, data); + println!("mod_name: {}, field_name: {}", mod_name, field_name); + // Parse the import description, we don't care about it at this stage so we + // ignore it. We still need to call this in order to skip over the data. + let _type_spec = parse_type_spec(cursor, data); + ImportEntry { + index, + mod_name, + field_name, + } +} + + +/// A type is a 'kind' specifier (0,3) followed by an index. Don't return +/// anything for now. +fn parse_type_spec(cursor: &mut Cursor, data: &[u8]) { + // Just read a single byte as the kind specifier. + let kind = cursor.read(data); + // Currently we only support typeids (0x00) so panic on anything else. + match kind { + 0x00 => (), + _ => panic!("unsupported type spec: {}", kind), + } + let type_index = parse_varuint_32(cursor, data); + +} + +fn parse_name(cursor: &mut Cursor, data: &[u8]) -> String { + let length = parse_varuint_32(cursor, data); + let string_slice: &[u8] = &data[(cursor.i)..(cursor.i+length as usize)]; + cursor.i += length as usize; + String::from_utf8(string_slice.into()).unwrap() +} + +fn parse_vec_imports(data: &[u8]) -> Vec { + let mut cursor = Cursor {i:0}; + // The length is the number of encoded elements (as opposed to bytes) + let length = parse_varuint_32(&mut cursor, data); + let mut elems = Vec::new(); + for n in 0..length { + let entry = parse_import(&mut cursor, data, n); + elems.push(entry); + } + elems +} + +/// This is our desrialisation trait. +// trait WasmDeserialize { +// fn deserialize(data: &[u8]) -> Self; +// } + +// impl WasmDeserialize for char { + +// } + // fn get_imports(module: &Module) -> Vec { // if let Some(import_section) = module.import_section() { @@ -420,6 +664,139 @@ fn parse_varuint_32(cursor: &mut Cursor, data: &[u8]) -> u32 { // true // } +/// An iterator which counts from one to five +struct Code<'a> { + current_offset: usize, + body: &'a [u8], +} + +// we want our count to start at one, so let's add a new() method to help. +// This isn't strictly necessary, but is convenient. Note that we start +// `count` at zero, we'll see why in `next()`'s implementation below. +impl<'a> Code<'a> { + fn new(body: &'a [u8]) -> Code { + Code { + current_offset: 0, + body: body, + } + } +} + +impl<'a> Iterator for Code<'a> { + // we will be counting with usize + type Item = u8; + + // next() is the only required method + fn next(&mut self) -> Option { + // Increment our count. This is why we started at zero. + + // Check to see if we've finished counting or not. + if self.current_offset < self.body.len() { + // We need to parse the code into something meaningful + let val = Some(self.body[self.current_offset]); + self.current_offset += 1; + val + } else { + None + } + } +} + +pub fn is_syscall(body: &[u8]) -> bool { + let code_iter = Code::new(body); + for (i,d) in code_iter.enumerate() { + println!("code_iter[{}]: {:#x}", i, d); + } + // // First we need to check that the instructions are correct, that is: + // // 0. call $a + // // 1. call $b + // // 2. get_local 0 + // // 3. get_local 1 + // // 4. get_local 2 + // // 5. get_local 3 + // // 6. call $c + // // $a, $b, and $c will be used later. + // // First we simply check the length + // if instructions.len() != 8 { + // return false; + // } + // // 0. call gasleft + // if let Instruction::Call(f_ind) = instructions[0] { + // // Check that f_ind is the function index of "gasleft" + // let gasleft_index = find_import(module, "env", "gasleft"); + // if Some(f_ind) != gasleft_index { + // return false; + // } + // } else { + // return false; + // } + // // 1. call sender + // if let Instruction::Call(f_ind) = instructions[1] { + // // Check that f_ind is the function index of "sender" + // let sender_index = find_import(module, "env", "sender"); + // if Some(f_ind) != sender_index { + // return false; + // } + // } else { + // return false; + // } + // // 2. get_local 0 + // if let Instruction::GetLocal(0) = instructions[2] { + // } else { + // return false; + // } + // // 3. get_local 1 + // if let Instruction::GetLocal(1) = instructions[3] { + // } else { + // return false; + // } + // // 4. get_local 2 + // if let Instruction::GetLocal(2) = instructions[4] { + // } else { + // return false; + // } + // // 5. get_local 3 + // if let Instruction::GetLocal(3) = instructions[5] { + // } else { + // return false; + // } + + // // 6. call dcall + // if let Instruction::Call(f_ind) = instructions[6] { + // // Check that f_ind is the function index of "dcall" + // let dcall_index = find_import(module, "env", "dcall"); + // if Some(f_ind) != dcall_index { + // return false; + // } + // } else { + // return false; + // } + // // 7. END + // if let Instruction::End = instructions[7] { + // } else { + // return false; + // } + + // // Check that no locals are used + // if code.locals().len() > 0 { + // return false; + // } + // // Check that the type signature is correct + // let parity_wasm::elements::Type::Function(f_type) = this_type; + // if f_type.return_type() != Some(ValueType::I32) { + // return false; + // } + // if f_type.params() != [ ValueType::I32, ValueType::I32, ValueType::I32, ValueType::I32] { + // return false; + // } + // if f_type.form() != 0x60 { + // return false; + // } + + // true + false +} + #[cfg(test)] mod tests { // extern crate pwasm_test; @@ -430,6 +807,9 @@ mod tests { // use pwasm_abi::types::*; // use self::pwasm_test::{ext_reset, ext_get}; // use token::TokenInterface; + use std::io; + use std::io::prelude::*; + use std::fs::File; #[test] fn module_only_pass() { @@ -453,6 +833,15 @@ mod tests { assert!(wasm.as_slice().is_valid()); } + #[test] + fn example_contract_1_pass() { + let mut f = File::open("../example_contract_1/target/wasm32-unknown-unknown/release/example_contract_1.wasm").expect("could not open file"); + let mut wasm = Vec::new(); + f.read_to_end(&mut wasm).unwrap(); + println!("big example", ); + assert!(!wasm.as_slice().is_valid()); + } + // #[test] // fn minimal_contract_with_write_fail() { // let wat = r#" diff --git a/kernel-ewasm/validator/src/primitives.rs b/kernel-ewasm/validator/src/primitives.rs new file mode 100644 index 0000000..8e6d195 --- /dev/null +++ b/kernel-ewasm/validator/src/primitives.rs @@ -0,0 +1,926 @@ +// This file is based on parity-wasm from parity, MIT & Apache Licensed +// use crate::rust::{vec::Vec, string::String}; +use crate::{io}; +use crate::{Deserialize, Serialize}; +use pwasm_std::vec::Vec; +use crate::serialization::{Error}; +use crate::serialization::{deserialize_buffer}; + + +macro_rules! buffered_read { + ($buffer_size: expr, $length: expr, $reader: expr) => { + { + let mut vec_buf = Vec::new(); + let mut total_read = 0; + let mut buf = [0u8; $buffer_size]; + while total_read < $length { + let next_to_read = if $length - total_read > $buffer_size { $buffer_size } else { $length - total_read }; + $reader.read(&mut buf[0..next_to_read])?; + vec_buf.extend_from_slice(&buf[0..next_to_read]); + total_read += next_to_read; + } + vec_buf + } + } +} + + + +/// Unsigned variable-length integer, limited to 32 bits, +/// represented by at most 5 bytes that may contain padding 0x80 bytes. +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct VarUint32(u32); + +impl From for usize { + fn from(var: VarUint32) -> usize { + var.0 as usize + } +} + +impl From for u32 { + fn from(var: VarUint32) -> u32 { + var.0 + } +} + +impl From for VarUint32 { + fn from(i: u32) -> VarUint32 { + VarUint32(i) + } +} + +impl From for VarUint32 { + fn from(i: usize) -> VarUint32 { + assert!(i <= u32::max_value() as usize); + VarUint32(i as u32) + } +} + +impl Deserialize for VarUint32 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut res = 0; + let mut shift = 0; + let mut u8buf = [0u8; 1]; + loop { + if shift > 31 { return Err(Error::InvalidVarUint32); } + + reader.read(&mut u8buf)?; + let b = u8buf[0] as u32; + res |= (b & 0x7f).checked_shl(shift).ok_or(Error::InvalidVarUint32)?; + shift += 7; + if (b >> 7) == 0 { + if shift >= 32 && (b as u8).leading_zeros() < 4 { + return Err(Error::InvalidVarInt32); + } + break; + } + } + Ok(VarUint32(res)) + } +} + +impl Serialize for VarUint32 { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + let mut buf = [0u8; 1]; + let mut v = self.0; + loop { + buf[0] = (v & 0b0111_1111) as u8; + v >>= 7; + if v > 0 { + buf[0] |= 0b1000_0000; + } + writer.write(&buf[..])?; + if v == 0 { break; } + } + + Ok(()) + } +} + +/// Unsigned variable-length integer, limited to 64 bits, +/// represented by at most 9 bytes that may contain padding 0x80 bytes. +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct VarUint64(u64); + +impl From for u64 { + fn from(var: VarUint64) -> u64 { + var.0 + } +} + +impl Deserialize for VarUint64 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut res = 0; + let mut shift = 0; + let mut u8buf = [0u8; 1]; + loop { + if shift > 63 { return Err(Error::InvalidVarUint64); } + + reader.read(&mut u8buf)?; + let b = u8buf[0] as u64; + res |= (b & 0x7f).checked_shl(shift).ok_or(Error::InvalidVarUint64)?; + shift += 7; + if (b >> 7) == 0 { + if shift >= 64 && (b as u8).leading_zeros() < 7 { + return Err(Error::InvalidVarInt64); + } + break; + } + } + Ok(VarUint64(res)) + } +} + +impl Serialize for VarUint64 { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + let mut buf = [0u8; 1]; + let mut v = self.0; + loop { + buf[0] = (v & 0b0111_1111) as u8; + v >>= 7; + if v > 0 { + buf[0] |= 0b1000_0000; + } + writer.write(&buf[..])?; + if v == 0 { break; } + } + + Ok(()) + } +} + +impl From for VarUint64 { + fn from(u: u64) -> VarUint64 { + VarUint64(u) + } +} + +/// 7-bit unsigned integer, encoded in LEB128 (always 1 byte length). +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct VarUint7(u8); + +impl From for u8 { + fn from(v: VarUint7) -> u8 { + v.0 + } +} + +impl From for VarUint7 { + fn from(v: u8) -> Self { + VarUint7(v) + } +} + +impl Deserialize for VarUint7 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut u8buf = [0u8; 1]; + reader.read(&mut u8buf)?; + Ok(VarUint7(u8buf[0])) + } +} + +impl Serialize for VarUint7 { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + // todo check range? + writer.write(&[self.0])?; + Ok(()) + } +} + +/// 7-bit signed integer, encoded in LEB128 (always 1 byte length) +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct VarInt7(i8); + +impl From for i8 { + fn from(v: VarInt7) -> i8 { + v.0 + } +} + +impl From for VarInt7 { + fn from(v: i8) -> VarInt7 { + VarInt7(v) + } +} + +impl Deserialize for VarInt7 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut u8buf = [0u8; 1]; + reader.read(&mut u8buf)?; + + // check if number is not continued! + if u8buf[0] & 0b1000_0000 != 0 { + return Err(Error::InvalidVarInt7(u8buf[0])); + } + + // expand sign + if u8buf[0] & 0b0100_0000 == 0b0100_0000 { u8buf[0] |= 0b1000_0000 } + + Ok(VarInt7(u8buf[0] as i8)) + } +} + +impl Serialize for VarInt7 { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + // todo check range? + let mut b: u8 = self.0 as u8; + if self.0 < 0 { b |= 0b0100_0000; b &= 0b0111_1111; } + writer.write(&[b])?; + Ok(()) + } +} + +/// 8-bit unsigned integer, NOT encoded in LEB128; +/// it's just a single byte. +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Uint8(u8); + +impl From for u8 { + fn from(v: Uint8) -> u8 { + v.0 + } +} + +impl From for Uint8 { + fn from(v: u8) -> Self { + Uint8(v) + } +} + +impl Deserialize for Uint8 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut u8buf = [0u8; 1]; + reader.read(&mut u8buf)?; + Ok(Uint8(u8buf[0])) + } +} + +impl Serialize for Uint8 { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + writer.write(&[self.0])?; + Ok(()) + } +} + + +/// 32-bit signed integer, encoded in LEB128 (can be 1-5 bytes length). +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct VarInt32(i32); + +impl From for i32 { + fn from(v: VarInt32) -> i32 { + v.0 + } +} + +impl From for VarInt32 { + fn from(v: i32) -> VarInt32 { + VarInt32(v) + } +} + +impl Deserialize for VarInt32 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut res = 0; + let mut shift = 0; + let mut u8buf = [0u8; 1]; + loop { + if shift > 31 { return Err(Error::InvalidVarInt32); } + reader.read(&mut u8buf)?; + let b = u8buf[0]; + + res |= ((b & 0x7f) as i32).checked_shl(shift).ok_or(Error::InvalidVarInt32)?; + + shift += 7; + if (b >> 7) == 0 { + if shift < 32 && b & 0b0100_0000 == 0b0100_0000 { + res |= (1i32 << shift).wrapping_neg(); + } else if shift >= 32 && b & 0b0100_0000 == 0b0100_0000 { + if (!(b | 0b1000_0000)).leading_zeros() < 5 { + return Err(Error::InvalidVarInt32); + } + } else if shift >= 32 && b & 0b0100_0000 == 0 { + if b.leading_zeros() < 5 { + return Err(Error::InvalidVarInt32); + } + } + break; + } + } + Ok(VarInt32(res)) + } +} + +impl Serialize for VarInt32 { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + let mut buf = [0u8; 1]; + let mut v = self.0; + let mut more = true; + while more { + buf[0] = (v & 0b0111_1111) as u8; + v >>= 7; + if (v == 0 && buf[0] & 0b0100_0000 == 0) || (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) { + more = false + } else { + buf[0] |= 0b1000_0000 + } + + writer.write(&buf[..])?; + } + + Ok(()) + } +} + +/// 64-bit signed integer, encoded in LEB128 (can be 1-9 bytes length). +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct VarInt64(i64); + +impl From for i64 { + fn from(v: VarInt64) -> i64 { + v.0 + } +} + +impl From for VarInt64 { + fn from(v: i64) -> VarInt64 { + VarInt64(v) + } +} + +impl Deserialize for VarInt64 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut res = 0i64; + let mut shift = 0; + let mut u8buf = [0u8; 1]; + + loop { + if shift > 63 { return Err(Error::InvalidVarInt64); } + reader.read(&mut u8buf)?; + let b = u8buf[0]; + + res |= ((b & 0x7f) as i64).checked_shl(shift).ok_or(Error::InvalidVarInt64)?; + + shift += 7; + if (b >> 7) == 0 { + if shift < 64 && b & 0b0100_0000 == 0b0100_0000 { + res |= (1i64 << shift).wrapping_neg(); + } else if shift >= 64 && b & 0b0100_0000 == 0b0100_0000 { + if (b | 0b1000_0000) as i8 != -1 { + return Err(Error::InvalidVarInt64); + } + } else if shift >= 64 && b != 0 { + return Err(Error::InvalidVarInt64); + } + break; + } + } + Ok(VarInt64(res)) + } +} + +impl Serialize for VarInt64 { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + let mut buf = [0u8; 1]; + let mut v = self.0; + let mut more = true; + while more { + buf[0] = (v & 0b0111_1111) as u8; + v >>= 7; + if (v == 0 && buf[0] & 0b0100_0000 == 0) || (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) { + more = false + } else { + buf[0] |= 0b1000_0000 + } + + writer.write(&buf[..])?; + } + + Ok(()) + } +} + +/// 32-bit unsigned integer, encoded in little endian. +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Uint32(u32); + +impl Deserialize for Uint32 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut buf = [0u8; 4]; + reader.read(&mut buf)?; + // todo check range + Ok(u32::from_le_bytes(buf).into()) + } +} + +impl From for u32 { + fn from(var: Uint32) -> u32 { + var.0 + } +} + +impl Serialize for Uint32 { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + writer.write(&self.0.to_le_bytes())?; + Ok(()) + } +} + +impl From for Uint32 { + fn from(u: u32) -> Self { Uint32(u) } +} + +/// 64-bit unsigned integer, encoded in little endian. +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Uint64(u64); + +impl Deserialize for Uint64 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut buf = [0u8; 8]; + reader.read(&mut buf)?; + // todo check range + Ok(u64::from_le_bytes(buf).into()) + } +} + +impl Serialize for Uint64 { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + writer.write(&self.0.to_le_bytes())?; + Ok(()) + } +} + +impl From for Uint64 { + fn from(u: u64) -> Self { Uint64(u) } +} + +impl From for u64 { + fn from(var: Uint64) -> u64 { + var.0 + } +} + + +/// VarUint1, 1-bit value (0/1). +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct VarUint1(bool); + +impl From for bool { + fn from(v: VarUint1) -> bool { + v.0 + } +} + +impl From for VarUint1 { + fn from(b: bool) -> Self { + VarUint1(b) + } +} + +impl Deserialize for VarUint1 { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut u8buf = [0u8; 1]; + reader.read(&mut u8buf)?; + match u8buf[0] { + 0 => Ok(VarUint1(false)), + 1 => Ok(VarUint1(true)), + v @ _ => Err(Error::InvalidVarUint1(v)), + } + } +} + +impl Serialize for VarUint1 { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + writer.write(&[ + if self.0 { 1u8 } else { 0u8 } + ])?; + Ok(()) + } +} + +impl Deserialize for String { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let length = u32::from(VarUint32::deserialize(reader)?) as usize; + if length > 0 { + String::from_utf8(buffered_read!(1024, length, reader)).map_err(|_| Error::NonUtf8String) + } + else { + Ok(String::new()) + } + } +} + +impl Serialize for String { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Error> { + VarUint32::from(self.len()).serialize(writer)?; + writer.write(&self.into_bytes()[..])?; + Ok(()) + } +} + +/// List for reading sequence of elements typed `T`, given +/// they are preceded by length (serialized as VarUint32). +#[derive(Debug, Clone)] +pub struct CountedList(Vec); + +impl CountedList { + /// Destroy counted list returing inner vector. + pub fn into_inner(self) -> Vec { self.0 } +} + +impl Deserialize for CountedList where T::Error: From { + type Error = T::Error; + + fn deserialize(reader: &mut R) -> Result { + let count: usize = VarUint32::deserialize(reader)?.into(); + let mut result = Vec::new(); + for _ in 0..count { result.push(T::deserialize(reader)?); } + Ok(CountedList(result)) + } +} + +/// Helper struct to write payload which is preceded by +/// it's own length in bytes. +#[derive(Debug)] +pub struct CountedWriter<'a, W: 'a + io::Write> { + writer: &'a mut W, + data: Vec, +} + +impl<'a, W: 'a + io::Write> CountedWriter<'a, W> { + /// New counted writer on top of the given serial writer. + pub fn new(writer: &'a mut W) -> Self { + CountedWriter { + writer: writer, + data: Vec::new(), + } + } + + /// Finish counted writer routing, which writes accumulated length + /// and actual payload. + pub fn done(self) -> io::Result<()> { + let writer = self.writer; + let data = self.data; + VarUint32::from(data.len()) + .serialize(writer) + .map_err(|_| io::Error::InvalidData)?; + writer.write(&data[..])?; + Ok(()) + } +} + +impl<'a, W: 'a + io::Write> io::Write for CountedWriter<'a, W> { + fn write(&mut self, buf: &[u8]) -> io::Result<()> { + self.data.extend_from_slice(buf); + Ok(()) + } +} + +/// Helper struct to write series of `T` preceded by the length of the sequence +/// serialized as VarUint32. +#[derive(Debug, Clone)] +pub struct CountedListWriter, T: IntoIterator>(pub usize, pub T); + +impl, T: IntoIterator> Serialize for CountedListWriter { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + let len_us = self.0; + let data = self.1; + let len: VarUint32 = len_us.into(); + len.serialize(writer)?; + for data_element in data { data_element.serialize(writer)? } + + Ok(()) + } +} + + +// #[cfg(test)] +// mod tests { + +// use super::super::{deserialize_buffer, Serialize}; +// use super::{CountedList, VarInt7, VarUint32, VarInt32, VarInt64, VarUint64}; +// use crate::io::Error; + +// fn varuint32_ser_test(val: u32, expected: Vec) { +// let mut buf = Vec::new(); +// let v1: VarUint32 = val.into(); +// v1.serialize(&mut buf).expect("to be serialized ok"); +// assert_eq!(expected, buf); +// } + +// fn varuint32_de_test(dt: Vec, expected: u32) { +// let val: VarUint32 = deserialize_buffer(&dt).expect("buf to be serialized"); +// assert_eq!(expected, val.into()); +// } + +// fn varuint32_serde_test(dt: Vec, val: u32) { +// varuint32_de_test(dt.clone(), val); +// varuint32_ser_test(val, dt); +// } + +// fn varint32_ser_test(val: i32, expected: Vec) { +// let mut buf = Vec::new(); +// let v1: VarInt32 = val.into(); +// v1.serialize(&mut buf).expect("to be serialized ok"); +// assert_eq!(expected, buf); +// } + +// fn varint32_de_test(dt: Vec, expected: i32) { +// let val: VarInt32 = deserialize_buffer(&dt).expect("buf to be serialized"); +// assert_eq!(expected, val.into()); +// } + +// fn varint32_serde_test(dt: Vec, val: i32) { +// varint32_de_test(dt.clone(), val); +// varint32_ser_test(val, dt); +// } + +// fn varuint64_ser_test(val: u64, expected: Vec) { +// let mut buf = Vec::new(); +// let v1: VarUint64 = val.into(); +// v1.serialize(&mut buf).expect("to be serialized ok"); +// assert_eq!(expected, buf); +// } + +// fn varuint64_de_test(dt: Vec, expected: u64) { +// let val: VarUint64 = deserialize_buffer(&dt).expect("buf to be serialized"); +// assert_eq!(expected, val.into()); +// } + +// fn varuint64_serde_test(dt: Vec, val: u64) { +// varuint64_de_test(dt.clone(), val); +// varuint64_ser_test(val, dt); +// } + +// fn varint64_ser_test(val: i64, expected: Vec) { +// let mut buf = Vec::new(); +// let v1: VarInt64 = val.into(); +// v1.serialize(&mut buf).expect("to be serialized ok"); +// assert_eq!(expected, buf); +// } + +// fn varint64_de_test(dt: Vec, expected: i64) { +// let val: VarInt64 = deserialize_buffer(&dt).expect("buf to be serialized"); +// assert_eq!(expected, val.into()); +// } + +// fn varint64_serde_test(dt: Vec, val: i64) { +// varint64_de_test(dt.clone(), val); +// varint64_ser_test(val, dt); +// } + +// #[test] +// fn varuint32_0() { +// varuint32_serde_test(vec![0u8; 1], 0); +// } + +// #[test] +// fn varuint32_1() { +// varuint32_serde_test(vec![1u8; 1], 1); +// } + +// #[test] +// fn varuint32_135() { +// varuint32_serde_test(vec![135u8, 0x01], 135); +// } + +// #[test] +// fn varuint32_8192() { +// varuint32_serde_test(vec![0x80, 0x40], 8192); +// } + +// #[test] +// fn varint32_8192() { +// varint32_serde_test(vec![0x80, 0xc0, 0x00], 8192); +// } + +// #[test] +// fn varint32_neg_8192() { +// varint32_serde_test(vec![0x80, 0x40], -8192); +// } + +// #[test] +// fn varuint64_0() { +// varuint64_serde_test(vec![0u8; 1], 0); +// } + +// #[test] +// fn varuint64_1() { +// varuint64_serde_test(vec![1u8; 1], 1); +// } + +// #[test] +// fn varuint64_135() { +// varuint64_serde_test(vec![135u8, 0x01], 135); +// } + +// #[test] +// fn varuint64_8192() { +// varuint64_serde_test(vec![0x80, 0x40], 8192); +// } + +// #[test] +// fn varint64_8192() { +// varint64_serde_test(vec![0x80, 0xc0, 0x00], 8192); +// } + +// #[test] +// fn varint64_neg_8192() { +// varint64_serde_test(vec![0x80, 0x40], -8192); +// } + +// #[test] +// fn varint64_min() { +// varint64_serde_test( +// vec![0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f], +// -9223372036854775808, +// ); +// } + +// #[test] +// fn varint64_bad_extended() { +// let res = deserialize_buffer::(&[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x6f][..]); +// assert!(res.is_err()); +// } + +// #[test] +// fn varint32_bad_extended() { +// let res = deserialize_buffer::(&[0x80, 0x80, 0x80, 0x80, 0x6f][..]); +// assert!(res.is_err()); +// } + +// #[test] +// fn varint32_bad_extended2() { +// let res = deserialize_buffer::(&[0x80, 0x80, 0x80, 0x80, 0x41][..]); +// assert!(res.is_err()); +// } + +// #[test] +// fn varint64_max() { +// varint64_serde_test( +// vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00], +// 9223372036854775807, +// ); +// } + +// #[test] +// fn varint64_too_long() { +// assert!( +// deserialize_buffer::( +// &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00][..], +// ).is_err() +// ); +// } + +// #[test] +// fn varint32_too_long() { +// assert!( +// deserialize_buffer::( +// &[0xff, 0xff, 0xff, 0xff, 0xff, 0x00][..], +// ).is_err() +// ); +// } + +// #[test] +// fn varuint64_too_long() { +// assert!( +// deserialize_buffer::( +// &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00][..], +// ).is_err() +// ); +// } + +// #[test] +// fn varuint32_too_long() { +// assert!( +// deserialize_buffer::( +// &[0xff, 0xff, 0xff, 0xff, 0xff, 0x00][..], +// ).is_err() +// ); +// } + +// #[test] +// fn varuint32_too_long_trailing() { +// assert!( +// deserialize_buffer::( +// &[0xff, 0xff, 0xff, 0xff, 0x7f][..], +// ).is_err() +// ); +// } + +// #[test] +// fn varuint64_too_long_trailing() { +// assert!( +// deserialize_buffer::( +// &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04][..], +// ).is_err() +// ); +// } + +// #[test] +// fn varint32_min() { +// varint32_serde_test( +// vec![0x80, 0x80, 0x80, 0x80, 0x78], +// -2147483648, +// ); +// } + +// #[test] +// fn varint7_invalid() { +// match deserialize_buffer::(&[240]) { +// Err(Error::InvalidVarInt7(_)) => {}, +// _ => panic!("Should be invalid varint7 error!") +// } +// } + +// #[test] +// fn varint7_neg() { +// assert_eq!(-0x10i8, deserialize_buffer::(&[0x70]).expect("fail").into()); +// } + +// #[test] +// fn varuint32_too_long_nulled() { +// match deserialize_buffer::( +// &[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x78] +// ) { +// Err(Error::InvalidVarUint32) => {}, +// _ => panic!("Should be invalid varuint32"), +// } +// } + +// #[test] +// fn varint32_max() { +// varint32_serde_test( +// vec![0xff, 0xff, 0xff, 0xff, 0x07], +// 2147483647, +// ); +// } + + +// #[test] +// fn counted_list() { +// let payload = [ +// 133u8, //(128+5), length is 5 +// 0x80, 0x80, 0x80, 0x0, // padding +// 0x01, +// 0x7d, +// 0x05, +// 0x07, +// 0x09, +// ]; + +// let list: CountedList = +// deserialize_buffer(&payload).expect("type_section be deserialized"); + +// let vars = list.into_inner(); +// assert_eq!(5, vars.len()); +// let v3: i8 = (*vars.get(1).unwrap()).into(); +// assert_eq!(-0x03i8, v3); +// } +// } diff --git a/kernel-ewasm/validator/src/serialization.rs b/kernel-ewasm/validator/src/serialization.rs new file mode 100644 index 0000000..9cad144 --- /dev/null +++ b/kernel-ewasm/validator/src/serialization.rs @@ -0,0 +1,220 @@ +use crate::{io}; +use crate::primitives::*; +pub use core::fmt; + +/// Deserialization from serial i/o. +pub trait Deserialize : Sized { + /// Serialization error produced by deserialization routine. + type Error: From; + /// Deserialize type from serial i/o + fn deserialize(reader: &mut R) -> Result; +} + +/// Serialization to serial i/o. Takes self by value to consume less memory +/// (parity-wasm IR is being partially freed by filling the result buffer). +pub trait Serialize { + /// Serialization error produced by serialization routine. + type Error: From; + /// Serialize type to serial i/o + fn serialize(self, writer: &mut W) -> Result<(), Self::Error>; +} + +/// Deserialization/serialization error +#[derive(Debug, Clone)] +pub enum Error { + /// Unexpected end of input. + UnexpectedEof, + /// Invalid magic. + InvalidMagic, + /// Unsupported version. + UnsupportedVersion(u32), + /// Inconsistence between declared and actual length. + InconsistentLength { + /// Expected length of the definition. + expected: usize, + /// Actual length of the definition. + actual: usize + }, + /// Other static error. + Other(&'static str), + /// Other allocated error. + HeapOther(String), + /// Invalid/unknown value type declaration. + UnknownValueType(i8), + /// Invalid/unknown table element type declaration. + UnknownTableElementType(i8), + /// Non-utf8 string. + NonUtf8String, + /// Unknown external kind code. + UnknownExternalKind(u8), + /// Unknown internal kind code. + UnknownInternalKind(u8), + /// Unknown opcode encountered. + UnknownOpcode(u8), + /// Unknown SIMD opcode encountered. + UnknownSimdOpcode(u32), + /// Invalid VarUint1 value. + InvalidVarUint1(u8), + /// Invalid VarInt32 value. + InvalidVarInt32, + /// Invalid VarInt64 value. + InvalidVarInt64, + /// Invalid VarUint32 value. + InvalidVarUint32, + /// Invalid VarUint64 value. + InvalidVarUint64, + /// Inconsistent metadata. + InconsistentMetadata, + /// Invalid section id. + InvalidSectionId(u8), + /// Sections are out of order. + SectionsOutOfOrder, + /// Duplicated sections. + DuplicatedSections(u8), + /// Invalid memory reference (should be 0). + InvalidMemoryReference(u8), + /// Invalid table reference (should be 0). + InvalidTableReference(u8), + /// Invalid value used for flags in limits type. + InvalidLimitsFlags(u8), + /// Unknown function form (should be 0x60). + UnknownFunctionForm(u8), + /// Invalid varint7 (should be in -64..63 range). + InvalidVarInt7(u8), + /// Number of function body entries and signatures does not match. + InconsistentCode, + /// Only flags 0, 1, and 2 are accepted on segments. + InvalidSegmentFlags(u32), + /// Sum of counts of locals is greater than 2^32. + TooManyLocals, + /// Duplicated name subsections. + DuplicatedNameSubsections(u8), + /// Unknown name subsection type. + UnknownNameSubsectionType(u8), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::UnexpectedEof => write!(f, "Unexpected end of input"), + Error::InvalidMagic => write!(f, "Invalid magic number at start of file"), + Error::UnsupportedVersion(v) => write!(f, "Unsupported wasm version {}", v), + Error::InconsistentLength { expected, actual } => { + write!(f, "Expected length {}, found {}", expected, actual) + } + Error::Other(msg) => write!(f, "{}", msg), + Error::HeapOther(ref msg) => write!(f, "{}", msg), + Error::UnknownValueType(ty) => write!(f, "Invalid or unknown value type {}", ty), + Error::UnknownTableElementType(ty) => write!(f, "Unknown table element type {}", ty), + Error::NonUtf8String => write!(f, "Non-UTF-8 string"), + Error::UnknownExternalKind(kind) => write!(f, "Unknown external kind {}", kind), + Error::UnknownInternalKind(kind) => write!(f, "Unknown internal kind {}", kind), + Error::UnknownOpcode(opcode) => write!(f, "Unknown opcode {}", opcode), + Error::UnknownSimdOpcode(opcode) => write!(f, "Unknown SIMD opcode {}", opcode), + Error::InvalidVarUint1(val) => write!(f, "Not an unsigned 1-bit integer: {}", val), + Error::InvalidVarInt7(val) => write!(f, "Not a signed 7-bit integer: {}", val), + Error::InvalidVarInt32 => write!(f, "Not a signed 32-bit integer"), + Error::InvalidVarUint32 => write!(f, "Not an unsigned 32-bit integer"), + Error::InvalidVarInt64 => write!(f, "Not a signed 64-bit integer"), + Error::InvalidVarUint64 => write!(f, "Not an unsigned 64-bit integer"), + Error::InconsistentMetadata => write!(f, "Inconsistent metadata"), + Error::InvalidSectionId(ref id) => write!(f, "Invalid section id: {}", id), + Error::SectionsOutOfOrder => write!(f, "Sections out of order"), + Error::DuplicatedSections(ref id) => write!(f, "Duplicated sections ({})", id), + Error::InvalidMemoryReference(ref mem_ref) => write!(f, "Invalid memory reference ({})", mem_ref), + Error::InvalidTableReference(ref table_ref) => write!(f, "Invalid table reference ({})", table_ref), + Error::InvalidLimitsFlags(ref flags) => write!(f, "Invalid limits flags ({})", flags), + Error::UnknownFunctionForm(ref form) => write!(f, "Unknown function form ({})", form), + Error::InconsistentCode => write!(f, "Number of function body entries and signatures does not match"), + Error::InvalidSegmentFlags(n) => write!(f, "Invalid segment flags: {}", n), + Error::TooManyLocals => write!(f, "Too many locals"), + Error::DuplicatedNameSubsections(n) => write!(f, "Duplicated name subsections: {}", n), + Error::UnknownNameSubsectionType(n) => write!(f, "Unknown subsection type: {}", n), + } + } +} + +#[cfg(feature = "std")] +impl ::std::error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::UnexpectedEof => "Unexpected end of input", + Error::InvalidMagic => "Invalid magic number at start of file", + Error::UnsupportedVersion(_) => "Unsupported wasm version", + Error::InconsistentLength { .. } => "Inconsistent length", + Error::Other(msg) => msg, + Error::HeapOther(ref msg) => &msg[..], + Error::UnknownValueType(_) => "Invalid or unknown value type", + Error::UnknownTableElementType(_) => "Unknown table element type", + Error::NonUtf8String => "Non-UTF-8 string", + Error::UnknownExternalKind(_) => "Unknown external kind", + Error::UnknownInternalKind(_) => "Unknown internal kind", + Error::UnknownOpcode(_) => "Unknown opcode", + Error::UnknownSimdOpcode(_) => "Unknown SIMD opcode", + Error::InvalidVarUint1(_) => "Not an unsigned 1-bit integer", + Error::InvalidVarInt32 => "Not a signed 32-bit integer", + Error::InvalidVarInt7(_) => "Not a signed 7-bit integer", + Error::InvalidVarUint32 => "Not an unsigned 32-bit integer", + Error::InvalidVarInt64 => "Not a signed 64-bit integer", + Error::InvalidVarUint64 => "Not an unsigned 64-bit integer", + Error::InconsistentMetadata => "Inconsistent metadata", + Error::InvalidSectionId(_) => "Invalid section id", + Error::SectionsOutOfOrder => "Sections out of order", + Error::DuplicatedSections(_) => "Duplicated section", + Error::InvalidMemoryReference(_) => "Invalid memory reference", + Error::InvalidTableReference(_) => "Invalid table reference", + Error::InvalidLimitsFlags(_) => "Invalid limits flags", + Error::UnknownFunctionForm(_) => "Unknown function form", + Error::InconsistentCode => "Number of function body entries and signatures does not match", + Error::InvalidSegmentFlags(_) => "Invalid segment flags", + Error::TooManyLocals => "Too many locals", + Error::DuplicatedNameSubsections(_) => "Duplicated name subsections", + Error::UnknownNameSubsectionType(_) => "Unknown name subsections type", + } + } +} + +impl From for Error { + fn from(err: io::Error) -> Self { + Error::HeapOther(format!("I/O Error: {:?}", err)) + } +} + +/// Unparsed part of the module/section. +pub struct Unparsed(pub Vec); + +impl Deserialize for Unparsed { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let len = VarUint32::deserialize(reader)?.into(); + let mut vec = vec![0u8; len]; + reader.read(&mut vec[..])?; + Ok(Unparsed(vec)) + } +} + +impl From for Vec { + fn from(u: Unparsed) -> Vec { + u.0 + } +} + +/// Deserialize deserializable type from buffer. +pub fn deserialize_buffer(contents: &[u8]) -> Result { + let mut reader = io::Cursor::new(contents); + let result = T::deserialize(&mut reader)?; + if reader.position() != contents.len() { + // It's a TrailingData, since if there is not enough data then + // UnexpectedEof must have been returned earlier in T::deserialize. + return Err(io::Error::TrailingData.into()) + } + Ok(result) +} + +/// Create buffer with serialized value. +pub fn serialize(val: T) -> Result, T::Error> { + let mut buf = Vec::new(); + val.serialize(&mut buf)?; + Ok(buf) +} diff --git a/kernel-ewasm/validator/src/types.rs b/kernel-ewasm/validator/src/types.rs new file mode 100644 index 0000000..ee9d990 --- /dev/null +++ b/kernel-ewasm/validator/src/types.rs @@ -0,0 +1,263 @@ +// use crate::rust::{fmt, vec::Vec}; +pub use core::fmt; +use pwasm_std::vec::Vec; +use crate::io; +use super::{ + Deserialize, Serialize, VarUint7, VarInt7, VarUint1, CountedList, + CountedListWriter, VarUint32, +}; +use crate::serialization::{Error}; + +/// Type definition in types section. Currently can be only of the function type. +#[derive(Debug, Clone, PartialEq, Hash, Eq)] +pub enum Type { + /// Function type. + Function(FunctionType), +} + +impl Deserialize for Type { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + Ok(Type::Function(FunctionType::deserialize(reader)?)) + } +} + +// impl Serialize for Type { +// type Error = Error; + +// fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { +// match self { +// Type::Function(fn_type) => fn_type.serialize(writer) +// } +// } +// } + +/// Value type. +#[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)] +pub enum ValueType { + /// 32-bit signed integer + I32, + /// 64-bit signed integer + I64, + /// 32-bit float + F32, + /// 64-bit float + F64, + /// 128-bit SIMD register + V128, +} + +impl Deserialize for ValueType { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let val = VarInt7::deserialize(reader)?; + + match val.into() { + -0x01 => Ok(ValueType::I32), + -0x02 => Ok(ValueType::I64), + -0x03 => Ok(ValueType::F32), + -0x04 => Ok(ValueType::F64), + -0x05 => Ok(ValueType::V128), + _ => Err(Error::UnknownValueType(val.into())), + } + } +} + +impl Serialize for ValueType { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + let val: VarInt7 = match self { + ValueType::I32 => -0x01, + ValueType::I64 => -0x02, + ValueType::F32 => -0x03, + ValueType::F64 => -0x04, + ValueType::V128 => -0x05, + }.into(); + val.serialize(writer)?; + Ok(()) + } +} + +impl fmt::Display for ValueType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + ValueType::I32 => write!(f, "i32"), + ValueType::I64 => write!(f, "i64"), + ValueType::F32 => write!(f, "f32"), + ValueType::F64 => write!(f, "f64"), + ValueType::V128 => write!(f, "v128"), + } + } +} + +/// Block type which is basically `ValueType` + NoResult (to define blocks that have no return type) +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum BlockType { + /// Value-type specified block type + Value(ValueType), + /// No specified block type + NoResult, +} + +impl Deserialize for BlockType { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let val = VarInt7::deserialize(reader)?; + + match val.into() { + -0x01 => Ok(BlockType::Value(ValueType::I32)), + -0x02 => Ok(BlockType::Value(ValueType::I64)), + -0x03 => Ok(BlockType::Value(ValueType::F32)), + -0x04 => Ok(BlockType::Value(ValueType::F64)), + 0x7b => Ok(BlockType::Value(ValueType::V128)), + -0x40 => Ok(BlockType::NoResult), + _ => Err(Error::UnknownValueType(val.into())), + } + } +} + +impl Serialize for BlockType { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + let val: VarInt7 = match self { + BlockType::NoResult => -0x40i8, + BlockType::Value(ValueType::I32) => -0x01, + BlockType::Value(ValueType::I64) => -0x02, + BlockType::Value(ValueType::F32) => -0x03, + BlockType::Value(ValueType::F64) => -0x04, + BlockType::Value(ValueType::V128) => 0x7b, + }.into(); + val.serialize(writer)?; + Ok(()) + } +} + +/// Function signature type. +#[derive(Debug, Clone, PartialEq, Hash, Eq)] +pub struct FunctionType { + form: u8, + params: Vec, + return_type: Option, +} + +impl Default for FunctionType { + fn default() -> Self { + FunctionType { + form: 0x60, + params: Vec::new(), + return_type: None, + } + } +} + +impl FunctionType { + /// New function type given the signature in-params(`params`) and return type (`return_type`) + pub fn new(params: Vec, return_type: Option) -> Self { + FunctionType { + params: params, + return_type: return_type, + ..Default::default() + } + } + /// Function form (currently only valid value is `0x60`) + pub fn form(&self) -> u8 { self.form } + /// Parameters in the function signature. + pub fn params(&self) -> &[ValueType] { &self.params } + /// Mutable parameters in the function signature. + pub fn params_mut(&mut self) -> &mut Vec { &mut self.params } + /// Return type in the function signature, if any. + pub fn return_type(&self) -> Option { self.return_type } + /// Mutable type in the function signature, if any. + pub fn return_type_mut(&mut self) -> &mut Option { &mut self.return_type } +} + +impl Deserialize for FunctionType { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let form: u8 = VarUint7::deserialize(reader)?.into(); + + if form != 0x60 { + return Err(Error::UnknownFunctionForm(form)); + } + + let params: Vec = CountedList::deserialize(reader)?.into_inner(); + + let return_types: u32 = VarUint32::deserialize(reader)?.into(); + + let return_type = if return_types == 1 { + Some(ValueType::deserialize(reader)?) + } else if return_types == 0 { + None + } else { + return Err(Error::Other("Return types length should be 0 or 1")); + }; + + Ok(FunctionType { + form: form, + params: params, + return_type: return_type, + }) + } +} + +// impl Serialize for FunctionType { +// type Error = Error; + +// fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { +// VarUint7::from(self.form).serialize(writer)?; + +// let data = self.params; +// let counted_list = CountedListWriter::( +// data.len(), +// data.into_iter().map(Into::into), +// ); +// counted_list.serialize(writer)?; + +// if let Some(return_type) = self.return_type { +// VarUint1::from(true).serialize(writer)?; +// return_type.serialize(writer)?; +// } else { +// VarUint1::from(false).serialize(writer)?; +// } + +// Ok(()) +// } +// } + +/// Table element type. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum TableElementType { + /// A reference to a function with any signature. + AnyFunc, +} + +impl Deserialize for TableElementType { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let val = VarInt7::deserialize(reader)?; + + match val.into() { + -0x10 => Ok(TableElementType::AnyFunc), + _ => Err(Error::UnknownTableElementType(val.into())), + } + } +} + +// impl Serialize for TableElementType { +// type Error = Error; + +// fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { +// let val: VarInt7 = match self { +// TableElementType::AnyFunc => -0x10, +// }.into(); +// val.serialize(writer)?; +// Ok(()) +// } +// } From 78b9d9086d5a33817d85c550fe7bf15e5e531bc5 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 16:19:24 +1000 Subject: [PATCH 04/22] wasm-parser: build and link with kernel --- kernel-ewasm/src/lib.rs | 20 +-- kernel-ewasm/validator/src/func.rs | 125 ++++++++++++++++ kernel-ewasm/validator/src/instructions.rs | 156 ++++++++++---------- kernel-ewasm/validator/src/io.rs | 7 +- kernel-ewasm/validator/src/lib.rs | 121 ++++++++++----- kernel-ewasm/validator/src/primitives.rs | 1 + kernel-ewasm/validator/src/serialization.rs | 3 + kernel-ewasm/validator/src/types.rs | 7 +- 8 files changed, 310 insertions(+), 130 deletions(-) create mode 100644 kernel-ewasm/validator/src/func.rs diff --git a/kernel-ewasm/src/lib.rs b/kernel-ewasm/src/lib.rs index c1851da..e7c1848 100644 --- a/kernel-ewasm/src/lib.rs +++ b/kernel-ewasm/src/lib.rs @@ -44,7 +44,7 @@ pub mod token { use pwasm_ethereum; use pwasm_abi::types::*; // use parity_wasm::elements::{Module}; - use validator::{Validity, Module, deserialize_buffer}; + use validator::{Validity}; // eth_abi is a procedural macros https://doc.rust-lang.org/book/first-edition/procedural-macros.html @@ -136,16 +136,16 @@ pub mod token { // data section. let big_code_slice = &[0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0B, 0x07, 0x01, 0x00, 0x41, 0x01, 0x0B, 0x01, 0x54, 0x00, 0x08, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x02, 0x01, 0x00]; // Next we deserialise the code from Vec into a Module. - let module: Module = match deserialize_buffer(code.as_slice()) { - // let module: Module = match deserialize_buffer(code_slice) { - Ok(module) => module, - // If we are unable to decode the contract, we assume it is - // not valid, but for now we will panic for testing - // purposes. - Err(_) => panic!("invalid wasm module"), - }; + // let module: Module = match deserialize_buffer(code.as_slice()) { + // // let module: Module = match deserialize_buffer(code_slice) { + // Ok(module) => module, + // // If we are unable to decode the contract, we assume it is + // // not valid, but for now we will panic for testing + // // purposes. + // Err(_) => panic!("invalid wasm module"), + // }; // // Then we perform a boolen is_valid() check. - module.is_valid(); + code.as_slice().is_valid(); false } } diff --git a/kernel-ewasm/validator/src/func.rs b/kernel-ewasm/validator/src/func.rs new file mode 100644 index 0000000..aba081a --- /dev/null +++ b/kernel-ewasm/validator/src/func.rs @@ -0,0 +1,125 @@ +use crate::io; +// mod primitives; +use crate::{ + Serialize, Deserialize, + Uint8, VarUint32, CountedList, + Uint32, Uint64, + VarInt32, VarInt64, +}; +use crate::types::ValueType; +use crate::instructions::{Instructions}; +use crate::types::{BlockType}; +use crate::serialization::{Error}; +use pwasm_std::vec::Vec; +use pwasm_std::String; + +/// Function signature (type reference) +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Func(u32); + +impl Func { + /// New function signature + pub fn new(type_ref: u32) -> Self { Func(type_ref) } + + /// Function signature type reference. + pub fn type_ref(&self) -> u32 { + self.0 + } + + /// Function signature type reference (mutable). + pub fn type_ref_mut(&mut self) -> &mut u32 { + &mut self.0 + } +} + +// impl Deserialize for Func { +// type Error = Error; + +// fn deserialize(reader: &mut R) -> Result { +// Ok(Func(VarUint32::deserialize(reader)?.into())) +// } +// } + +/// Local definition inside the function body. +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Local { + count: u32, + value_type: ValueType, +} + +impl Local { + /// New local with `count` and `value_type`. + pub fn new(count: u32, value_type: ValueType) -> Self { + Local { count: count, value_type: value_type } + } + + /// Number of locals with the shared type. + pub fn count(&self) -> u32 { self.count } + + /// Type of the locals. + pub fn value_type(&self) -> ValueType { self.value_type } +} + +impl Deserialize for Local { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let count = VarUint32::deserialize(reader)?; + let value_type = ValueType::deserialize(reader)?; + Ok(Local { count: count.into(), value_type: value_type }) + } +} + +/// Function body definition. +#[derive(Debug, Clone, PartialEq)] +pub struct FuncBody { + locals: Vec, + instructions: Instructions, +} + +impl FuncBody { + /// New function body with given `locals` and `instructions`. + pub fn new(locals: Vec, instructions: Instructions) -> Self { + FuncBody { locals: locals, instructions: instructions } + } + + /// List of individual instructions. + pub fn empty() -> Self { + FuncBody { locals: Vec::new(), instructions: Instructions::empty() } + } + + /// Locals declared in function body. + pub fn locals(&self) -> &[Local] { &self.locals } + + /// Instruction list of the function body. Minimal instruction list + /// + /// is just `&[Instruction::End]` + pub fn code(&self) -> &Instructions { &self.instructions } + + /// Locals declared in function body (mutable). + pub fn locals_mut(&mut self) -> &mut Vec { &mut self.locals } + + /// Instruction list of the function body (mutable). + pub fn code_mut(&mut self) -> &mut Instructions { &mut self.instructions } +} + +// impl Deserialize for FuncBody { +// type Error = Error; + +// fn deserialize(reader: &mut R) -> Result { +// // Why do we need to use a section reader here? +// let mut body_reader = SectionReader::new(reader)?; +// let locals: Vec = CountedList::::deserialize(&mut body_reader)?.into_inner(); + +// // The specification obliges us to count the total number of local variables while +// // decoding the binary format. +// locals +// .iter() +// .try_fold(0u32, |acc, &Local { count, .. }| acc.checked_add(count)) +// .ok_or_else(|| Error::TooManyLocals)?; + +// let instructions = Instructions::deserialize(&mut body_reader)?; +// body_reader.close()?; +// Ok(FuncBody { locals: locals, instructions: instructions }) +// } +// } diff --git a/kernel-ewasm/validator/src/instructions.rs b/kernel-ewasm/validator/src/instructions.rs index 9efeac9..5067e40 100644 --- a/kernel-ewasm/validator/src/instructions.rs +++ b/kernel-ewasm/validator/src/instructions.rs @@ -9,6 +9,8 @@ use pwasm_std; // use parity_wasm::elements::{ValueType}; use pwasm_std::vec::Vec; +use pwasm_std::String; +use pwasm_std::Box; // use crate::rust::{fmt, vec::Vec, boxed::Box}; use crate::io; @@ -22,99 +24,99 @@ use crate::{ use crate::types::{BlockType}; use crate::serialization::{Error}; -// /// List of instructions (usually inside a block section). -// #[derive(Debug, Clone, PartialEq)] -// pub struct Instructions(Vec); +/// List of instructions (usually inside a block section). +#[derive(Debug, Clone, PartialEq)] +pub struct Instructions(Vec); -// impl Instructions { -// /// New list of instructions from vector of instructions. -// pub fn new(elements: Vec) -> Self { -// Instructions(elements) -// } +impl Instructions { + /// New list of instructions from vector of instructions. + pub fn new(elements: Vec) -> Self { + Instructions(elements) + } -// /// Empty expression with only `Instruction::End` instruction. -// pub fn empty() -> Self { -// Instructions(vec![Instruction::End]) -// } + /// Empty expression with only `Instruction::End` instruction. + pub fn empty() -> Self { + Instructions(vec![Instruction::End]) + } -// /// List of individual instructions. -// pub fn elements(&self) -> &[Instruction] { &self.0 } + /// List of individual instructions. + pub fn elements(&self) -> &[Instruction] { &self.0 } -// /// Individual instructions, mutable. -// pub fn elements_mut(&mut self) -> &mut Vec { &mut self.0 } -// } + /// Individual instructions, mutable. + pub fn elements_mut(&mut self) -> &mut Vec { &mut self.0 } +} -// impl Deserialize for Instructions { -// type Error = Error; +impl Deserialize for Instructions { + type Error = Error; -// fn deserialize(reader: &mut R) -> Result { -// let mut instructions = Vec::new(); -// let mut block_count = 1usize; - -// loop { -// let instruction = Instruction::deserialize(reader)?; -// if instruction.is_terminal() { -// block_count -= 1; -// } else if instruction.is_block() { -// block_count = block_count.checked_add(1).ok_or(Error::Other("too many instructions"))?; -// } - -// instructions.push(instruction); -// if block_count == 0 { -// break; -// } -// } + fn deserialize(reader: &mut R) -> Result { + let mut instructions = Vec::new(); + let mut block_count = 1usize; + + loop { + let instruction = Instruction::deserialize(reader)?; + if instruction.is_terminal() { + block_count -= 1; + } else if instruction.is_block() { + block_count = block_count.checked_add(1).ok_or(Error::Other("too many instructions"))?; + } -// Ok(Instructions(instructions)) -// } -// } + instructions.push(instruction); + if block_count == 0 { + break; + } + } -// /// Initialization expression. -// #[derive(Debug, Clone, PartialEq)] -// pub struct InitExpr(Vec); + Ok(Instructions(instructions)) + } +} -// impl InitExpr { -// /// New initialization expression from instruction list. -// /// -// /// `code` must end with the `Instruction::End` instruction! -// pub fn new(code: Vec) -> Self { -// InitExpr(code) -// } +/// Initialization expression. +#[derive(Debug, Clone, PartialEq)] +pub struct InitExpr(Vec); -// /// Empty expression with only `Instruction::End` instruction. -// pub fn empty() -> Self { -// InitExpr(vec![Instruction::End]) -// } +impl InitExpr { + /// New initialization expression from instruction list. + /// + /// `code` must end with the `Instruction::End` instruction! + pub fn new(code: Vec) -> Self { + InitExpr(code) + } -// /// List of instructions used in the expression. -// pub fn code(&self) -> &[Instruction] { -// &self.0 -// } + /// Empty expression with only `Instruction::End` instruction. + pub fn empty() -> Self { + InitExpr(vec![Instruction::End]) + } -// /// List of instructions used in the expression. -// pub fn code_mut(&mut self) -> &mut Vec { -// &mut self.0 -// } -// } + /// List of instructions used in the expression. + pub fn code(&self) -> &[Instruction] { + &self.0 + } -// impl Deserialize for InitExpr { -// type Error = Error; + /// List of instructions used in the expression. + pub fn code_mut(&mut self) -> &mut Vec { + &mut self.0 + } +} -// fn deserialize(reader: &mut R) -> Result { -// let mut instructions = Vec::new(); +impl Deserialize for InitExpr { + type Error = Error; -// loop { -// let instruction = Instruction::deserialize(reader)?; -// let is_terminal = instruction.is_terminal(); -// instructions.push(instruction); -// if is_terminal { -// break; -// } -// } + fn deserialize(reader: &mut R) -> Result { + let mut instructions = Vec::new(); + + loop { + let instruction = Instruction::deserialize(reader)?; + let is_terminal = instruction.is_terminal(); + instructions.push(instruction); + if is_terminal { + break; + } + } -// Ok(InitExpr(instructions)) -// } -// } + Ok(InitExpr(instructions)) + } +} /// Instruction. #[derive(Clone, Debug, PartialEq, Eq, Hash)] diff --git a/kernel-ewasm/validator/src/io.rs b/kernel-ewasm/validator/src/io.rs index 1c13cbd..e9ee937 100644 --- a/kernel-ewasm/validator/src/io.rs +++ b/kernel-ewasm/validator/src/io.rs @@ -6,7 +6,10 @@ // use crate::rust::result; // #[cfg(feature="std")] -use std::io; +// use std::io; + +use pwasm_std::vec::Vec; +use pwasm_std::String; // #[cfg(not(feature="std"))] // use crate::rust::vec::Vec; @@ -28,7 +31,7 @@ pub enum Error { } /// IO specific Result. -pub type Result = std::result::Result; +pub type Result = core::result::Result; pub trait Write { /// Write a buffer of data into this write. diff --git a/kernel-ewasm/validator/src/lib.rs b/kernel-ewasm/validator/src/lib.rs index 375806b..8a0a0f7 100644 --- a/kernel-ewasm/validator/src/lib.rs +++ b/kernel-ewasm/validator/src/lib.rs @@ -1,4 +1,10 @@ -// #![no_std] +#![cfg_attr(not(feature = "std"), no_std)] + +#![cfg_attr(not(feature = "std"), feature(alloc))] + +#[cfg(not(feature="std"))] +#[macro_use] +extern crate alloc; use pwasm_std; // use parity_wasm; @@ -8,13 +14,15 @@ use pwasm_std; // use parity_wasm::elements::{ValueType}; use pwasm_std::vec::Vec; +use pwasm_std::String; mod instructions; +pub mod func; mod primitives; pub mod io; pub mod serialization; pub mod types; - +use io::Read; pub use self::io::{Error}; pub use self::serialization::{Serialize, Deserialize}; @@ -190,9 +198,9 @@ impl Validity for &[u8] { // data: self, }; if self.len() < 100 { - println!("data: {:?}", &self); + // println!("data: {:?}", &self); } else { - println!("data: {:?}", &self[0..100]); + // println!("data: {:?}", &self[0..100]); } // Take the magic number, check that it matches if cursor.read_n(4, &self) != &[0, 97, 115, 109] { @@ -218,7 +226,7 @@ impl Validity for &[u8] { // let section: Section = parse_section(&mut i, &self[d..]); // println!("i: {:?}", cursor.i); let section: Section = parse_section(&mut cursor, &self); - println!("section: {:?}: index: {}", section.type_, section.offset); + // println!("section: {:?}: index: {}", section.type_, section.offset); // There are many section types we don't care about, for example, // Custom sections generally contain debugging symbols and // meaningful function names which are irrelevant to the current @@ -261,7 +269,7 @@ impl Validity for &[u8] { let section_size = parse_varuint_32(&mut imports_cursor, &self); // How many imports do we have? let n_imports = parse_varuint_32(&mut imports_cursor, &self); - println!("n_imports: {}", n_imports); + // println!("n_imports: {}", n_imports); for i in 0..n_imports { // let mut cursor = Cursor {i:0}; @@ -269,8 +277,8 @@ impl Validity for &[u8] { // index. let import = parse_import(&mut imports_cursor, &self, i); - println!("mod_name: {}, field_name: {}, f_index: {}, listing: {:?}", - import.mod_name, import.field_name, import.index, import.listing()); + // println!("mod_name: {}, field_name: {}, f_index: {}, listing: {:?}", + // import.mod_name, import.field_name, import.index, import.listing()); match import.listing() { Listing::White => (), Listing::Grey => { @@ -281,8 +289,8 @@ impl Validity for &[u8] { Listing::Black => { // If we encounter a blacklisted import we can return // early. - println!("{:?} is blacklisted", import); - // return false; + // println!("{:?} is blacklisted", import); + return false; }, } } @@ -298,13 +306,13 @@ impl Validity for &[u8] { // We will have to try and update these in parallel let function_section_size = parse_varuint_32(&mut functions_cursor, &self); let code_section_size = parse_varuint_32(&mut code_cursor, &self); - println!("functions_offset: {:?}", functions_offset); - println!("code_offset: {:?}", code_offset); + // println!("functions_offset: {:?}", functions_offset); + // println!("code_offset: {:?}", code_offset); let n_functions = parse_varuint_32(&mut functions_cursor, &self); let n_bodies = parse_varuint_32(&mut code_cursor, &self); - println!("functions_size: {:?}", function_section_size); - println!("code_size: {:?}", code_section_size); + // println!("functions_size: {:?}", function_section_size); + // println!("code_size: {:?}", code_section_size); assert_eq!(n_functions,n_bodies); @@ -318,7 +326,7 @@ impl Validity for &[u8] { continue; } // let body = parse_varuint_32(&mut code_cursor, &self); - println!("function[{}] is {} bytes", i, body_size); + // println!("function[{}] is {} bytes", i, body_size); code_cursor.skip(body_size as usize); // As the function is not a system call, it is not permitted to // have a dcall in it, so we iterate through all the @@ -415,7 +423,7 @@ fn parse_section(cursor: &mut Cursor, data: &[u8]) -> Section { let offset = cursor.i; // println!("type_n: {:?}", type_n); let size_n = parse_varuint_32(cursor, data); - println!("size_n: {:?}", size_n); + // println!("size_n: {:?}", size_n); let type_ = n_to_section(type_n); let section = Section { type_, @@ -469,7 +477,7 @@ fn parse_import(cursor: &mut Cursor, data: &[u8], index: u32) -> ImportEntry { // Both mod_name and field_name are *names* which are vectors of bytes (UTF-8). let mod_name = parse_name(cursor, data); let field_name = parse_name(cursor, data); - println!("mod_name: {}, field_name: {}", mod_name, field_name); + // println!("mod_name: {}, field_name: {}", mod_name, field_name); // Parse the import description, we don't care about it at this stage so we // ignore it. We still need to call this in order to skip over the data. let _type_spec = parse_type_spec(cursor, data); @@ -675,16 +683,45 @@ struct Code<'a> { // `count` at zero, we'll see why in `next()`'s implementation below. impl<'a> Code<'a> { fn new(body: &'a [u8]) -> Code { - Code { + let mut reader = CodeCursor { current_offset: 0, body: body, + }; + let locals: Vec = CountedList::::deserialize(&mut reader).expect("counted list").into_inner(); + // println!("locals: {:?}", locals); + Code { + current_offset: reader.current_offset, + body: body, } } } +struct CodeCursor<'a> { + current_offset: usize, + body: &'a [u8], +} + +impl<'a> io::Read for CodeCursor<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result<()> { + let actual_self = &self.body[self.current_offset..]; + let amt = core::cmp::min(buf.len(), actual_self.len()); + let (a, b) = actual_self.split_at(amt); + + if amt == 1 { + buf[0] = a[0]; + } else { + buf[..amt].copy_from_slice(a); + } + + self.current_offset += amt; + Ok(()) + } +} + + impl<'a> Iterator for Code<'a> { // we will be counting with usize - type Item = u8; + type Item = crate::instructions::Instruction; // next() is the only required method fn next(&mut self) -> Option { @@ -693,8 +730,12 @@ impl<'a> Iterator for Code<'a> { // Check to see if we've finished counting or not. if self.current_offset < self.body.len() { // We need to parse the code into something meaningful - let val = Some(self.body[self.current_offset]); - self.current_offset += 1; + let mut reader = CodeCursor { + current_offset: self.current_offset, + body: self.body, + }; + let val = Some(crate::instructions::Instruction::deserialize(&mut reader).expect("expected valid instruction")); + self.current_offset = reader.current_offset; val } else { None @@ -702,27 +743,30 @@ impl<'a> Iterator for Code<'a> { } } +// TODO: we need to provide the indices of the various necessary functions for +// the system call. pub fn is_syscall(body: &[u8]) -> bool { + // println!("body: {:?}", body); let code_iter = Code::new(body); - for (i,d) in code_iter.enumerate() { - println!("code_iter[{}]: {:#x}", i, d); + let mut indexed_iter = code_iter.enumerate(); + + // First we need to check that the instructions are correct, that is: + // 0. call $a + // 1. call $b + // 2. get_local 0 + // 3. get_local 1 + // 4. get_local 2 + // 5. get_local 3 + // 6. call $c + // $a, $b, and $c will be used later. + + + // 0. call gasleft + if let Some((instr_index, instructions::Instruction::Call(f_ind))) = indexed_iter.next() { + // Check that f_ind is the function index of "gasleft" + // println!("call_index: {}", f_ind); } - // // First we need to check that the instructions are correct, that is: - // // 0. call $a - // // 1. call $b - // // 2. get_local 0 - // // 3. get_local 1 - // // 4. get_local 2 - // // 5. get_local 3 - // // 6. call $c - // // $a, $b, and $c will be used later. - // // First we simply check the length - // if instructions.len() != 8 { - // return false; - // } - // // 0. call gasleft // if let Instruction::Call(f_ind) = instructions[0] { - // // Check that f_ind is the function index of "gasleft" // let gasleft_index = find_import(module, "env", "gasleft"); // if Some(f_ind) != gasleft_index { // return false; @@ -838,7 +882,6 @@ mod tests { let mut f = File::open("../example_contract_1/target/wasm32-unknown-unknown/release/example_contract_1.wasm").expect("could not open file"); let mut wasm = Vec::new(); f.read_to_end(&mut wasm).unwrap(); - println!("big example", ); assert!(!wasm.as_slice().is_valid()); } diff --git a/kernel-ewasm/validator/src/primitives.rs b/kernel-ewasm/validator/src/primitives.rs index 8e6d195..79bd589 100644 --- a/kernel-ewasm/validator/src/primitives.rs +++ b/kernel-ewasm/validator/src/primitives.rs @@ -3,6 +3,7 @@ use crate::{io}; use crate::{Deserialize, Serialize}; use pwasm_std::vec::Vec; +use pwasm_std::String; use crate::serialization::{Error}; use crate::serialization::{deserialize_buffer}; diff --git a/kernel-ewasm/validator/src/serialization.rs b/kernel-ewasm/validator/src/serialization.rs index 9cad144..8bcc7a5 100644 --- a/kernel-ewasm/validator/src/serialization.rs +++ b/kernel-ewasm/validator/src/serialization.rs @@ -1,6 +1,9 @@ use crate::{io}; use crate::primitives::*; pub use core::fmt; +use pwasm_std::vec::{Vec}; + +use pwasm_std::String; /// Deserialization from serial i/o. pub trait Deserialize : Sized { diff --git a/kernel-ewasm/validator/src/types.rs b/kernel-ewasm/validator/src/types.rs index ee9d990..af8ddfa 100644 --- a/kernel-ewasm/validator/src/types.rs +++ b/kernel-ewasm/validator/src/types.rs @@ -1,6 +1,7 @@ // use crate::rust::{fmt, vec::Vec}; pub use core::fmt; use pwasm_std::vec::Vec; +use pwasm_std::String; use crate::io; use super::{ Deserialize, Serialize, VarUint7, VarInt7, VarUint1, CountedList, @@ -60,7 +61,8 @@ impl Deserialize for ValueType { -0x03 => Ok(ValueType::F32), -0x04 => Ok(ValueType::F64), -0x05 => Ok(ValueType::V128), - _ => Err(Error::UnknownValueType(val.into())), + // _ => Err(Error::UnknownValueType(val.into())), + _ => panic!("unknown value type") } } } @@ -115,7 +117,8 @@ impl Deserialize for BlockType { -0x04 => Ok(BlockType::Value(ValueType::F64)), 0x7b => Ok(BlockType::Value(ValueType::V128)), -0x40 => Ok(BlockType::NoResult), - _ => Err(Error::UnknownValueType(val.into())), + // _ => Err(Error::UnknownValueType(val.into())), + _ => panic!("unknown value type") } } } From 6a8676b25c59dcc893f4beaa1d25205e6dc31eda Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 16:43:30 +1000 Subject: [PATCH 05/22] wasm-parser: fix parsing of import entries --- kernel-ewasm/Cargo.toml | 1 + kernel-ewasm/build.bat | 2 +- kernel-ewasm/build.sh | 2 +- kernel-ewasm/tests/integration/index.js | 2 +- kernel-ewasm/validator/src/instructions.rs | 11 +-- kernel-ewasm/validator/src/io.rs | 4 +- kernel-ewasm/validator/src/lib.rs | 80 +++------------------- 7 files changed, 15 insertions(+), 87 deletions(-) diff --git a/kernel-ewasm/Cargo.toml b/kernel-ewasm/Cargo.toml index 8addefb..a62f4a6 100644 --- a/kernel-ewasm/Cargo.toml +++ b/kernel-ewasm/Cargo.toml @@ -26,6 +26,7 @@ crate-type = ["cdylib"] [features] default = ["std"] std = ["pwasm-std/std", "pwasm-ethereum/std", "pwasm-test/std"] +panic_with_msg = ["pwasm-std/panic_with_msg"] [profile.release] panic = "abort" diff --git a/kernel-ewasm/build.bat b/kernel-ewasm/build.bat index ee62b43..af141fd 100644 --- a/kernel-ewasm/build.bat +++ b/kernel-ewasm/build.bat @@ -6,7 +6,7 @@ cargo install --path ..\cap9-build --bin cap9-build --force set contract_name=kernel_ewasm -cargo build --release --target wasm32-unknown-unknown --no-default-features +cargo build --release --target wasm32-unknown-unknown --no-default-features --features "panic_with_msg" cap9-build set-mem --pages 3 .\target\wasm32-unknown-unknown\release\%contract_name%.wasm .\target\wasm32-unknown-unknown\release\%contract_name%.wasm wasm-build --target=wasm32-unknown-unknown .\target kernel-ewasm REM ..\..\wasm-utils\target\debug\wasm-build.exe --target=wasm32-unknown-unknown .\target kernel-ewasm diff --git a/kernel-ewasm/build.sh b/kernel-ewasm/build.sh index 41ddacd..fa12228 100755 --- a/kernel-ewasm/build.sh +++ b/kernel-ewasm/build.sh @@ -4,7 +4,7 @@ rustup target add wasm32-unknown-unknown cargo install pwasm-utils-cli --bin wasm-build --version 0.6.0 cargo install --path ../cap9-build --bin cap9-build --force -cargo build --release --target wasm32-unknown-unknown --no-default-features +cargo build --release --target wasm32-unknown-unknown --no-default-features --features "panic_with_msg" cap9-build set-mem --pages 3 ./target/wasm32-unknown-unknown/release/kernel_ewasm.wasm ./target/wasm32-unknown-unknown/release/kernel_ewasm.wasm wasm-build --target=wasm32-unknown-unknown ./target kernel-ewasm diff --git a/kernel-ewasm/tests/integration/index.js b/kernel-ewasm/tests/integration/index.js index e3d018c..102b7ad 100644 --- a/kernel-ewasm/tests/integration/index.js +++ b/kernel-ewasm/tests/integration/index.js @@ -201,7 +201,7 @@ describe('Kernel', function() { const code = web3.utils.hexToBytes(code_hex); assert.strictEqual(code_size, code.length, "The code length should be as given by EXTCODESIZE"); let rec_validation = await kernel.methods.check_contract(contract.address).call(); - assert.strictEqual(rec_validation, true); + assert.strictEqual(rec_validation, false); }) }) }) diff --git a/kernel-ewasm/validator/src/instructions.rs b/kernel-ewasm/validator/src/instructions.rs index 5067e40..9e7b963 100644 --- a/kernel-ewasm/validator/src/instructions.rs +++ b/kernel-ewasm/validator/src/instructions.rs @@ -1,20 +1,10 @@ // This file is based on parity-wasm from parity, MIT & Apache Licensed - - use pwasm_std; -// use parity_wasm; - -// pub use parity_wasm::elements::{ImportEntry, Module}; -// use parity_wasm::elements::Instruction; -// use parity_wasm::elements::{ValueType}; - use pwasm_std::vec::Vec; use pwasm_std::String; use pwasm_std::Box; -// use crate::rust::{fmt, vec::Vec, boxed::Box}; use crate::io; -// mod primitives; use crate::{ Serialize, Deserialize, Uint8, VarUint32, CountedList, @@ -589,6 +579,7 @@ impl Instruction { } #[allow(missing_docs)] +#[allow(dead_code)] pub mod opcodes { pub const UNREACHABLE: u8 = 0x00; pub const NOP: u8 = 0x01; diff --git a/kernel-ewasm/validator/src/io.rs b/kernel-ewasm/validator/src/io.rs index e9ee937..cfb437e 100644 --- a/kernel-ewasm/validator/src/io.rs +++ b/kernel-ewasm/validator/src/io.rs @@ -5,8 +5,8 @@ // use crate::rust::result; -// #[cfg(feature="std")] -// use std::io; +#[cfg(feature="std")] +use std::io; use pwasm_std::vec::Vec; use pwasm_std::String; diff --git a/kernel-ewasm/validator/src/lib.rs b/kernel-ewasm/validator/src/lib.rs index 8a0a0f7..369dd90 100644 --- a/kernel-ewasm/validator/src/lib.rs +++ b/kernel-ewasm/validator/src/lib.rs @@ -21,6 +21,7 @@ pub mod func; mod primitives; pub mod io; pub mod serialization; +pub mod import_entry; pub mod types; use io::Read; pub use self::io::{Error}; @@ -72,24 +73,6 @@ pub trait Listed { fn listing(&self) -> Listing; } -// A webassembly module is a series of sections. From reading the spec it seems -// that each section can occur only once, except for the custom sections, of -// which there may be multiple. -// struct Module { -// custom_sections: Vec
, -// Type, -// Import, -// Function, -// Table, -// Memory, -// Global, -// Export, -// Start, -// Element, -// Code, -// Data, -// } - #[derive(Debug, Clone)] pub struct ImportEntry { index: u32, @@ -473,65 +456,18 @@ fn parse_varuint_32(cursor: &mut Cursor, data: &[u8]) -> u32 { } fn parse_import(cursor: &mut Cursor, data: &[u8], index: u32) -> ImportEntry { - // An import comes in 3 sections, mod_name, field_name, and importdesc. - // Both mod_name and field_name are *names* which are vectors of bytes (UTF-8). - let mod_name = parse_name(cursor, data); - let field_name = parse_name(cursor, data); - // println!("mod_name: {}, field_name: {}", mod_name, field_name); - // Parse the import description, we don't care about it at this stage so we - // ignore it. We still need to call this in order to skip over the data. - let _type_spec = parse_type_spec(cursor, data); + let mut reader = CodeCursor { + current_offset: cursor.i, + body: data, + }; + let import: import_entry::ImportEntry = import_entry::ImportEntry::deserialize(&mut reader).expect("counted list"); ImportEntry { index, - mod_name, - field_name, - } -} - - -/// A type is a 'kind' specifier (0,3) followed by an index. Don't return -/// anything for now. -fn parse_type_spec(cursor: &mut Cursor, data: &[u8]) { - // Just read a single byte as the kind specifier. - let kind = cursor.read(data); - // Currently we only support typeids (0x00) so panic on anything else. - match kind { - 0x00 => (), - _ => panic!("unsupported type spec: {}", kind), + mod_name: String::from(import.module()), + field_name: String::from(import.field()), } - let type_index = parse_varuint_32(cursor, data); - -} - -fn parse_name(cursor: &mut Cursor, data: &[u8]) -> String { - let length = parse_varuint_32(cursor, data); - let string_slice: &[u8] = &data[(cursor.i)..(cursor.i+length as usize)]; - cursor.i += length as usize; - String::from_utf8(string_slice.into()).unwrap() } -fn parse_vec_imports(data: &[u8]) -> Vec { - let mut cursor = Cursor {i:0}; - // The length is the number of encoded elements (as opposed to bytes) - let length = parse_varuint_32(&mut cursor, data); - let mut elems = Vec::new(); - for n in 0..length { - let entry = parse_import(&mut cursor, data, n); - elems.push(entry); - } - elems -} - -/// This is our desrialisation trait. -// trait WasmDeserialize { -// fn deserialize(data: &[u8]) -> Self; -// } - -// impl WasmDeserialize for char { - -// } - - // fn get_imports(module: &Module) -> Vec { // if let Some(import_section) = module.import_section() { // import_section.entries().to_vec() From 24ff9788bc89ff79f8ee173577f9554a076856bb Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 16:51:06 +1000 Subject: [PATCH 06/22] wasm-parser: add missing file --- kernel-ewasm/validator/src/import_entry.rs | 262 +++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 kernel-ewasm/validator/src/import_entry.rs diff --git a/kernel-ewasm/validator/src/import_entry.rs b/kernel-ewasm/validator/src/import_entry.rs new file mode 100644 index 0000000..c758725 --- /dev/null +++ b/kernel-ewasm/validator/src/import_entry.rs @@ -0,0 +1,262 @@ +use pwasm_std; +use pwasm_std::vec::Vec; +use pwasm_std::String; +use pwasm_std::Box; + +use crate::io; +use crate::{ + Serialize, Deserialize, + Uint8, VarUint32, CountedList, + Uint32, Uint64, CountedListWriter, + VarInt32, VarInt64, VarInt7, VarUint1, VarUint7 +}; +use crate::types::{BlockType, TableElementType, ValueType}; +use crate::serialization::{Error}; + +const FLAG_HAS_MAX: u8 = 0x01; +const FLAG_SHARED: u8 = 0x02; + +/// Global definition struct +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct GlobalType { + content_type: ValueType, + is_mutable: bool, +} + +impl GlobalType { + /// New global type + pub fn new(content_type: ValueType, is_mutable: bool) -> Self { + GlobalType { + content_type: content_type, + is_mutable: is_mutable, + } + } + + /// Type of the global entry + pub fn content_type(&self) -> ValueType { self.content_type } + + /// Is global entry is declared as mutable + pub fn is_mutable(&self) -> bool { self.is_mutable } +} + +impl Deserialize for GlobalType { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let content_type = ValueType::deserialize(reader)?; + let is_mutable = VarUint1::deserialize(reader)?; + Ok(GlobalType { + content_type: content_type, + is_mutable: is_mutable.into(), + }) + } +} + +impl Serialize for GlobalType { + type Error = Error; + + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + self.content_type.serialize(writer)?; + VarUint1::from(self.is_mutable).serialize(writer)?; + Ok(()) + } +} + +/// Table entry +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct TableType { + elem_type: TableElementType, + limits: ResizableLimits, +} + +impl TableType { + /// New table definition + pub fn new(min: u32, max: Option) -> Self { + TableType { + elem_type: TableElementType::AnyFunc, + limits: ResizableLimits::new(min, max), + } + } + + /// Table memory specification + pub fn limits(&self) -> &ResizableLimits { &self.limits } + + /// Table element type + pub fn elem_type(&self) -> TableElementType { self.elem_type } +} + +impl Deserialize for TableType { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let elem_type = TableElementType::deserialize(reader)?; + let limits = ResizableLimits::deserialize(reader)?; + Ok(TableType { + elem_type: elem_type, + limits: limits, + }) + } +} + +/// Memory and table limits. +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct ResizableLimits { + initial: u32, + maximum: Option, + shared: bool, +} + +impl ResizableLimits { + /// New memory limits definition. + pub fn new(min: u32, max: Option) -> Self { + ResizableLimits { + initial: min, + maximum: max, + shared: false, + } + } + /// Initial size. + pub fn initial(&self) -> u32 { self.initial } + /// Maximum size. + pub fn maximum(&self) -> Option { self.maximum } + /// Whether or not this is a shared array buffer. + pub fn shared(&self) -> bool { self.shared } +} + +impl Deserialize for ResizableLimits { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let flags: u8 = Uint8::deserialize(reader)?.into(); + match flags { + 0x00 | 0x01 | 0x03 => {}, + _ => return Err(Error::InvalidLimitsFlags(flags)), + } + + let initial = VarUint32::deserialize(reader)?; + let maximum = if flags & FLAG_HAS_MAX != 0 { + Some(VarUint32::deserialize(reader)?.into()) + } else { + None + }; + let shared = flags & FLAG_SHARED != 0; + + Ok(ResizableLimits { + initial: initial.into(), + maximum: maximum, + shared, + }) + } +} + +/// Memory entry. +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct MemoryType(ResizableLimits); + +impl MemoryType { + /// New memory definition + pub fn new(min: u32, max: Option, shared: bool) -> Self { + let mut r = ResizableLimits::new(min, max); + r.shared = shared; + MemoryType(r) + } + + /// Limits of the memory entry. + pub fn limits(&self) -> &ResizableLimits { + &self.0 + } +} + +impl Deserialize for MemoryType { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + Ok(MemoryType(ResizableLimits::deserialize(reader)?)) + } +} + +/// External to local binding. +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum External { + /// Binds to a function whose type is associated with the given index in the + /// type section. + Function(u32), + /// Describes local table definition to be imported as. + Table(TableType), + /// Describes local memory definition to be imported as. + Memory(MemoryType), + /// Describes local global entry to be imported as. + Global(GlobalType), +} + +impl Deserialize for External { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let kind = VarUint7::deserialize(reader)?; + match kind.into() { + 0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())), + 0x01 => Ok(External::Table(TableType::deserialize(reader)?)), + 0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)), + 0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)), + _ => Err(Error::UnknownExternalKind(kind.into())), + } + } +} + +/// Import entry. +#[derive(Debug, Clone, PartialEq)] +pub struct ImportEntry { + module_str: String, + field_str: String, + external: External, +} + +impl ImportEntry { + /// New import entry. + pub fn new(module_str: String, field_str: String, external: External) -> Self { + ImportEntry { + module_str: module_str, + field_str: field_str, + external: external, + } + } + + /// Module reference of the import entry. + pub fn module(&self) -> &str { &self.module_str } + + /// Module reference of the import entry (mutable). + pub fn module_mut(&mut self) -> &mut String { + &mut self.module_str + } + + /// Field reference of the import entry. + pub fn field(&self) -> &str { &self.field_str } + + /// Field reference of the import entry (mutable) + pub fn field_mut(&mut self) -> &mut String { + &mut self.field_str + } + + /// Local binidng of the import entry. + pub fn external(&self) -> &External { &self.external } + + /// Local binidng of the import entry (mutable) + pub fn external_mut(&mut self) -> &mut External { &mut self.external } +} + +impl Deserialize for ImportEntry { + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let module_str = String::deserialize(reader)?; + let field_str = String::deserialize(reader)?; + let external = External::deserialize(reader)?; + + Ok(ImportEntry { + module_str: module_str, + field_str: field_str, + external: external, + }) + } +} From 33e5c354924c9b33840a5433c8320d27c3b88e99 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 17:08:56 +1000 Subject: [PATCH 07/22] kernel: add test script --- kernel-ewasm/test.sh | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 kernel-ewasm/test.sh diff --git a/kernel-ewasm/test.sh b/kernel-ewasm/test.sh new file mode 100644 index 0000000..44f4f42 --- /dev/null +++ b/kernel-ewasm/test.sh @@ -0,0 +1,4 @@ +pushd example_contract_2 +./build.sh +popd +mocha tests/**/**.js From f87d4f520657b6774cbe3c2880b02670ab92a381 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 17:31:39 +1000 Subject: [PATCH 08/22] wasm-parser: minor cleanup --- kernel-ewasm/package.json | 2 +- kernel-ewasm/src/lib.rs | 18 +- kernel-ewasm/validator/Cargo.toml | 7 +- kernel-ewasm/validator/src/func.rs | 105 +- kernel-ewasm/validator/src/import_entry.rs | 363 +- kernel-ewasm/validator/src/instructions.rs | 4280 +++++++------------ kernel-ewasm/validator/src/io.rs | 156 +- kernel-ewasm/validator/src/lib.rs | 133 +- kernel-ewasm/validator/src/primitives.rs | 779 ++-- kernel-ewasm/validator/src/serialization.rs | 351 +- kernel-ewasm/validator/src/types.rs | 318 +- 11 files changed, 2569 insertions(+), 3943 deletions(-) diff --git a/kernel-ewasm/package.json b/kernel-ewasm/package.json index 74b3177..151f515 100644 --- a/kernel-ewasm/package.json +++ b/kernel-ewasm/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "deploy": "node script/deploy.js", - "test": "test.sh" + "test": "sh ./test.sh" }, "author": "", "license": "ISC", diff --git a/kernel-ewasm/src/lib.rs b/kernel-ewasm/src/lib.rs index e7c1848..639f4b9 100644 --- a/kernel-ewasm/src/lib.rs +++ b/kernel-ewasm/src/lib.rs @@ -130,23 +130,7 @@ pub mod token { // Next we get the code of the contract, using EXTCODECOPY under // the hood. let code: pwasm_std::Vec = self.code_copy(target); - // code_slice is magic number and version number only - let code_slice = &[0, 97, 115, 109, 1, 0, 0, 0]; - // big_code_slice is magic number, version number and a simple - // data section. - let big_code_slice = &[0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0B, 0x07, 0x01, 0x00, 0x41, 0x01, 0x0B, 0x01, 0x54, 0x00, 0x08, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x02, 0x01, 0x00]; - // Next we deserialise the code from Vec into a Module. - // let module: Module = match deserialize_buffer(code.as_slice()) { - // // let module: Module = match deserialize_buffer(code_slice) { - // Ok(module) => module, - // // If we are unable to decode the contract, we assume it is - // // not valid, but for now we will panic for testing - // // purposes. - // Err(_) => panic!("invalid wasm module"), - // }; - // // Then we perform a boolen is_valid() check. - code.as_slice().is_valid(); - false + code.as_slice().is_valid() } } diff --git a/kernel-ewasm/validator/Cargo.toml b/kernel-ewasm/validator/Cargo.toml index 8460fcb..7ff6d68 100644 --- a/kernel-ewasm/validator/Cargo.toml +++ b/kernel-ewasm/validator/Cargo.toml @@ -5,20 +5,15 @@ authors = ["Daohub Inc "] edition = "2018" [dependencies] -# parity-wasm = { version = "0.35", default-features = false } pwasm-std = {version = "0.13", default-features = false} pwasm-ethereum = {version = "0.8", default-features = false} [dev-dependencies] wabt = "0.7.1" -[dev-dependencies.pwasm-test] -git = "https://github.com/paritytech/pwasm-test" -default-features = false - [features] default = ["std"] -std = ["pwasm-std/std", "pwasm-ethereum/std", "pwasm-test/std"] +std = ["pwasm-std/std", "pwasm-ethereum/std"] [lib] name = "validator" diff --git a/kernel-ewasm/validator/src/func.rs b/kernel-ewasm/validator/src/func.rs index aba081a..48bc964 100644 --- a/kernel-ewasm/validator/src/func.rs +++ b/kernel-ewasm/validator/src/func.rs @@ -1,35 +1,28 @@ use crate::io; // mod primitives; -use crate::{ - Serialize, Deserialize, - Uint8, VarUint32, CountedList, - Uint32, Uint64, - VarInt32, VarInt64, -}; +use crate::{Deserialize, VarUint32}; use crate::types::ValueType; use crate::instructions::{Instructions}; -use crate::types::{BlockType}; use crate::serialization::{Error}; use pwasm_std::vec::Vec; -use pwasm_std::String; /// Function signature (type reference) #[derive(Debug, Copy, Clone, PartialEq)] pub struct Func(u32); impl Func { - /// New function signature - pub fn new(type_ref: u32) -> Self { Func(type_ref) } - - /// Function signature type reference. - pub fn type_ref(&self) -> u32 { - self.0 - } - - /// Function signature type reference (mutable). - pub fn type_ref_mut(&mut self) -> &mut u32 { - &mut self.0 - } + /// New function signature + pub fn new(type_ref: u32) -> Self { Func(type_ref) } + + /// Function signature type reference. + pub fn type_ref(&self) -> u32 { + self.0 + } + + /// Function signature type reference (mutable). + pub fn type_ref_mut(&mut self) -> &mut u32 { + &mut self.0 + } } // impl Deserialize for Func { @@ -43,64 +36,64 @@ impl Func { /// Local definition inside the function body. #[derive(Debug, Copy, Clone, PartialEq)] pub struct Local { - count: u32, - value_type: ValueType, + count: u32, + value_type: ValueType, } impl Local { - /// New local with `count` and `value_type`. - pub fn new(count: u32, value_type: ValueType) -> Self { - Local { count: count, value_type: value_type } - } + /// New local with `count` and `value_type`. + pub fn new(count: u32, value_type: ValueType) -> Self { + Local { count: count, value_type: value_type } + } - /// Number of locals with the shared type. - pub fn count(&self) -> u32 { self.count } + /// Number of locals with the shared type. + pub fn count(&self) -> u32 { self.count } - /// Type of the locals. - pub fn value_type(&self) -> ValueType { self.value_type } + /// Type of the locals. + pub fn value_type(&self) -> ValueType { self.value_type } } impl Deserialize for Local { - type Error = Error; + type Error = Error; - fn deserialize(reader: &mut R) -> Result { - let count = VarUint32::deserialize(reader)?; - let value_type = ValueType::deserialize(reader)?; - Ok(Local { count: count.into(), value_type: value_type }) - } + fn deserialize(reader: &mut R) -> Result { + let count = VarUint32::deserialize(reader)?; + let value_type = ValueType::deserialize(reader)?; + Ok(Local { count: count.into(), value_type: value_type }) + } } /// Function body definition. #[derive(Debug, Clone, PartialEq)] pub struct FuncBody { - locals: Vec, - instructions: Instructions, + locals: Vec, + instructions: Instructions, } impl FuncBody { - /// New function body with given `locals` and `instructions`. - pub fn new(locals: Vec, instructions: Instructions) -> Self { - FuncBody { locals: locals, instructions: instructions } - } + /// New function body with given `locals` and `instructions`. + pub fn new(locals: Vec, instructions: Instructions) -> Self { + FuncBody { locals: locals, instructions: instructions } + } - /// List of individual instructions. - pub fn empty() -> Self { - FuncBody { locals: Vec::new(), instructions: Instructions::empty() } - } + /// List of individual instructions. + pub fn empty() -> Self { + FuncBody { locals: Vec::new(), instructions: Instructions::empty() } + } - /// Locals declared in function body. - pub fn locals(&self) -> &[Local] { &self.locals } + /// Locals declared in function body. + pub fn locals(&self) -> &[Local] { &self.locals } - /// Instruction list of the function body. Minimal instruction list - /// - /// is just `&[Instruction::End]` - pub fn code(&self) -> &Instructions { &self.instructions } + /// Instruction list of the function body. Minimal instruction list + /// + /// is just `&[Instruction::End]` + pub fn code(&self) -> &Instructions { &self.instructions } - /// Locals declared in function body (mutable). - pub fn locals_mut(&mut self) -> &mut Vec { &mut self.locals } + /// Locals declared in function body (mutable). + pub fn locals_mut(&mut self) -> &mut Vec { &mut self.locals } - /// Instruction list of the function body (mutable). - pub fn code_mut(&mut self) -> &mut Instructions { &mut self.instructions } + /// Instruction list of the function body (mutable). + pub fn code_mut(&mut self) -> &mut Instructions { &mut self.instructions } } // impl Deserialize for FuncBody { diff --git a/kernel-ewasm/validator/src/import_entry.rs b/kernel-ewasm/validator/src/import_entry.rs index c758725..a6c1ed4 100644 --- a/kernel-ewasm/validator/src/import_entry.rs +++ b/kernel-ewasm/validator/src/import_entry.rs @@ -1,16 +1,9 @@ use pwasm_std; -use pwasm_std::vec::Vec; use pwasm_std::String; -use pwasm_std::Box; use crate::io; -use crate::{ - Serialize, Deserialize, - Uint8, VarUint32, CountedList, - Uint32, Uint64, CountedListWriter, - VarInt32, VarInt64, VarInt7, VarUint1, VarUint7 -}; -use crate::types::{BlockType, TableElementType, ValueType}; +use crate::{Deserialize, Uint8, VarUint32, VarUint1, VarUint7}; +use crate::types::{TableElementType, ValueType}; use crate::serialization::{Error}; const FLAG_HAS_MAX: u8 = 0x01; @@ -19,134 +12,124 @@ const FLAG_SHARED: u8 = 0x02; /// Global definition struct #[derive(Debug, Copy, Clone, PartialEq)] pub struct GlobalType { - content_type: ValueType, - is_mutable: bool, + content_type: ValueType, + is_mutable: bool, } impl GlobalType { - /// New global type - pub fn new(content_type: ValueType, is_mutable: bool) -> Self { - GlobalType { - content_type: content_type, - is_mutable: is_mutable, - } - } - - /// Type of the global entry - pub fn content_type(&self) -> ValueType { self.content_type } - - /// Is global entry is declared as mutable - pub fn is_mutable(&self) -> bool { self.is_mutable } -} + /// New global type + pub fn new(content_type: ValueType, is_mutable: bool) -> Self { + GlobalType { + content_type: content_type, + is_mutable: is_mutable, + } + } -impl Deserialize for GlobalType { - type Error = Error; - - fn deserialize(reader: &mut R) -> Result { - let content_type = ValueType::deserialize(reader)?; - let is_mutable = VarUint1::deserialize(reader)?; - Ok(GlobalType { - content_type: content_type, - is_mutable: is_mutable.into(), - }) - } + /// Type of the global entry + pub fn content_type(&self) -> ValueType { self.content_type } + + /// Is global entry is declared as mutable + pub fn is_mutable(&self) -> bool { self.is_mutable } } -impl Serialize for GlobalType { - type Error = Error; +impl Deserialize for GlobalType { + type Error = Error; - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - self.content_type.serialize(writer)?; - VarUint1::from(self.is_mutable).serialize(writer)?; - Ok(()) - } + fn deserialize(reader: &mut R) -> Result { + let content_type = ValueType::deserialize(reader)?; + let is_mutable = VarUint1::deserialize(reader)?; + Ok(GlobalType { + content_type: content_type, + is_mutable: is_mutable.into(), + }) + } } /// Table entry #[derive(Debug, Copy, Clone, PartialEq)] pub struct TableType { - elem_type: TableElementType, - limits: ResizableLimits, + elem_type: TableElementType, + limits: ResizableLimits, } impl TableType { - /// New table definition - pub fn new(min: u32, max: Option) -> Self { - TableType { - elem_type: TableElementType::AnyFunc, - limits: ResizableLimits::new(min, max), - } - } - - /// Table memory specification - pub fn limits(&self) -> &ResizableLimits { &self.limits } - - /// Table element type - pub fn elem_type(&self) -> TableElementType { self.elem_type } + /// New table definition + pub fn new(min: u32, max: Option) -> Self { + TableType { + elem_type: TableElementType::AnyFunc, + limits: ResizableLimits::new(min, max), + } + } + + /// Table memory specification + pub fn limits(&self) -> &ResizableLimits { &self.limits } + + /// Table element type + pub fn elem_type(&self) -> TableElementType { self.elem_type } } impl Deserialize for TableType { - type Error = Error; - - fn deserialize(reader: &mut R) -> Result { - let elem_type = TableElementType::deserialize(reader)?; - let limits = ResizableLimits::deserialize(reader)?; - Ok(TableType { - elem_type: elem_type, - limits: limits, - }) - } + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let elem_type = TableElementType::deserialize(reader)?; + let limits = ResizableLimits::deserialize(reader)?; + Ok(TableType { + elem_type: elem_type, + limits: limits, + }) + } } /// Memory and table limits. #[derive(Debug, Copy, Clone, PartialEq)] pub struct ResizableLimits { - initial: u32, - maximum: Option, - shared: bool, + initial: u32, + maximum: Option, + shared: bool, } impl ResizableLimits { - /// New memory limits definition. - pub fn new(min: u32, max: Option) -> Self { - ResizableLimits { - initial: min, - maximum: max, - shared: false, - } - } - /// Initial size. - pub fn initial(&self) -> u32 { self.initial } - /// Maximum size. - pub fn maximum(&self) -> Option { self.maximum } - /// Whether or not this is a shared array buffer. - pub fn shared(&self) -> bool { self.shared } + /// New memory limits definition. + pub fn new(min: u32, max: Option) -> Self { + ResizableLimits { + initial: min, + maximum: max, + shared: false, + } + } + /// Initial size. + pub fn initial(&self) -> u32 { self.initial } + /// Maximum size. + pub fn maximum(&self) -> Option { self.maximum } + /// Whether or not this is a shared array buffer. + pub fn shared(&self) -> bool { self.shared } } impl Deserialize for ResizableLimits { - type Error = Error; - - fn deserialize(reader: &mut R) -> Result { - let flags: u8 = Uint8::deserialize(reader)?.into(); - match flags { - 0x00 | 0x01 | 0x03 => {}, - _ => return Err(Error::InvalidLimitsFlags(flags)), - } - - let initial = VarUint32::deserialize(reader)?; - let maximum = if flags & FLAG_HAS_MAX != 0 { - Some(VarUint32::deserialize(reader)?.into()) - } else { - None - }; - let shared = flags & FLAG_SHARED != 0; - - Ok(ResizableLimits { - initial: initial.into(), - maximum: maximum, - shared, - }) - } + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let flags: u8 = Uint8::deserialize(reader)?.into(); + match flags { + 0x00 | 0x01 | 0x03 => {}, + _ => return Err(Error::InvalidLimitsFlags(flags)), + } + + let initial = VarUint32::deserialize(reader)?; + let maximum = if flags & FLAG_HAS_MAX != 0 { + Some(VarUint32::deserialize(reader)?.into()) + } else { + None + }; + let shared = flags & FLAG_SHARED != 0; + + Ok(ResizableLimits { + initial: initial.into(), + maximum: maximum, + shared, + }) + } } /// Memory entry. @@ -154,109 +137,109 @@ impl Deserialize for ResizableLimits { pub struct MemoryType(ResizableLimits); impl MemoryType { - /// New memory definition - pub fn new(min: u32, max: Option, shared: bool) -> Self { - let mut r = ResizableLimits::new(min, max); - r.shared = shared; - MemoryType(r) - } - - /// Limits of the memory entry. - pub fn limits(&self) -> &ResizableLimits { - &self.0 - } + /// New memory definition + pub fn new(min: u32, max: Option, shared: bool) -> Self { + let mut r = ResizableLimits::new(min, max); + r.shared = shared; + MemoryType(r) + } + + /// Limits of the memory entry. + pub fn limits(&self) -> &ResizableLimits { + &self.0 + } } impl Deserialize for MemoryType { - type Error = Error; + type Error = Error; - fn deserialize(reader: &mut R) -> Result { - Ok(MemoryType(ResizableLimits::deserialize(reader)?)) - } + fn deserialize(reader: &mut R) -> Result { + Ok(MemoryType(ResizableLimits::deserialize(reader)?)) + } } /// External to local binding. #[derive(Debug, Copy, Clone, PartialEq)] pub enum External { - /// Binds to a function whose type is associated with the given index in the - /// type section. - Function(u32), - /// Describes local table definition to be imported as. - Table(TableType), - /// Describes local memory definition to be imported as. - Memory(MemoryType), - /// Describes local global entry to be imported as. - Global(GlobalType), + /// Binds to a function whose type is associated with the given index in the + /// type section. + Function(u32), + /// Describes local table definition to be imported as. + Table(TableType), + /// Describes local memory definition to be imported as. + Memory(MemoryType), + /// Describes local global entry to be imported as. + Global(GlobalType), } impl Deserialize for External { - type Error = Error; - - fn deserialize(reader: &mut R) -> Result { - let kind = VarUint7::deserialize(reader)?; - match kind.into() { - 0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())), - 0x01 => Ok(External::Table(TableType::deserialize(reader)?)), - 0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)), - 0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)), - _ => Err(Error::UnknownExternalKind(kind.into())), - } - } + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let kind = VarUint7::deserialize(reader)?; + match kind.into() { + 0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())), + 0x01 => Ok(External::Table(TableType::deserialize(reader)?)), + 0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)), + 0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)), + _ => Err(Error::UnknownExternalKind(kind.into())), + } + } } /// Import entry. #[derive(Debug, Clone, PartialEq)] pub struct ImportEntry { - module_str: String, - field_str: String, - external: External, + module_str: String, + field_str: String, + external: External, } impl ImportEntry { - /// New import entry. - pub fn new(module_str: String, field_str: String, external: External) -> Self { - ImportEntry { - module_str: module_str, - field_str: field_str, - external: external, - } - } - - /// Module reference of the import entry. - pub fn module(&self) -> &str { &self.module_str } - - /// Module reference of the import entry (mutable). - pub fn module_mut(&mut self) -> &mut String { - &mut self.module_str - } - - /// Field reference of the import entry. - pub fn field(&self) -> &str { &self.field_str } - - /// Field reference of the import entry (mutable) - pub fn field_mut(&mut self) -> &mut String { - &mut self.field_str - } - - /// Local binidng of the import entry. - pub fn external(&self) -> &External { &self.external } - - /// Local binidng of the import entry (mutable) - pub fn external_mut(&mut self) -> &mut External { &mut self.external } + /// New import entry. + pub fn new(module_str: String, field_str: String, external: External) -> Self { + ImportEntry { + module_str: module_str, + field_str: field_str, + external: external, + } + } + + /// Module reference of the import entry. + pub fn module(&self) -> &str { &self.module_str } + + /// Module reference of the import entry (mutable). + pub fn module_mut(&mut self) -> &mut String { + &mut self.module_str + } + + /// Field reference of the import entry. + pub fn field(&self) -> &str { &self.field_str } + + /// Field reference of the import entry (mutable) + pub fn field_mut(&mut self) -> &mut String { + &mut self.field_str + } + + /// Local binidng of the import entry. + pub fn external(&self) -> &External { &self.external } + + /// Local binidng of the import entry (mutable) + pub fn external_mut(&mut self) -> &mut External { &mut self.external } } impl Deserialize for ImportEntry { - type Error = Error; - - fn deserialize(reader: &mut R) -> Result { - let module_str = String::deserialize(reader)?; - let field_str = String::deserialize(reader)?; - let external = External::deserialize(reader)?; - - Ok(ImportEntry { - module_str: module_str, - field_str: field_str, - external: external, - }) - } + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let module_str = String::deserialize(reader)?; + let field_str = String::deserialize(reader)?; + let external = External::deserialize(reader)?; + + Ok(ImportEntry { + module_str: module_str, + field_str: field_str, + external: external, + }) + } } diff --git a/kernel-ewasm/validator/src/instructions.rs b/kernel-ewasm/validator/src/instructions.rs index 9e7b963..d98c21a 100644 --- a/kernel-ewasm/validator/src/instructions.rs +++ b/kernel-ewasm/validator/src/instructions.rs @@ -1,15 +1,13 @@ // This file is based on parity-wasm from parity, MIT & Apache Licensed use pwasm_std; use pwasm_std::vec::Vec; -use pwasm_std::String; use pwasm_std::Box; use crate::io; -use crate::{ - Serialize, Deserialize, - Uint8, VarUint32, CountedList, - Uint32, Uint64, CountedListWriter, - VarInt32, VarInt64, +use crate::{Deserialize, + Uint8, VarUint32, CountedList, + Uint32, Uint64, + VarInt32, VarInt64, }; use crate::types::{BlockType}; use crate::serialization::{Error}; @@ -19,46 +17,46 @@ use crate::serialization::{Error}; pub struct Instructions(Vec); impl Instructions { - /// New list of instructions from vector of instructions. - pub fn new(elements: Vec) -> Self { - Instructions(elements) - } + /// New list of instructions from vector of instructions. + pub fn new(elements: Vec) -> Self { + Instructions(elements) + } - /// Empty expression with only `Instruction::End` instruction. - pub fn empty() -> Self { - Instructions(vec![Instruction::End]) - } + /// Empty expression with only `Instruction::End` instruction. + pub fn empty() -> Self { + Instructions(vec![Instruction::End]) + } - /// List of individual instructions. - pub fn elements(&self) -> &[Instruction] { &self.0 } + /// List of individual instructions. + pub fn elements(&self) -> &[Instruction] { &self.0 } - /// Individual instructions, mutable. - pub fn elements_mut(&mut self) -> &mut Vec { &mut self.0 } + /// Individual instructions, mutable. + pub fn elements_mut(&mut self) -> &mut Vec { &mut self.0 } } impl Deserialize for Instructions { - type Error = Error; - - fn deserialize(reader: &mut R) -> Result { - let mut instructions = Vec::new(); - let mut block_count = 1usize; - - loop { - let instruction = Instruction::deserialize(reader)?; - if instruction.is_terminal() { - block_count -= 1; - } else if instruction.is_block() { - block_count = block_count.checked_add(1).ok_or(Error::Other("too many instructions"))?; - } - - instructions.push(instruction); - if block_count == 0 { - break; - } - } - - Ok(Instructions(instructions)) - } + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut instructions = Vec::new(); + let mut block_count = 1usize; + + loop { + let instruction = Instruction::deserialize(reader)?; + if instruction.is_terminal() { + block_count -= 1; + } else if instruction.is_block() { + block_count = block_count.checked_add(1).ok_or(Error::Other("too many instructions"))?; + } + + instructions.push(instruction); + if block_count == 0 { + break; + } + } + + Ok(Instructions(instructions)) + } } /// Initialization expression. @@ -66,2733 +64,1563 @@ impl Deserialize for Instructions { pub struct InitExpr(Vec); impl InitExpr { - /// New initialization expression from instruction list. - /// - /// `code` must end with the `Instruction::End` instruction! - pub fn new(code: Vec) -> Self { - InitExpr(code) - } - - /// Empty expression with only `Instruction::End` instruction. - pub fn empty() -> Self { - InitExpr(vec![Instruction::End]) - } - - /// List of instructions used in the expression. - pub fn code(&self) -> &[Instruction] { - &self.0 - } - - /// List of instructions used in the expression. - pub fn code_mut(&mut self) -> &mut Vec { - &mut self.0 - } + /// New initialization expression from instruction list. + /// + /// `code` must end with the `Instruction::End` instruction! + pub fn new(code: Vec) -> Self { + InitExpr(code) + } + + /// Empty expression with only `Instruction::End` instruction. + pub fn empty() -> Self { + InitExpr(vec![Instruction::End]) + } + + /// List of instructions used in the expression. + pub fn code(&self) -> &[Instruction] { + &self.0 + } + + /// List of instructions used in the expression. + pub fn code_mut(&mut self) -> &mut Vec { + &mut self.0 + } } impl Deserialize for InitExpr { - type Error = Error; - - fn deserialize(reader: &mut R) -> Result { - let mut instructions = Vec::new(); - - loop { - let instruction = Instruction::deserialize(reader)?; - let is_terminal = instruction.is_terminal(); - instructions.push(instruction); - if is_terminal { - break; - } - } - - Ok(InitExpr(instructions)) - } + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut instructions = Vec::new(); + + loop { + let instruction = Instruction::deserialize(reader)?; + let is_terminal = instruction.is_terminal(); + instructions.push(instruction); + if is_terminal { + break; + } + } + + Ok(InitExpr(instructions)) + } } /// Instruction. #[derive(Clone, Debug, PartialEq, Eq, Hash)] #[allow(missing_docs)] pub enum Instruction { - Unreachable, - Nop, - Block(BlockType), - Loop(BlockType), - If(BlockType), - Else, - End, - Br(u32), - BrIf(u32), - BrTable(Box), - Return, - - Call(u32), - CallIndirect(u32, u8), - - Drop, - Select, - - GetLocal(u32), - SetLocal(u32), - TeeLocal(u32), - GetGlobal(u32), - SetGlobal(u32), - - // All store/load instructions operate with 'memory immediates' - // which represented here as (flag, offset) tuple - I32Load(u32, u32), - I64Load(u32, u32), - F32Load(u32, u32), - F64Load(u32, u32), - I32Load8S(u32, u32), - I32Load8U(u32, u32), - I32Load16S(u32, u32), - I32Load16U(u32, u32), - I64Load8S(u32, u32), - I64Load8U(u32, u32), - I64Load16S(u32, u32), - I64Load16U(u32, u32), - I64Load32S(u32, u32), - I64Load32U(u32, u32), - I32Store(u32, u32), - I64Store(u32, u32), - F32Store(u32, u32), - F64Store(u32, u32), - I32Store8(u32, u32), - I32Store16(u32, u32), - I64Store8(u32, u32), - I64Store16(u32, u32), - I64Store32(u32, u32), - - CurrentMemory(u8), - GrowMemory(u8), - - I32Const(i32), - I64Const(i64), - F32Const(u32), - F64Const(u64), - - I32Eqz, - I32Eq, - I32Ne, - I32LtS, - I32LtU, - I32GtS, - I32GtU, - I32LeS, - I32LeU, - I32GeS, - I32GeU, - - I64Eqz, - I64Eq, - I64Ne, - I64LtS, - I64LtU, - I64GtS, - I64GtU, - I64LeS, - I64LeU, - I64GeS, - I64GeU, - - F32Eq, - F32Ne, - F32Lt, - F32Gt, - F32Le, - F32Ge, - - F64Eq, - F64Ne, - F64Lt, - F64Gt, - F64Le, - F64Ge, - - I32Clz, - I32Ctz, - I32Popcnt, - I32Add, - I32Sub, - I32Mul, - I32DivS, - I32DivU, - I32RemS, - I32RemU, - I32And, - I32Or, - I32Xor, - I32Shl, - I32ShrS, - I32ShrU, - I32Rotl, - I32Rotr, - - I64Clz, - I64Ctz, - I64Popcnt, - I64Add, - I64Sub, - I64Mul, - I64DivS, - I64DivU, - I64RemS, - I64RemU, - I64And, - I64Or, - I64Xor, - I64Shl, - I64ShrS, - I64ShrU, - I64Rotl, - I64Rotr, - F32Abs, - F32Neg, - F32Ceil, - F32Floor, - F32Trunc, - F32Nearest, - F32Sqrt, - F32Add, - F32Sub, - F32Mul, - F32Div, - F32Min, - F32Max, - F32Copysign, - F64Abs, - F64Neg, - F64Ceil, - F64Floor, - F64Trunc, - F64Nearest, - F64Sqrt, - F64Add, - F64Sub, - F64Mul, - F64Div, - F64Min, - F64Max, - F64Copysign, - - I32WrapI64, - I32TruncSF32, - I32TruncUF32, - I32TruncSF64, - I32TruncUF64, - I64ExtendSI32, - I64ExtendUI32, - I64TruncSF32, - I64TruncUF32, - I64TruncSF64, - I64TruncUF64, - F32ConvertSI32, - F32ConvertUI32, - F32ConvertSI64, - F32ConvertUI64, - F32DemoteF64, - F64ConvertSI32, - F64ConvertUI32, - F64ConvertSI64, - F64ConvertUI64, - F64PromoteF32, - - I32ReinterpretF32, - I64ReinterpretF64, - F32ReinterpretI32, - F64ReinterpretI64, - - I32Extend8S, - I32Extend16S, - I64Extend8S, - I64Extend16S, - I64Extend32S, - - AtomicWake(MemArg), - I32AtomicWait(MemArg), - I64AtomicWait(MemArg), - - I32AtomicLoad(MemArg), - I64AtomicLoad(MemArg), - I32AtomicLoad8u(MemArg), - I32AtomicLoad16u(MemArg), - I64AtomicLoad8u(MemArg), - I64AtomicLoad16u(MemArg), - I64AtomicLoad32u(MemArg), - I32AtomicStore(MemArg), - I64AtomicStore(MemArg), - I32AtomicStore8u(MemArg), - I32AtomicStore16u(MemArg), - I64AtomicStore8u(MemArg), - I64AtomicStore16u(MemArg), - I64AtomicStore32u(MemArg), - - I32AtomicRmwAdd(MemArg), - I64AtomicRmwAdd(MemArg), - I32AtomicRmwAdd8u(MemArg), - I32AtomicRmwAdd16u(MemArg), - I64AtomicRmwAdd8u(MemArg), - I64AtomicRmwAdd16u(MemArg), - I64AtomicRmwAdd32u(MemArg), - - I32AtomicRmwSub(MemArg), - I64AtomicRmwSub(MemArg), - I32AtomicRmwSub8u(MemArg), - I32AtomicRmwSub16u(MemArg), - I64AtomicRmwSub8u(MemArg), - I64AtomicRmwSub16u(MemArg), - I64AtomicRmwSub32u(MemArg), - - I32AtomicRmwAnd(MemArg), - I64AtomicRmwAnd(MemArg), - I32AtomicRmwAnd8u(MemArg), - I32AtomicRmwAnd16u(MemArg), - I64AtomicRmwAnd8u(MemArg), - I64AtomicRmwAnd16u(MemArg), - I64AtomicRmwAnd32u(MemArg), - - I32AtomicRmwOr(MemArg), - I64AtomicRmwOr(MemArg), - I32AtomicRmwOr8u(MemArg), - I32AtomicRmwOr16u(MemArg), - I64AtomicRmwOr8u(MemArg), - I64AtomicRmwOr16u(MemArg), - I64AtomicRmwOr32u(MemArg), - - I32AtomicRmwXor(MemArg), - I64AtomicRmwXor(MemArg), - I32AtomicRmwXor8u(MemArg), - I32AtomicRmwXor16u(MemArg), - I64AtomicRmwXor8u(MemArg), - I64AtomicRmwXor16u(MemArg), - I64AtomicRmwXor32u(MemArg), - - I32AtomicRmwXchg(MemArg), - I64AtomicRmwXchg(MemArg), - I32AtomicRmwXchg8u(MemArg), - I32AtomicRmwXchg16u(MemArg), - I64AtomicRmwXchg8u(MemArg), - I64AtomicRmwXchg16u(MemArg), - I64AtomicRmwXchg32u(MemArg), - - I32AtomicRmwCmpxchg(MemArg), - I64AtomicRmwCmpxchg(MemArg), - I32AtomicRmwCmpxchg8u(MemArg), - I32AtomicRmwCmpxchg16u(MemArg), - I64AtomicRmwCmpxchg8u(MemArg), - I64AtomicRmwCmpxchg16u(MemArg), - I64AtomicRmwCmpxchg32u(MemArg), - - V128Const(Box<[u8; 16]>), - V128Load(MemArg), - V128Store(MemArg), - I8x16Splat, - I16x8Splat, - I32x4Splat, - I64x2Splat, - F32x4Splat, - F64x2Splat, - I8x16ExtractLaneS(u8), - I8x16ExtractLaneU(u8), - I16x8ExtractLaneS(u8), - I16x8ExtractLaneU(u8), - I32x4ExtractLane(u8), - I64x2ExtractLane(u8), - F32x4ExtractLane(u8), - F64x2ExtractLane(u8), - I8x16ReplaceLane(u8), - I16x8ReplaceLane(u8), - I32x4ReplaceLane(u8), - I64x2ReplaceLane(u8), - F32x4ReplaceLane(u8), - F64x2ReplaceLane(u8), - V8x16Shuffle(Box<[u8; 16]>), - I8x16Add, - I16x8Add, - I32x4Add, - I64x2Add, - I8x16Sub, - I16x8Sub, - I32x4Sub, - I64x2Sub, - I8x16Mul, - I16x8Mul, - I32x4Mul, - // I64x2Mul, - I8x16Neg, - I16x8Neg, - I32x4Neg, - I64x2Neg, - I8x16AddSaturateS, - I8x16AddSaturateU, - I16x8AddSaturateS, - I16x8AddSaturateU, - I8x16SubSaturateS, - I8x16SubSaturateU, - I16x8SubSaturateS, - I16x8SubSaturateU, - I8x16Shl, - I16x8Shl, - I32x4Shl, - I64x2Shl, - I8x16ShrS, - I8x16ShrU, - I16x8ShrS, - I16x8ShrU, - I32x4ShrS, - I32x4ShrU, - I64x2ShrS, - I64x2ShrU, - V128And, - V128Or, - V128Xor, - V128Not, - V128Bitselect, - I8x16AnyTrue, - I16x8AnyTrue, - I32x4AnyTrue, - I64x2AnyTrue, - I8x16AllTrue, - I16x8AllTrue, - I32x4AllTrue, - I64x2AllTrue, - I8x16Eq, - I16x8Eq, - I32x4Eq, - // I64x2Eq, - F32x4Eq, - F64x2Eq, - I8x16Ne, - I16x8Ne, - I32x4Ne, - // I64x2Ne, - F32x4Ne, - F64x2Ne, - I8x16LtS, - I8x16LtU, - I16x8LtS, - I16x8LtU, - I32x4LtS, - I32x4LtU, - // I64x2LtS, - // I64x2LtU, - F32x4Lt, - F64x2Lt, - I8x16LeS, - I8x16LeU, - I16x8LeS, - I16x8LeU, - I32x4LeS, - I32x4LeU, - // I64x2LeS, - // I64x2LeU, - F32x4Le, - F64x2Le, - I8x16GtS, - I8x16GtU, - I16x8GtS, - I16x8GtU, - I32x4GtS, - I32x4GtU, - // I64x2GtS, - // I64x2GtU, - F32x4Gt, - F64x2Gt, - I8x16GeS, - I8x16GeU, - I16x8GeS, - I16x8GeU, - I32x4GeS, - I32x4GeU, - // I64x2GeS, - // I64x2GeU, - F32x4Ge, - F64x2Ge, - F32x4Neg, - F64x2Neg, - F32x4Abs, - F64x2Abs, - F32x4Min, - F64x2Min, - F32x4Max, - F64x2Max, - F32x4Add, - F64x2Add, - F32x4Sub, - F64x2Sub, - F32x4Div, - F64x2Div, - F32x4Mul, - F64x2Mul, - F32x4Sqrt, - F64x2Sqrt, - F32x4ConvertSI32x4, - F32x4ConvertUI32x4, - F64x2ConvertSI64x2, - F64x2ConvertUI64x2, - I32x4TruncSF32x4Sat, - I32x4TruncUF32x4Sat, - I64x2TruncSF64x2Sat, - I64x2TruncUF64x2Sat, - - // https://github.com/WebAssembly/bulk-memory-operations - MemoryInit(u32), - MemoryDrop(u32), - MemoryCopy, - MemoryFill, - TableInit(u32), - TableDrop(u32), - TableCopy, + Unreachable, + Nop, + Block(BlockType), + Loop(BlockType), + If(BlockType), + Else, + End, + Br(u32), + BrIf(u32), + BrTable(Box), + Return, + + Call(u32), + CallIndirect(u32, u8), + + Drop, + Select, + + GetLocal(u32), + SetLocal(u32), + TeeLocal(u32), + GetGlobal(u32), + SetGlobal(u32), + + // All store/load instructions operate with 'memory immediates' + // which represented here as (flag, offset) tuple + I32Load(u32, u32), + I64Load(u32, u32), + F32Load(u32, u32), + F64Load(u32, u32), + I32Load8S(u32, u32), + I32Load8U(u32, u32), + I32Load16S(u32, u32), + I32Load16U(u32, u32), + I64Load8S(u32, u32), + I64Load8U(u32, u32), + I64Load16S(u32, u32), + I64Load16U(u32, u32), + I64Load32S(u32, u32), + I64Load32U(u32, u32), + I32Store(u32, u32), + I64Store(u32, u32), + F32Store(u32, u32), + F64Store(u32, u32), + I32Store8(u32, u32), + I32Store16(u32, u32), + I64Store8(u32, u32), + I64Store16(u32, u32), + I64Store32(u32, u32), + + CurrentMemory(u8), + GrowMemory(u8), + + I32Const(i32), + I64Const(i64), + F32Const(u32), + F64Const(u64), + + I32Eqz, + I32Eq, + I32Ne, + I32LtS, + I32LtU, + I32GtS, + I32GtU, + I32LeS, + I32LeU, + I32GeS, + I32GeU, + + I64Eqz, + I64Eq, + I64Ne, + I64LtS, + I64LtU, + I64GtS, + I64GtU, + I64LeS, + I64LeU, + I64GeS, + I64GeU, + + F32Eq, + F32Ne, + F32Lt, + F32Gt, + F32Le, + F32Ge, + + F64Eq, + F64Ne, + F64Lt, + F64Gt, + F64Le, + F64Ge, + + I32Clz, + I32Ctz, + I32Popcnt, + I32Add, + I32Sub, + I32Mul, + I32DivS, + I32DivU, + I32RemS, + I32RemU, + I32And, + I32Or, + I32Xor, + I32Shl, + I32ShrS, + I32ShrU, + I32Rotl, + I32Rotr, + + I64Clz, + I64Ctz, + I64Popcnt, + I64Add, + I64Sub, + I64Mul, + I64DivS, + I64DivU, + I64RemS, + I64RemU, + I64And, + I64Or, + I64Xor, + I64Shl, + I64ShrS, + I64ShrU, + I64Rotl, + I64Rotr, + F32Abs, + F32Neg, + F32Ceil, + F32Floor, + F32Trunc, + F32Nearest, + F32Sqrt, + F32Add, + F32Sub, + F32Mul, + F32Div, + F32Min, + F32Max, + F32Copysign, + F64Abs, + F64Neg, + F64Ceil, + F64Floor, + F64Trunc, + F64Nearest, + F64Sqrt, + F64Add, + F64Sub, + F64Mul, + F64Div, + F64Min, + F64Max, + F64Copysign, + + I32WrapI64, + I32TruncSF32, + I32TruncUF32, + I32TruncSF64, + I32TruncUF64, + I64ExtendSI32, + I64ExtendUI32, + I64TruncSF32, + I64TruncUF32, + I64TruncSF64, + I64TruncUF64, + F32ConvertSI32, + F32ConvertUI32, + F32ConvertSI64, + F32ConvertUI64, + F32DemoteF64, + F64ConvertSI32, + F64ConvertUI32, + F64ConvertSI64, + F64ConvertUI64, + F64PromoteF32, + + I32ReinterpretF32, + I64ReinterpretF64, + F32ReinterpretI32, + F64ReinterpretI64, + + I32Extend8S, + I32Extend16S, + I64Extend8S, + I64Extend16S, + I64Extend32S, + + AtomicWake(MemArg), + I32AtomicWait(MemArg), + I64AtomicWait(MemArg), + + I32AtomicLoad(MemArg), + I64AtomicLoad(MemArg), + I32AtomicLoad8u(MemArg), + I32AtomicLoad16u(MemArg), + I64AtomicLoad8u(MemArg), + I64AtomicLoad16u(MemArg), + I64AtomicLoad32u(MemArg), + I32AtomicStore(MemArg), + I64AtomicStore(MemArg), + I32AtomicStore8u(MemArg), + I32AtomicStore16u(MemArg), + I64AtomicStore8u(MemArg), + I64AtomicStore16u(MemArg), + I64AtomicStore32u(MemArg), + + I32AtomicRmwAdd(MemArg), + I64AtomicRmwAdd(MemArg), + I32AtomicRmwAdd8u(MemArg), + I32AtomicRmwAdd16u(MemArg), + I64AtomicRmwAdd8u(MemArg), + I64AtomicRmwAdd16u(MemArg), + I64AtomicRmwAdd32u(MemArg), + + I32AtomicRmwSub(MemArg), + I64AtomicRmwSub(MemArg), + I32AtomicRmwSub8u(MemArg), + I32AtomicRmwSub16u(MemArg), + I64AtomicRmwSub8u(MemArg), + I64AtomicRmwSub16u(MemArg), + I64AtomicRmwSub32u(MemArg), + + I32AtomicRmwAnd(MemArg), + I64AtomicRmwAnd(MemArg), + I32AtomicRmwAnd8u(MemArg), + I32AtomicRmwAnd16u(MemArg), + I64AtomicRmwAnd8u(MemArg), + I64AtomicRmwAnd16u(MemArg), + I64AtomicRmwAnd32u(MemArg), + + I32AtomicRmwOr(MemArg), + I64AtomicRmwOr(MemArg), + I32AtomicRmwOr8u(MemArg), + I32AtomicRmwOr16u(MemArg), + I64AtomicRmwOr8u(MemArg), + I64AtomicRmwOr16u(MemArg), + I64AtomicRmwOr32u(MemArg), + + I32AtomicRmwXor(MemArg), + I64AtomicRmwXor(MemArg), + I32AtomicRmwXor8u(MemArg), + I32AtomicRmwXor16u(MemArg), + I64AtomicRmwXor8u(MemArg), + I64AtomicRmwXor16u(MemArg), + I64AtomicRmwXor32u(MemArg), + + I32AtomicRmwXchg(MemArg), + I64AtomicRmwXchg(MemArg), + I32AtomicRmwXchg8u(MemArg), + I32AtomicRmwXchg16u(MemArg), + I64AtomicRmwXchg8u(MemArg), + I64AtomicRmwXchg16u(MemArg), + I64AtomicRmwXchg32u(MemArg), + + I32AtomicRmwCmpxchg(MemArg), + I64AtomicRmwCmpxchg(MemArg), + I32AtomicRmwCmpxchg8u(MemArg), + I32AtomicRmwCmpxchg16u(MemArg), + I64AtomicRmwCmpxchg8u(MemArg), + I64AtomicRmwCmpxchg16u(MemArg), + I64AtomicRmwCmpxchg32u(MemArg), + + V128Const(Box<[u8; 16]>), + V128Load(MemArg), + V128Store(MemArg), + I8x16Splat, + I16x8Splat, + I32x4Splat, + I64x2Splat, + F32x4Splat, + F64x2Splat, + I8x16ExtractLaneS(u8), + I8x16ExtractLaneU(u8), + I16x8ExtractLaneS(u8), + I16x8ExtractLaneU(u8), + I32x4ExtractLane(u8), + I64x2ExtractLane(u8), + F32x4ExtractLane(u8), + F64x2ExtractLane(u8), + I8x16ReplaceLane(u8), + I16x8ReplaceLane(u8), + I32x4ReplaceLane(u8), + I64x2ReplaceLane(u8), + F32x4ReplaceLane(u8), + F64x2ReplaceLane(u8), + V8x16Shuffle(Box<[u8; 16]>), + I8x16Add, + I16x8Add, + I32x4Add, + I64x2Add, + I8x16Sub, + I16x8Sub, + I32x4Sub, + I64x2Sub, + I8x16Mul, + I16x8Mul, + I32x4Mul, + // I64x2Mul, + I8x16Neg, + I16x8Neg, + I32x4Neg, + I64x2Neg, + I8x16AddSaturateS, + I8x16AddSaturateU, + I16x8AddSaturateS, + I16x8AddSaturateU, + I8x16SubSaturateS, + I8x16SubSaturateU, + I16x8SubSaturateS, + I16x8SubSaturateU, + I8x16Shl, + I16x8Shl, + I32x4Shl, + I64x2Shl, + I8x16ShrS, + I8x16ShrU, + I16x8ShrS, + I16x8ShrU, + I32x4ShrS, + I32x4ShrU, + I64x2ShrS, + I64x2ShrU, + V128And, + V128Or, + V128Xor, + V128Not, + V128Bitselect, + I8x16AnyTrue, + I16x8AnyTrue, + I32x4AnyTrue, + I64x2AnyTrue, + I8x16AllTrue, + I16x8AllTrue, + I32x4AllTrue, + I64x2AllTrue, + I8x16Eq, + I16x8Eq, + I32x4Eq, + // I64x2Eq, + F32x4Eq, + F64x2Eq, + I8x16Ne, + I16x8Ne, + I32x4Ne, + // I64x2Ne, + F32x4Ne, + F64x2Ne, + I8x16LtS, + I8x16LtU, + I16x8LtS, + I16x8LtU, + I32x4LtS, + I32x4LtU, + // I64x2LtS, + // I64x2LtU, + F32x4Lt, + F64x2Lt, + I8x16LeS, + I8x16LeU, + I16x8LeS, + I16x8LeU, + I32x4LeS, + I32x4LeU, + // I64x2LeS, + // I64x2LeU, + F32x4Le, + F64x2Le, + I8x16GtS, + I8x16GtU, + I16x8GtS, + I16x8GtU, + I32x4GtS, + I32x4GtU, + // I64x2GtS, + // I64x2GtU, + F32x4Gt, + F64x2Gt, + I8x16GeS, + I8x16GeU, + I16x8GeS, + I16x8GeU, + I32x4GeS, + I32x4GeU, + // I64x2GeS, + // I64x2GeU, + F32x4Ge, + F64x2Ge, + F32x4Neg, + F64x2Neg, + F32x4Abs, + F64x2Abs, + F32x4Min, + F64x2Min, + F32x4Max, + F64x2Max, + F32x4Add, + F64x2Add, + F32x4Sub, + F64x2Sub, + F32x4Div, + F64x2Div, + F32x4Mul, + F64x2Mul, + F32x4Sqrt, + F64x2Sqrt, + F32x4ConvertSI32x4, + F32x4ConvertUI32x4, + F64x2ConvertSI64x2, + F64x2ConvertUI64x2, + I32x4TruncSF32x4Sat, + I32x4TruncUF32x4Sat, + I64x2TruncSF64x2Sat, + I64x2TruncUF64x2Sat, + + // https://github.com/WebAssembly/bulk-memory-operations + MemoryInit(u32), + MemoryDrop(u32), + MemoryCopy, + MemoryFill, + TableInit(u32), + TableDrop(u32), + TableCopy, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] #[allow(missing_docs)] pub struct MemArg { - pub align: u8, - pub offset: u32, + pub align: u8, + pub offset: u32, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] #[allow(missing_docs)] pub struct BrTableData { - pub table: Box<[u32]>, - pub default: u32, + pub table: Box<[u32]>, + pub default: u32, } impl Instruction { - /// Is this instruction starts the new block (which should end with terminal instruction). - pub fn is_block(&self) -> bool { - match self { - &Instruction::Block(_) | &Instruction::Loop(_) | &Instruction::If(_) => true, - _ => false, - } - } - - /// Is this instruction determines the termination of instruction sequence? - /// - /// `true` for `Instruction::End` - pub fn is_terminal(&self) -> bool { - match self { - &Instruction::End => true, - _ => false, - } - } + /// Is this instruction starts the new block (which should end with terminal instruction). + pub fn is_block(&self) -> bool { + match self { + &Instruction::Block(_) | &Instruction::Loop(_) | &Instruction::If(_) => true, + _ => false, + } + } + + /// Is this instruction determines the termination of instruction sequence? + /// + /// `true` for `Instruction::End` + pub fn is_terminal(&self) -> bool { + match self { + &Instruction::End => true, + _ => false, + } + } } #[allow(missing_docs)] #[allow(dead_code)] pub mod opcodes { - pub const UNREACHABLE: u8 = 0x00; - pub const NOP: u8 = 0x01; - pub const BLOCK: u8 = 0x02; - pub const LOOP: u8 = 0x03; - pub const IF: u8 = 0x04; - pub const ELSE: u8 = 0x05; - pub const END: u8 = 0x0b; - pub const BR: u8 = 0x0c; - pub const BRIF: u8 = 0x0d; - pub const BRTABLE: u8 = 0x0e; - pub const RETURN: u8 = 0x0f; - pub const CALL: u8 = 0x10; - pub const CALLINDIRECT: u8 = 0x11; - pub const DROP: u8 = 0x1a; - pub const SELECT: u8 = 0x1b; - pub const GETLOCAL: u8 = 0x20; - pub const SETLOCAL: u8 = 0x21; - pub const TEELOCAL: u8 = 0x22; - pub const GETGLOBAL: u8 = 0x23; - pub const SETGLOBAL: u8 = 0x24; - pub const I32LOAD: u8 = 0x28; - pub const I64LOAD: u8 = 0x29; - pub const F32LOAD: u8 = 0x2a; - pub const F64LOAD: u8 = 0x2b; - pub const I32LOAD8S: u8 = 0x2c; - pub const I32LOAD8U: u8 = 0x2d; - pub const I32LOAD16S: u8 = 0x2e; - pub const I32LOAD16U: u8 = 0x2f; - pub const I64LOAD8S: u8 = 0x30; - pub const I64LOAD8U: u8 = 0x31; - pub const I64LOAD16S: u8 = 0x32; - pub const I64LOAD16U: u8 = 0x33; - pub const I64LOAD32S: u8 = 0x34; - pub const I64LOAD32U: u8 = 0x35; - pub const I32STORE: u8 = 0x36; - pub const I64STORE: u8 = 0x37; - pub const F32STORE: u8 = 0x38; - pub const F64STORE: u8 = 0x39; - pub const I32STORE8: u8 = 0x3a; - pub const I32STORE16: u8 = 0x3b; - pub const I64STORE8: u8 = 0x3c; - pub const I64STORE16: u8 = 0x3d; - pub const I64STORE32: u8 = 0x3e; - pub const CURRENTMEMORY: u8 = 0x3f; - pub const GROWMEMORY: u8 = 0x40; - pub const I32CONST: u8 = 0x41; - pub const I64CONST: u8 = 0x42; - pub const F32CONST: u8 = 0x43; - pub const F64CONST: u8 = 0x44; - pub const I32EQZ: u8 = 0x45; - pub const I32EQ: u8 = 0x46; - pub const I32NE: u8 = 0x47; - pub const I32LTS: u8 = 0x48; - pub const I32LTU: u8 = 0x49; - pub const I32GTS: u8 = 0x4a; - pub const I32GTU: u8 = 0x4b; - pub const I32LES: u8 = 0x4c; - pub const I32LEU: u8 = 0x4d; - pub const I32GES: u8 = 0x4e; - pub const I32GEU: u8 = 0x4f; - pub const I64EQZ: u8 = 0x50; - pub const I64EQ: u8 = 0x51; - pub const I64NE: u8 = 0x52; - pub const I64LTS: u8 = 0x53; - pub const I64LTU: u8 = 0x54; - pub const I64GTS: u8 = 0x55; - pub const I64GTU: u8 = 0x56; - pub const I64LES: u8 = 0x57; - pub const I64LEU: u8 = 0x58; - pub const I64GES: u8 = 0x59; - pub const I64GEU: u8 = 0x5a; - - pub const F32EQ: u8 = 0x5b; - pub const F32NE: u8 = 0x5c; - pub const F32LT: u8 = 0x5d; - pub const F32GT: u8 = 0x5e; - pub const F32LE: u8 = 0x5f; - pub const F32GE: u8 = 0x60; - - pub const F64EQ: u8 = 0x61; - pub const F64NE: u8 = 0x62; - pub const F64LT: u8 = 0x63; - pub const F64GT: u8 = 0x64; - pub const F64LE: u8 = 0x65; - pub const F64GE: u8 = 0x66; - - pub const I32CLZ: u8 = 0x67; - pub const I32CTZ: u8 = 0x68; - pub const I32POPCNT: u8 = 0x69; - pub const I32ADD: u8 = 0x6a; - pub const I32SUB: u8 = 0x6b; - pub const I32MUL: u8 = 0x6c; - pub const I32DIVS: u8 = 0x6d; - pub const I32DIVU: u8 = 0x6e; - pub const I32REMS: u8 = 0x6f; - pub const I32REMU: u8 = 0x70; - pub const I32AND: u8 = 0x71; - pub const I32OR: u8 = 0x72; - pub const I32XOR: u8 = 0x73; - pub const I32SHL: u8 = 0x74; - pub const I32SHRS: u8 = 0x75; - pub const I32SHRU: u8 = 0x76; - pub const I32ROTL: u8 = 0x77; - pub const I32ROTR: u8 = 0x78; - - pub const I64CLZ: u8 = 0x79; - pub const I64CTZ: u8 = 0x7a; - pub const I64POPCNT: u8 = 0x7b; - pub const I64ADD: u8 = 0x7c; - pub const I64SUB: u8 = 0x7d; - pub const I64MUL: u8 = 0x7e; - pub const I64DIVS: u8 = 0x7f; - pub const I64DIVU: u8 = 0x80; - pub const I64REMS: u8 = 0x81; - pub const I64REMU: u8 = 0x82; - pub const I64AND: u8 = 0x83; - pub const I64OR: u8 = 0x84; - pub const I64XOR: u8 = 0x85; - pub const I64SHL: u8 = 0x86; - pub const I64SHRS: u8 = 0x87; - pub const I64SHRU: u8 = 0x88; - pub const I64ROTL: u8 = 0x89; - pub const I64ROTR: u8 = 0x8a; - pub const F32ABS: u8 = 0x8b; - pub const F32NEG: u8 = 0x8c; - pub const F32CEIL: u8 = 0x8d; - pub const F32FLOOR: u8 = 0x8e; - pub const F32TRUNC: u8 = 0x8f; - pub const F32NEAREST: u8 = 0x90; - pub const F32SQRT: u8 = 0x91; - pub const F32ADD: u8 = 0x92; - pub const F32SUB: u8 = 0x93; - pub const F32MUL: u8 = 0x94; - pub const F32DIV: u8 = 0x95; - pub const F32MIN: u8 = 0x96; - pub const F32MAX: u8 = 0x97; - pub const F32COPYSIGN: u8 = 0x98; - pub const F64ABS: u8 = 0x99; - pub const F64NEG: u8 = 0x9a; - pub const F64CEIL: u8 = 0x9b; - pub const F64FLOOR: u8 = 0x9c; - pub const F64TRUNC: u8 = 0x9d; - pub const F64NEAREST: u8 = 0x9e; - pub const F64SQRT: u8 = 0x9f; - pub const F64ADD: u8 = 0xa0; - pub const F64SUB: u8 = 0xa1; - pub const F64MUL: u8 = 0xa2; - pub const F64DIV: u8 = 0xa3; - pub const F64MIN: u8 = 0xa4; - pub const F64MAX: u8 = 0xa5; - pub const F64COPYSIGN: u8 = 0xa6; - - pub const I32WRAPI64: u8 = 0xa7; - pub const I32TRUNCSF32: u8 = 0xa8; - pub const I32TRUNCUF32: u8 = 0xa9; - pub const I32TRUNCSF64: u8 = 0xaa; - pub const I32TRUNCUF64: u8 = 0xab; - pub const I64EXTENDSI32: u8 = 0xac; - pub const I64EXTENDUI32: u8 = 0xad; - pub const I64TRUNCSF32: u8 = 0xae; - pub const I64TRUNCUF32: u8 = 0xaf; - pub const I64TRUNCSF64: u8 = 0xb0; - pub const I64TRUNCUF64: u8 = 0xb1; - pub const F32CONVERTSI32: u8 = 0xb2; - pub const F32CONVERTUI32: u8 = 0xb3; - pub const F32CONVERTSI64: u8 = 0xb4; - pub const F32CONVERTUI64: u8 = 0xb5; - pub const F32DEMOTEF64: u8 = 0xb6; - pub const F64CONVERTSI32: u8 = 0xb7; - pub const F64CONVERTUI32: u8 = 0xb8; - pub const F64CONVERTSI64: u8 = 0xb9; - pub const F64CONVERTUI64: u8 = 0xba; - pub const F64PROMOTEF32: u8 = 0xbb; - - pub const I32REINTERPRETF32: u8 = 0xbc; - pub const I64REINTERPRETF64: u8 = 0xbd; - pub const F32REINTERPRETI32: u8 = 0xbe; - pub const F64REINTERPRETI64: u8 = 0xbf; - - pub const I32_EXTEND8_S: u8 = 0xc0; - pub const I32_EXTEND16_S: u8 = 0xc1; - pub const I64_EXTEND8_S: u8 = 0xc2; - pub const I64_EXTEND16_S: u8 = 0xc3; - pub const I64_EXTEND32_S: u8 = 0xc4; - - pub const ATOMIC_PREFIX: u8 = 0xfe; - pub const ATOMIC_WAKE: u8 = 0x00; - pub const I32_ATOMIC_WAIT: u8 = 0x01; - pub const I64_ATOMIC_WAIT: u8 = 0x02; - - pub const I32_ATOMIC_LOAD: u8 = 0x10; - pub const I64_ATOMIC_LOAD: u8 = 0x11; - pub const I32_ATOMIC_LOAD8U: u8 = 0x12; - pub const I32_ATOMIC_LOAD16U: u8 = 0x13; - pub const I64_ATOMIC_LOAD8U: u8 = 0x14; - pub const I64_ATOMIC_LOAD16U: u8 = 0x15; - pub const I64_ATOMIC_LOAD32U: u8 = 0x16; - pub const I32_ATOMIC_STORE: u8 = 0x17; - pub const I64_ATOMIC_STORE: u8 = 0x18; - pub const I32_ATOMIC_STORE8U: u8 = 0x19; - pub const I32_ATOMIC_STORE16U: u8 = 0x1a; - pub const I64_ATOMIC_STORE8U: u8 = 0x1b; - pub const I64_ATOMIC_STORE16U: u8 = 0x1c; - pub const I64_ATOMIC_STORE32U: u8 = 0x1d; - - pub const I32_ATOMIC_RMW_ADD: u8 = 0x1e; - pub const I64_ATOMIC_RMW_ADD: u8 = 0x1f; - pub const I32_ATOMIC_RMW_ADD8U: u8 = 0x20; - pub const I32_ATOMIC_RMW_ADD16U: u8 = 0x21; - pub const I64_ATOMIC_RMW_ADD8U: u8 = 0x22; - pub const I64_ATOMIC_RMW_ADD16U: u8 = 0x23; - pub const I64_ATOMIC_RMW_ADD32U: u8 = 0x24; - - pub const I32_ATOMIC_RMW_SUB: u8 = 0x25; - pub const I64_ATOMIC_RMW_SUB: u8 = 0x26; - pub const I32_ATOMIC_RMW_SUB8U: u8 = 0x27; - pub const I32_ATOMIC_RMW_SUB16U: u8 = 0x28; - pub const I64_ATOMIC_RMW_SUB8U: u8 = 0x29; - pub const I64_ATOMIC_RMW_SUB16U: u8 = 0x2a; - pub const I64_ATOMIC_RMW_SUB32U: u8 = 0x2b; - - pub const I32_ATOMIC_RMW_AND: u8 = 0x2c; - pub const I64_ATOMIC_RMW_AND: u8 = 0x2d; - pub const I32_ATOMIC_RMW_AND8U: u8 = 0x2e; - pub const I32_ATOMIC_RMW_AND16U: u8 = 0x2f; - pub const I64_ATOMIC_RMW_AND8U: u8 = 0x30; - pub const I64_ATOMIC_RMW_AND16U: u8 = 0x31; - pub const I64_ATOMIC_RMW_AND32U: u8 = 0x32; - - pub const I32_ATOMIC_RMW_OR: u8 = 0x33; - pub const I64_ATOMIC_RMW_OR: u8 = 0x34; - pub const I32_ATOMIC_RMW_OR8U: u8 = 0x35; - pub const I32_ATOMIC_RMW_OR16U: u8 = 0x36; - pub const I64_ATOMIC_RMW_OR8U: u8 = 0x37; - pub const I64_ATOMIC_RMW_OR16U: u8 = 0x38; - pub const I64_ATOMIC_RMW_OR32U: u8 = 0x39; - - pub const I32_ATOMIC_RMW_XOR: u8 = 0x3a; - pub const I64_ATOMIC_RMW_XOR: u8 = 0x3b; - pub const I32_ATOMIC_RMW_XOR8U: u8 = 0x3c; - pub const I32_ATOMIC_RMW_XOR16U: u8 = 0x3d; - pub const I64_ATOMIC_RMW_XOR8U: u8 = 0x3e; - pub const I64_ATOMIC_RMW_XOR16U: u8 = 0x3f; - pub const I64_ATOMIC_RMW_XOR32U: u8 = 0x40; - - pub const I32_ATOMIC_RMW_XCHG: u8 = 0x41; - pub const I64_ATOMIC_RMW_XCHG: u8 = 0x42; - pub const I32_ATOMIC_RMW_XCHG8U: u8 = 0x43; - pub const I32_ATOMIC_RMW_XCHG16U: u8 = 0x44; - pub const I64_ATOMIC_RMW_XCHG8U: u8 = 0x45; - pub const I64_ATOMIC_RMW_XCHG16U: u8 = 0x46; - pub const I64_ATOMIC_RMW_XCHG32U: u8 = 0x47; - - pub const I32_ATOMIC_RMW_CMPXCHG: u8 = 0x48; - pub const I64_ATOMIC_RMW_CMPXCHG: u8 = 0x49; - pub const I32_ATOMIC_RMW_CMPXCHG8U: u8 = 0x4a; - pub const I32_ATOMIC_RMW_CMPXCHG16U: u8 = 0x4b; - pub const I64_ATOMIC_RMW_CMPXCHG8U: u8 = 0x4c; - pub const I64_ATOMIC_RMW_CMPXCHG16U: u8 = 0x4d; - pub const I64_ATOMIC_RMW_CMPXCHG32U: u8 = 0x4e; - - // https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md - pub const SIMD_PREFIX: u8 = 0xfd; - - pub const V128_LOAD: u32 = 0x00; - pub const V128_STORE: u32 = 0x01; - pub const V128_CONST: u32 = 0x02; - pub const V8X16_SHUFFLE: u32 = 0x03; - - pub const I8X16_SPLAT: u32 = 0x04; - pub const I8X16_EXTRACT_LANE_S: u32 = 0x05; - pub const I8X16_EXTRACT_LANE_U: u32 = 0x06; - pub const I8X16_REPLACE_LANE: u32 = 0x07; - pub const I16X8_SPLAT: u32 = 0x08; - pub const I16X8_EXTRACT_LANE_S: u32 = 0x09; - pub const I16X8_EXTRACT_LANE_U: u32 = 0xa; - pub const I16X8_REPLACE_LANE: u32 = 0x0b; - pub const I32X4_SPLAT: u32 = 0x0c; - pub const I32X4_EXTRACT_LANE: u32 = 0x0d; - pub const I32X4_REPLACE_LANE: u32 = 0x0e; - pub const I64X2_SPLAT: u32 = 0x0f; - pub const I64X2_EXTRACT_LANE: u32 = 0x10; - pub const I64X2_REPLACE_LANE: u32 = 0x11; - pub const F32X4_SPLAT: u32 = 0x12; - pub const F32X4_EXTRACT_LANE: u32 = 0x13; - pub const F32X4_REPLACE_LANE: u32 = 0x14; - pub const F64X2_SPLAT: u32 = 0x15; - pub const F64X2_EXTRACT_LANE: u32 = 0x16; - pub const F64X2_REPLACE_LANE: u32 = 0x17; - - pub const I8X16_EQ: u32 = 0x18; - pub const I8X16_NE: u32 = 0x19; - pub const I8X16_LT_S: u32 = 0x1a; - pub const I8X16_LT_U: u32 = 0x1b; - pub const I8X16_GT_S: u32 = 0x1c; - pub const I8X16_GT_U: u32 = 0x1d; - pub const I8X16_LE_S: u32 = 0x1e; - pub const I8X16_LE_U: u32 = 0x1f; - pub const I8X16_GE_S: u32 = 0x20; - pub const I8X16_GE_U: u32 = 0x21; - - pub const I16X8_EQ: u32 = 0x22; - pub const I16X8_NE: u32 = 0x23; - pub const I16X8_LT_S: u32 = 0x24; - pub const I16X8_LT_U: u32 = 0x25; - pub const I16X8_GT_S: u32 = 0x26; - pub const I16X8_GT_U: u32 = 0x27; - pub const I16X8_LE_S: u32 = 0x28; - pub const I16X8_LE_U: u32 = 0x29; - pub const I16X8_GE_S: u32 = 0x2a; - pub const I16X8_GE_U: u32 = 0x2b; - - pub const I32X4_EQ: u32 = 0x2c; - pub const I32X4_NE: u32 = 0x2d; - pub const I32X4_LT_S: u32 = 0x2e; - pub const I32X4_LT_U: u32 = 0x2f; - pub const I32X4_GT_S: u32 = 0x30; - pub const I32X4_GT_U: u32 = 0x31; - pub const I32X4_LE_S: u32 = 0x32; - pub const I32X4_LE_U: u32 = 0x33; - pub const I32X4_GE_S: u32 = 0x34; - pub const I32X4_GE_U: u32 = 0x35; - - pub const F32X4_EQ: u32 = 0x40; - pub const F32X4_NE: u32 = 0x41; - pub const F32X4_LT: u32 = 0x42; - pub const F32X4_GT: u32 = 0x43; - pub const F32X4_LE: u32 = 0x44; - pub const F32X4_GE: u32 = 0x45; - - pub const F64X2_EQ: u32 = 0x46; - pub const F64X2_NE: u32 = 0x47; - pub const F64X2_LT: u32 = 0x48; - pub const F64X2_GT: u32 = 0x49; - pub const F64X2_LE: u32 = 0x4a; - pub const F64X2_GE: u32 = 0x4b; - - pub const V128_NOT: u32 = 0x4c; - pub const V128_AND: u32 = 0x4d; - pub const V128_OR: u32 = 0x4e; - pub const V128_XOR: u32 = 0x4f; - pub const V128_BITSELECT: u32 = 0x50; - - pub const I8X16_NEG: u32 = 0x51; - pub const I8X16_ANY_TRUE: u32 = 0x52; - pub const I8X16_ALL_TRUE: u32 = 0x53; - pub const I8X16_SHL: u32 = 0x54; - pub const I8X16_SHR_S: u32 = 0x55; - pub const I8X16_SHR_U: u32 = 0x56; - pub const I8X16_ADD: u32 = 0x57; - pub const I8X16_ADD_SATURATE_S: u32 = 0x58; - pub const I8X16_ADD_SATURATE_U: u32 = 0x59; - pub const I8X16_SUB: u32 = 0x5a; - pub const I8X16_SUB_SATURATE_S: u32 = 0x5b; - pub const I8X16_SUB_SATURATE_U: u32 = 0x5c; - pub const I8X16_MUL: u32 = 0x5d; - - pub const I16X8_NEG: u32 = 0x62; - pub const I16X8_ANY_TRUE: u32 = 0x63; - pub const I16X8_ALL_TRUE: u32 = 0x64; - pub const I16X8_SHL: u32 = 0x65; - pub const I16X8_SHR_S: u32 = 0x66; - pub const I16X8_SHR_U: u32 = 0x67; - pub const I16X8_ADD: u32 = 0x68; - pub const I16X8_ADD_SATURATE_S: u32 = 0x69; - pub const I16X8_ADD_SATURATE_U: u32 = 0x6a; - pub const I16X8_SUB: u32 = 0x6b; - pub const I16X8_SUB_SATURATE_S: u32 = 0x6c; - pub const I16X8_SUB_SATURATE_U: u32 = 0x6d; - pub const I16X8_MUL: u32 = 0x6e; - - pub const I32X4_NEG: u32 = 0x73; - pub const I32X4_ANY_TRUE: u32 = 0x74; - pub const I32X4_ALL_TRUE: u32 = 0x75; - pub const I32X4_SHL: u32 = 0x76; - pub const I32X4_SHR_S: u32 = 0x77; - pub const I32X4_SHR_U: u32 = 0x78; - pub const I32X4_ADD: u32 = 0x79; - pub const I32X4_ADD_SATURATE_S: u32 = 0x7a; - pub const I32X4_ADD_SATURATE_U: u32 = 0x7b; - pub const I32X4_SUB: u32 = 0x7c; - pub const I32X4_SUB_SATURATE_S: u32 = 0x7d; - pub const I32X4_SUB_SATURATE_U: u32 = 0x7e; - pub const I32X4_MUL: u32 = 0x7f; - - pub const I64X2_NEG: u32 = 0x84; - pub const I64X2_ANY_TRUE: u32 = 0x85; - pub const I64X2_ALL_TRUE: u32 = 0x86; - pub const I64X2_SHL: u32 = 0x87; - pub const I64X2_SHR_S: u32 = 0x88; - pub const I64X2_SHR_U: u32 = 0x89; - pub const I64X2_ADD: u32 = 0x8a; - pub const I64X2_SUB: u32 = 0x8d; - - pub const F32X4_ABS: u32 = 0x95; - pub const F32X4_NEG: u32 = 0x96; - pub const F32X4_SQRT: u32 = 0x97; - pub const F32X4_ADD: u32 = 0x9a; - pub const F32X4_SUB: u32 = 0x9b; - pub const F32X4_MUL: u32 = 0x9c; - pub const F32X4_DIV: u32 = 0x9d; - pub const F32X4_MIN: u32 = 0x9e; - pub const F32X4_MAX: u32 = 0x9f; - - pub const F64X2_ABS: u32 = 0xa0; - pub const F64X2_NEG: u32 = 0xa1; - pub const F64X2_SQRT: u32 = 0xa2; - pub const F64X2_ADD: u32 = 0xa5; - pub const F64X2_SUB: u32 = 0xa6; - pub const F64X2_MUL: u32 = 0xa7; - pub const F64X2_DIV: u32 = 0xa8; - pub const F64X2_MIN: u32 = 0xa9; - pub const F64X2_MAX: u32 = 0xaa; - - pub const I32X4_TRUNC_S_F32X4_SAT: u32 = 0xab; - pub const I32X4_TRUNC_U_F32X4_SAT: u32 = 0xac; - pub const I64X2_TRUNC_S_F64X2_SAT: u32 = 0xad; - pub const I64X2_TRUNC_U_F64X2_SAT: u32 = 0xae; - - pub const F32X4_CONVERT_S_I32X4: u32 = 0xaf; - pub const F32X4_CONVERT_U_I32X4: u32 = 0xb0; - pub const F64X2_CONVERT_S_I64X2: u32 = 0xb1; - pub const F64X2_CONVERT_U_I64X2: u32 = 0xb2; - - pub const BULK_PREFIX: u8 = 0xfc; - pub const MEMORY_INIT: u8 = 0x08; - pub const MEMORY_DROP: u8 = 0x09; - pub const MEMORY_COPY: u8 = 0x0a; - pub const MEMORY_FILL: u8 = 0x0b; - pub const TABLE_INIT: u8 = 0x0c; - pub const TABLE_DROP: u8 = 0x0d; - pub const TABLE_COPY: u8 = 0x0e; + pub const UNREACHABLE: u8 = 0x00; + pub const NOP: u8 = 0x01; + pub const BLOCK: u8 = 0x02; + pub const LOOP: u8 = 0x03; + pub const IF: u8 = 0x04; + pub const ELSE: u8 = 0x05; + pub const END: u8 = 0x0b; + pub const BR: u8 = 0x0c; + pub const BRIF: u8 = 0x0d; + pub const BRTABLE: u8 = 0x0e; + pub const RETURN: u8 = 0x0f; + pub const CALL: u8 = 0x10; + pub const CALLINDIRECT: u8 = 0x11; + pub const DROP: u8 = 0x1a; + pub const SELECT: u8 = 0x1b; + pub const GETLOCAL: u8 = 0x20; + pub const SETLOCAL: u8 = 0x21; + pub const TEELOCAL: u8 = 0x22; + pub const GETGLOBAL: u8 = 0x23; + pub const SETGLOBAL: u8 = 0x24; + pub const I32LOAD: u8 = 0x28; + pub const I64LOAD: u8 = 0x29; + pub const F32LOAD: u8 = 0x2a; + pub const F64LOAD: u8 = 0x2b; + pub const I32LOAD8S: u8 = 0x2c; + pub const I32LOAD8U: u8 = 0x2d; + pub const I32LOAD16S: u8 = 0x2e; + pub const I32LOAD16U: u8 = 0x2f; + pub const I64LOAD8S: u8 = 0x30; + pub const I64LOAD8U: u8 = 0x31; + pub const I64LOAD16S: u8 = 0x32; + pub const I64LOAD16U: u8 = 0x33; + pub const I64LOAD32S: u8 = 0x34; + pub const I64LOAD32U: u8 = 0x35; + pub const I32STORE: u8 = 0x36; + pub const I64STORE: u8 = 0x37; + pub const F32STORE: u8 = 0x38; + pub const F64STORE: u8 = 0x39; + pub const I32STORE8: u8 = 0x3a; + pub const I32STORE16: u8 = 0x3b; + pub const I64STORE8: u8 = 0x3c; + pub const I64STORE16: u8 = 0x3d; + pub const I64STORE32: u8 = 0x3e; + pub const CURRENTMEMORY: u8 = 0x3f; + pub const GROWMEMORY: u8 = 0x40; + pub const I32CONST: u8 = 0x41; + pub const I64CONST: u8 = 0x42; + pub const F32CONST: u8 = 0x43; + pub const F64CONST: u8 = 0x44; + pub const I32EQZ: u8 = 0x45; + pub const I32EQ: u8 = 0x46; + pub const I32NE: u8 = 0x47; + pub const I32LTS: u8 = 0x48; + pub const I32LTU: u8 = 0x49; + pub const I32GTS: u8 = 0x4a; + pub const I32GTU: u8 = 0x4b; + pub const I32LES: u8 = 0x4c; + pub const I32LEU: u8 = 0x4d; + pub const I32GES: u8 = 0x4e; + pub const I32GEU: u8 = 0x4f; + pub const I64EQZ: u8 = 0x50; + pub const I64EQ: u8 = 0x51; + pub const I64NE: u8 = 0x52; + pub const I64LTS: u8 = 0x53; + pub const I64LTU: u8 = 0x54; + pub const I64GTS: u8 = 0x55; + pub const I64GTU: u8 = 0x56; + pub const I64LES: u8 = 0x57; + pub const I64LEU: u8 = 0x58; + pub const I64GES: u8 = 0x59; + pub const I64GEU: u8 = 0x5a; + + pub const F32EQ: u8 = 0x5b; + pub const F32NE: u8 = 0x5c; + pub const F32LT: u8 = 0x5d; + pub const F32GT: u8 = 0x5e; + pub const F32LE: u8 = 0x5f; + pub const F32GE: u8 = 0x60; + + pub const F64EQ: u8 = 0x61; + pub const F64NE: u8 = 0x62; + pub const F64LT: u8 = 0x63; + pub const F64GT: u8 = 0x64; + pub const F64LE: u8 = 0x65; + pub const F64GE: u8 = 0x66; + + pub const I32CLZ: u8 = 0x67; + pub const I32CTZ: u8 = 0x68; + pub const I32POPCNT: u8 = 0x69; + pub const I32ADD: u8 = 0x6a; + pub const I32SUB: u8 = 0x6b; + pub const I32MUL: u8 = 0x6c; + pub const I32DIVS: u8 = 0x6d; + pub const I32DIVU: u8 = 0x6e; + pub const I32REMS: u8 = 0x6f; + pub const I32REMU: u8 = 0x70; + pub const I32AND: u8 = 0x71; + pub const I32OR: u8 = 0x72; + pub const I32XOR: u8 = 0x73; + pub const I32SHL: u8 = 0x74; + pub const I32SHRS: u8 = 0x75; + pub const I32SHRU: u8 = 0x76; + pub const I32ROTL: u8 = 0x77; + pub const I32ROTR: u8 = 0x78; + + pub const I64CLZ: u8 = 0x79; + pub const I64CTZ: u8 = 0x7a; + pub const I64POPCNT: u8 = 0x7b; + pub const I64ADD: u8 = 0x7c; + pub const I64SUB: u8 = 0x7d; + pub const I64MUL: u8 = 0x7e; + pub const I64DIVS: u8 = 0x7f; + pub const I64DIVU: u8 = 0x80; + pub const I64REMS: u8 = 0x81; + pub const I64REMU: u8 = 0x82; + pub const I64AND: u8 = 0x83; + pub const I64OR: u8 = 0x84; + pub const I64XOR: u8 = 0x85; + pub const I64SHL: u8 = 0x86; + pub const I64SHRS: u8 = 0x87; + pub const I64SHRU: u8 = 0x88; + pub const I64ROTL: u8 = 0x89; + pub const I64ROTR: u8 = 0x8a; + pub const F32ABS: u8 = 0x8b; + pub const F32NEG: u8 = 0x8c; + pub const F32CEIL: u8 = 0x8d; + pub const F32FLOOR: u8 = 0x8e; + pub const F32TRUNC: u8 = 0x8f; + pub const F32NEAREST: u8 = 0x90; + pub const F32SQRT: u8 = 0x91; + pub const F32ADD: u8 = 0x92; + pub const F32SUB: u8 = 0x93; + pub const F32MUL: u8 = 0x94; + pub const F32DIV: u8 = 0x95; + pub const F32MIN: u8 = 0x96; + pub const F32MAX: u8 = 0x97; + pub const F32COPYSIGN: u8 = 0x98; + pub const F64ABS: u8 = 0x99; + pub const F64NEG: u8 = 0x9a; + pub const F64CEIL: u8 = 0x9b; + pub const F64FLOOR: u8 = 0x9c; + pub const F64TRUNC: u8 = 0x9d; + pub const F64NEAREST: u8 = 0x9e; + pub const F64SQRT: u8 = 0x9f; + pub const F64ADD: u8 = 0xa0; + pub const F64SUB: u8 = 0xa1; + pub const F64MUL: u8 = 0xa2; + pub const F64DIV: u8 = 0xa3; + pub const F64MIN: u8 = 0xa4; + pub const F64MAX: u8 = 0xa5; + pub const F64COPYSIGN: u8 = 0xa6; + + pub const I32WRAPI64: u8 = 0xa7; + pub const I32TRUNCSF32: u8 = 0xa8; + pub const I32TRUNCUF32: u8 = 0xa9; + pub const I32TRUNCSF64: u8 = 0xaa; + pub const I32TRUNCUF64: u8 = 0xab; + pub const I64EXTENDSI32: u8 = 0xac; + pub const I64EXTENDUI32: u8 = 0xad; + pub const I64TRUNCSF32: u8 = 0xae; + pub const I64TRUNCUF32: u8 = 0xaf; + pub const I64TRUNCSF64: u8 = 0xb0; + pub const I64TRUNCUF64: u8 = 0xb1; + pub const F32CONVERTSI32: u8 = 0xb2; + pub const F32CONVERTUI32: u8 = 0xb3; + pub const F32CONVERTSI64: u8 = 0xb4; + pub const F32CONVERTUI64: u8 = 0xb5; + pub const F32DEMOTEF64: u8 = 0xb6; + pub const F64CONVERTSI32: u8 = 0xb7; + pub const F64CONVERTUI32: u8 = 0xb8; + pub const F64CONVERTSI64: u8 = 0xb9; + pub const F64CONVERTUI64: u8 = 0xba; + pub const F64PROMOTEF32: u8 = 0xbb; + + pub const I32REINTERPRETF32: u8 = 0xbc; + pub const I64REINTERPRETF64: u8 = 0xbd; + pub const F32REINTERPRETI32: u8 = 0xbe; + pub const F64REINTERPRETI64: u8 = 0xbf; + + pub const I32_EXTEND8_S: u8 = 0xc0; + pub const I32_EXTEND16_S: u8 = 0xc1; + pub const I64_EXTEND8_S: u8 = 0xc2; + pub const I64_EXTEND16_S: u8 = 0xc3; + pub const I64_EXTEND32_S: u8 = 0xc4; + + pub const ATOMIC_PREFIX: u8 = 0xfe; + pub const ATOMIC_WAKE: u8 = 0x00; + pub const I32_ATOMIC_WAIT: u8 = 0x01; + pub const I64_ATOMIC_WAIT: u8 = 0x02; + + pub const I32_ATOMIC_LOAD: u8 = 0x10; + pub const I64_ATOMIC_LOAD: u8 = 0x11; + pub const I32_ATOMIC_LOAD8U: u8 = 0x12; + pub const I32_ATOMIC_LOAD16U: u8 = 0x13; + pub const I64_ATOMIC_LOAD8U: u8 = 0x14; + pub const I64_ATOMIC_LOAD16U: u8 = 0x15; + pub const I64_ATOMIC_LOAD32U: u8 = 0x16; + pub const I32_ATOMIC_STORE: u8 = 0x17; + pub const I64_ATOMIC_STORE: u8 = 0x18; + pub const I32_ATOMIC_STORE8U: u8 = 0x19; + pub const I32_ATOMIC_STORE16U: u8 = 0x1a; + pub const I64_ATOMIC_STORE8U: u8 = 0x1b; + pub const I64_ATOMIC_STORE16U: u8 = 0x1c; + pub const I64_ATOMIC_STORE32U: u8 = 0x1d; + + pub const I32_ATOMIC_RMW_ADD: u8 = 0x1e; + pub const I64_ATOMIC_RMW_ADD: u8 = 0x1f; + pub const I32_ATOMIC_RMW_ADD8U: u8 = 0x20; + pub const I32_ATOMIC_RMW_ADD16U: u8 = 0x21; + pub const I64_ATOMIC_RMW_ADD8U: u8 = 0x22; + pub const I64_ATOMIC_RMW_ADD16U: u8 = 0x23; + pub const I64_ATOMIC_RMW_ADD32U: u8 = 0x24; + + pub const I32_ATOMIC_RMW_SUB: u8 = 0x25; + pub const I64_ATOMIC_RMW_SUB: u8 = 0x26; + pub const I32_ATOMIC_RMW_SUB8U: u8 = 0x27; + pub const I32_ATOMIC_RMW_SUB16U: u8 = 0x28; + pub const I64_ATOMIC_RMW_SUB8U: u8 = 0x29; + pub const I64_ATOMIC_RMW_SUB16U: u8 = 0x2a; + pub const I64_ATOMIC_RMW_SUB32U: u8 = 0x2b; + + pub const I32_ATOMIC_RMW_AND: u8 = 0x2c; + pub const I64_ATOMIC_RMW_AND: u8 = 0x2d; + pub const I32_ATOMIC_RMW_AND8U: u8 = 0x2e; + pub const I32_ATOMIC_RMW_AND16U: u8 = 0x2f; + pub const I64_ATOMIC_RMW_AND8U: u8 = 0x30; + pub const I64_ATOMIC_RMW_AND16U: u8 = 0x31; + pub const I64_ATOMIC_RMW_AND32U: u8 = 0x32; + + pub const I32_ATOMIC_RMW_OR: u8 = 0x33; + pub const I64_ATOMIC_RMW_OR: u8 = 0x34; + pub const I32_ATOMIC_RMW_OR8U: u8 = 0x35; + pub const I32_ATOMIC_RMW_OR16U: u8 = 0x36; + pub const I64_ATOMIC_RMW_OR8U: u8 = 0x37; + pub const I64_ATOMIC_RMW_OR16U: u8 = 0x38; + pub const I64_ATOMIC_RMW_OR32U: u8 = 0x39; + + pub const I32_ATOMIC_RMW_XOR: u8 = 0x3a; + pub const I64_ATOMIC_RMW_XOR: u8 = 0x3b; + pub const I32_ATOMIC_RMW_XOR8U: u8 = 0x3c; + pub const I32_ATOMIC_RMW_XOR16U: u8 = 0x3d; + pub const I64_ATOMIC_RMW_XOR8U: u8 = 0x3e; + pub const I64_ATOMIC_RMW_XOR16U: u8 = 0x3f; + pub const I64_ATOMIC_RMW_XOR32U: u8 = 0x40; + + pub const I32_ATOMIC_RMW_XCHG: u8 = 0x41; + pub const I64_ATOMIC_RMW_XCHG: u8 = 0x42; + pub const I32_ATOMIC_RMW_XCHG8U: u8 = 0x43; + pub const I32_ATOMIC_RMW_XCHG16U: u8 = 0x44; + pub const I64_ATOMIC_RMW_XCHG8U: u8 = 0x45; + pub const I64_ATOMIC_RMW_XCHG16U: u8 = 0x46; + pub const I64_ATOMIC_RMW_XCHG32U: u8 = 0x47; + + pub const I32_ATOMIC_RMW_CMPXCHG: u8 = 0x48; + pub const I64_ATOMIC_RMW_CMPXCHG: u8 = 0x49; + pub const I32_ATOMIC_RMW_CMPXCHG8U: u8 = 0x4a; + pub const I32_ATOMIC_RMW_CMPXCHG16U: u8 = 0x4b; + pub const I64_ATOMIC_RMW_CMPXCHG8U: u8 = 0x4c; + pub const I64_ATOMIC_RMW_CMPXCHG16U: u8 = 0x4d; + pub const I64_ATOMIC_RMW_CMPXCHG32U: u8 = 0x4e; + + // https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md + pub const SIMD_PREFIX: u8 = 0xfd; + + pub const V128_LOAD: u32 = 0x00; + pub const V128_STORE: u32 = 0x01; + pub const V128_CONST: u32 = 0x02; + pub const V8X16_SHUFFLE: u32 = 0x03; + + pub const I8X16_SPLAT: u32 = 0x04; + pub const I8X16_EXTRACT_LANE_S: u32 = 0x05; + pub const I8X16_EXTRACT_LANE_U: u32 = 0x06; + pub const I8X16_REPLACE_LANE: u32 = 0x07; + pub const I16X8_SPLAT: u32 = 0x08; + pub const I16X8_EXTRACT_LANE_S: u32 = 0x09; + pub const I16X8_EXTRACT_LANE_U: u32 = 0xa; + pub const I16X8_REPLACE_LANE: u32 = 0x0b; + pub const I32X4_SPLAT: u32 = 0x0c; + pub const I32X4_EXTRACT_LANE: u32 = 0x0d; + pub const I32X4_REPLACE_LANE: u32 = 0x0e; + pub const I64X2_SPLAT: u32 = 0x0f; + pub const I64X2_EXTRACT_LANE: u32 = 0x10; + pub const I64X2_REPLACE_LANE: u32 = 0x11; + pub const F32X4_SPLAT: u32 = 0x12; + pub const F32X4_EXTRACT_LANE: u32 = 0x13; + pub const F32X4_REPLACE_LANE: u32 = 0x14; + pub const F64X2_SPLAT: u32 = 0x15; + pub const F64X2_EXTRACT_LANE: u32 = 0x16; + pub const F64X2_REPLACE_LANE: u32 = 0x17; + + pub const I8X16_EQ: u32 = 0x18; + pub const I8X16_NE: u32 = 0x19; + pub const I8X16_LT_S: u32 = 0x1a; + pub const I8X16_LT_U: u32 = 0x1b; + pub const I8X16_GT_S: u32 = 0x1c; + pub const I8X16_GT_U: u32 = 0x1d; + pub const I8X16_LE_S: u32 = 0x1e; + pub const I8X16_LE_U: u32 = 0x1f; + pub const I8X16_GE_S: u32 = 0x20; + pub const I8X16_GE_U: u32 = 0x21; + + pub const I16X8_EQ: u32 = 0x22; + pub const I16X8_NE: u32 = 0x23; + pub const I16X8_LT_S: u32 = 0x24; + pub const I16X8_LT_U: u32 = 0x25; + pub const I16X8_GT_S: u32 = 0x26; + pub const I16X8_GT_U: u32 = 0x27; + pub const I16X8_LE_S: u32 = 0x28; + pub const I16X8_LE_U: u32 = 0x29; + pub const I16X8_GE_S: u32 = 0x2a; + pub const I16X8_GE_U: u32 = 0x2b; + + pub const I32X4_EQ: u32 = 0x2c; + pub const I32X4_NE: u32 = 0x2d; + pub const I32X4_LT_S: u32 = 0x2e; + pub const I32X4_LT_U: u32 = 0x2f; + pub const I32X4_GT_S: u32 = 0x30; + pub const I32X4_GT_U: u32 = 0x31; + pub const I32X4_LE_S: u32 = 0x32; + pub const I32X4_LE_U: u32 = 0x33; + pub const I32X4_GE_S: u32 = 0x34; + pub const I32X4_GE_U: u32 = 0x35; + + pub const F32X4_EQ: u32 = 0x40; + pub const F32X4_NE: u32 = 0x41; + pub const F32X4_LT: u32 = 0x42; + pub const F32X4_GT: u32 = 0x43; + pub const F32X4_LE: u32 = 0x44; + pub const F32X4_GE: u32 = 0x45; + + pub const F64X2_EQ: u32 = 0x46; + pub const F64X2_NE: u32 = 0x47; + pub const F64X2_LT: u32 = 0x48; + pub const F64X2_GT: u32 = 0x49; + pub const F64X2_LE: u32 = 0x4a; + pub const F64X2_GE: u32 = 0x4b; + + pub const V128_NOT: u32 = 0x4c; + pub const V128_AND: u32 = 0x4d; + pub const V128_OR: u32 = 0x4e; + pub const V128_XOR: u32 = 0x4f; + pub const V128_BITSELECT: u32 = 0x50; + + pub const I8X16_NEG: u32 = 0x51; + pub const I8X16_ANY_TRUE: u32 = 0x52; + pub const I8X16_ALL_TRUE: u32 = 0x53; + pub const I8X16_SHL: u32 = 0x54; + pub const I8X16_SHR_S: u32 = 0x55; + pub const I8X16_SHR_U: u32 = 0x56; + pub const I8X16_ADD: u32 = 0x57; + pub const I8X16_ADD_SATURATE_S: u32 = 0x58; + pub const I8X16_ADD_SATURATE_U: u32 = 0x59; + pub const I8X16_SUB: u32 = 0x5a; + pub const I8X16_SUB_SATURATE_S: u32 = 0x5b; + pub const I8X16_SUB_SATURATE_U: u32 = 0x5c; + pub const I8X16_MUL: u32 = 0x5d; + + pub const I16X8_NEG: u32 = 0x62; + pub const I16X8_ANY_TRUE: u32 = 0x63; + pub const I16X8_ALL_TRUE: u32 = 0x64; + pub const I16X8_SHL: u32 = 0x65; + pub const I16X8_SHR_S: u32 = 0x66; + pub const I16X8_SHR_U: u32 = 0x67; + pub const I16X8_ADD: u32 = 0x68; + pub const I16X8_ADD_SATURATE_S: u32 = 0x69; + pub const I16X8_ADD_SATURATE_U: u32 = 0x6a; + pub const I16X8_SUB: u32 = 0x6b; + pub const I16X8_SUB_SATURATE_S: u32 = 0x6c; + pub const I16X8_SUB_SATURATE_U: u32 = 0x6d; + pub const I16X8_MUL: u32 = 0x6e; + + pub const I32X4_NEG: u32 = 0x73; + pub const I32X4_ANY_TRUE: u32 = 0x74; + pub const I32X4_ALL_TRUE: u32 = 0x75; + pub const I32X4_SHL: u32 = 0x76; + pub const I32X4_SHR_S: u32 = 0x77; + pub const I32X4_SHR_U: u32 = 0x78; + pub const I32X4_ADD: u32 = 0x79; + pub const I32X4_ADD_SATURATE_S: u32 = 0x7a; + pub const I32X4_ADD_SATURATE_U: u32 = 0x7b; + pub const I32X4_SUB: u32 = 0x7c; + pub const I32X4_SUB_SATURATE_S: u32 = 0x7d; + pub const I32X4_SUB_SATURATE_U: u32 = 0x7e; + pub const I32X4_MUL: u32 = 0x7f; + + pub const I64X2_NEG: u32 = 0x84; + pub const I64X2_ANY_TRUE: u32 = 0x85; + pub const I64X2_ALL_TRUE: u32 = 0x86; + pub const I64X2_SHL: u32 = 0x87; + pub const I64X2_SHR_S: u32 = 0x88; + pub const I64X2_SHR_U: u32 = 0x89; + pub const I64X2_ADD: u32 = 0x8a; + pub const I64X2_SUB: u32 = 0x8d; + + pub const F32X4_ABS: u32 = 0x95; + pub const F32X4_NEG: u32 = 0x96; + pub const F32X4_SQRT: u32 = 0x97; + pub const F32X4_ADD: u32 = 0x9a; + pub const F32X4_SUB: u32 = 0x9b; + pub const F32X4_MUL: u32 = 0x9c; + pub const F32X4_DIV: u32 = 0x9d; + pub const F32X4_MIN: u32 = 0x9e; + pub const F32X4_MAX: u32 = 0x9f; + + pub const F64X2_ABS: u32 = 0xa0; + pub const F64X2_NEG: u32 = 0xa1; + pub const F64X2_SQRT: u32 = 0xa2; + pub const F64X2_ADD: u32 = 0xa5; + pub const F64X2_SUB: u32 = 0xa6; + pub const F64X2_MUL: u32 = 0xa7; + pub const F64X2_DIV: u32 = 0xa8; + pub const F64X2_MIN: u32 = 0xa9; + pub const F64X2_MAX: u32 = 0xaa; + + pub const I32X4_TRUNC_S_F32X4_SAT: u32 = 0xab; + pub const I32X4_TRUNC_U_F32X4_SAT: u32 = 0xac; + pub const I64X2_TRUNC_S_F64X2_SAT: u32 = 0xad; + pub const I64X2_TRUNC_U_F64X2_SAT: u32 = 0xae; + + pub const F32X4_CONVERT_S_I32X4: u32 = 0xaf; + pub const F32X4_CONVERT_U_I32X4: u32 = 0xb0; + pub const F64X2_CONVERT_S_I64X2: u32 = 0xb1; + pub const F64X2_CONVERT_U_I64X2: u32 = 0xb2; + + pub const BULK_PREFIX: u8 = 0xfc; + pub const MEMORY_INIT: u8 = 0x08; + pub const MEMORY_DROP: u8 = 0x09; + pub const MEMORY_COPY: u8 = 0x0a; + pub const MEMORY_FILL: u8 = 0x0b; + pub const TABLE_INIT: u8 = 0x0c; + pub const TABLE_DROP: u8 = 0x0d; + pub const TABLE_COPY: u8 = 0x0e; } impl Deserialize for Instruction { - type Error = Error; - - fn deserialize(reader: &mut R) -> Result { - use self::Instruction::*; - use self::opcodes::*; - - let val: u8 = Uint8::deserialize(reader)?.into(); - - Ok( - match val { - UNREACHABLE => Unreachable, - NOP => Nop, - BLOCK => Block(BlockType::deserialize(reader)?), - LOOP => Loop(BlockType::deserialize(reader)?), - IF => If(BlockType::deserialize(reader)?), - ELSE => Else, - END => End, - - BR => Br(VarUint32::deserialize(reader)?.into()), - BRIF => BrIf(VarUint32::deserialize(reader)?.into()), - BRTABLE => { - let t1: Vec = CountedList::::deserialize(reader)? - .into_inner() - .into_iter() - .map(Into::into) - .collect(); - - BrTable(Box::new(BrTableData { - table: t1.into_boxed_slice(), - default: VarUint32::deserialize(reader)?.into(), - })) - }, - RETURN => Return, - CALL => Call(VarUint32::deserialize(reader)?.into()), - CALLINDIRECT => { - let signature: u32 = VarUint32::deserialize(reader)?.into(); - let table_ref: u8 = Uint8::deserialize(reader)?.into(); - if table_ref != 0 { return Err(Error::InvalidTableReference(table_ref)); } - - CallIndirect( - signature, - table_ref, - ) - }, - DROP => Drop, - SELECT => Select, - - GETLOCAL => GetLocal(VarUint32::deserialize(reader)?.into()), - SETLOCAL => SetLocal(VarUint32::deserialize(reader)?.into()), - TEELOCAL => TeeLocal(VarUint32::deserialize(reader)?.into()), - GETGLOBAL => GetGlobal(VarUint32::deserialize(reader)?.into()), - SETGLOBAL => SetGlobal(VarUint32::deserialize(reader)?.into()), - - I32LOAD => I32Load( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I64LOAD => I64Load( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - F32LOAD => F32Load( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - F64LOAD => F64Load( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I32LOAD8S => I32Load8S( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I32LOAD8U => I32Load8U( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I32LOAD16S => I32Load16S( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I32LOAD16U => I32Load16U( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I64LOAD8S => I64Load8S( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I64LOAD8U => I64Load8U( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I64LOAD16S => I64Load16S( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I64LOAD16U => I64Load16U( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I64LOAD32S => I64Load32S( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I64LOAD32U => I64Load32U( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I32STORE => I32Store( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I64STORE => I64Store( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - F32STORE => F32Store( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - F64STORE => F64Store( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I32STORE8 => I32Store8( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I32STORE16 => I32Store16( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I64STORE8 => I64Store8( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I64STORE16 => I64Store16( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - I64STORE32 => I64Store32( - VarUint32::deserialize(reader)?.into(), - VarUint32::deserialize(reader)?.into()), - - - CURRENTMEMORY => { - let mem_ref: u8 = Uint8::deserialize(reader)?.into(); - if mem_ref != 0 { return Err(Error::InvalidMemoryReference(mem_ref)); } - CurrentMemory(mem_ref) - }, - GROWMEMORY => { - let mem_ref: u8 = Uint8::deserialize(reader)?.into(); - if mem_ref != 0 { return Err(Error::InvalidMemoryReference(mem_ref)); } - GrowMemory(mem_ref) - } - - I32CONST => I32Const(VarInt32::deserialize(reader)?.into()), - I64CONST => I64Const(VarInt64::deserialize(reader)?.into()), - F32CONST => F32Const(Uint32::deserialize(reader)?.into()), - F64CONST => F64Const(Uint64::deserialize(reader)?.into()), - I32EQZ => I32Eqz, - I32EQ => I32Eq, - I32NE => I32Ne, - I32LTS => I32LtS, - I32LTU => I32LtU, - I32GTS => I32GtS, - I32GTU => I32GtU, - I32LES => I32LeS, - I32LEU => I32LeU, - I32GES => I32GeS, - I32GEU => I32GeU, - - I64EQZ => I64Eqz, - I64EQ => I64Eq, - I64NE => I64Ne, - I64LTS => I64LtS, - I64LTU => I64LtU, - I64GTS => I64GtS, - I64GTU => I64GtU, - I64LES => I64LeS, - I64LEU => I64LeU, - I64GES => I64GeS, - I64GEU => I64GeU, - - F32EQ => F32Eq, - F32NE => F32Ne, - F32LT => F32Lt, - F32GT => F32Gt, - F32LE => F32Le, - F32GE => F32Ge, - - F64EQ => F64Eq, - F64NE => F64Ne, - F64LT => F64Lt, - F64GT => F64Gt, - F64LE => F64Le, - F64GE => F64Ge, - - I32CLZ => I32Clz, - I32CTZ => I32Ctz, - I32POPCNT => I32Popcnt, - I32ADD => I32Add, - I32SUB => I32Sub, - I32MUL => I32Mul, - I32DIVS => I32DivS, - I32DIVU => I32DivU, - I32REMS => I32RemS, - I32REMU => I32RemU, - I32AND => I32And, - I32OR => I32Or, - I32XOR => I32Xor, - I32SHL => I32Shl, - I32SHRS => I32ShrS, - I32SHRU => I32ShrU, - I32ROTL => I32Rotl, - I32ROTR => I32Rotr, - - I64CLZ => I64Clz, - I64CTZ => I64Ctz, - I64POPCNT => I64Popcnt, - I64ADD => I64Add, - I64SUB => I64Sub, - I64MUL => I64Mul, - I64DIVS => I64DivS, - I64DIVU => I64DivU, - I64REMS => I64RemS, - I64REMU => I64RemU, - I64AND => I64And, - I64OR => I64Or, - I64XOR => I64Xor, - I64SHL => I64Shl, - I64SHRS => I64ShrS, - I64SHRU => I64ShrU, - I64ROTL => I64Rotl, - I64ROTR => I64Rotr, - F32ABS => F32Abs, - F32NEG => F32Neg, - F32CEIL => F32Ceil, - F32FLOOR => F32Floor, - F32TRUNC => F32Trunc, - F32NEAREST => F32Nearest, - F32SQRT => F32Sqrt, - F32ADD => F32Add, - F32SUB => F32Sub, - F32MUL => F32Mul, - F32DIV => F32Div, - F32MIN => F32Min, - F32MAX => F32Max, - F32COPYSIGN => F32Copysign, - F64ABS => F64Abs, - F64NEG => F64Neg, - F64CEIL => F64Ceil, - F64FLOOR => F64Floor, - F64TRUNC => F64Trunc, - F64NEAREST => F64Nearest, - F64SQRT => F64Sqrt, - F64ADD => F64Add, - F64SUB => F64Sub, - F64MUL => F64Mul, - F64DIV => F64Div, - F64MIN => F64Min, - F64MAX => F64Max, - F64COPYSIGN => F64Copysign, - - I32WRAPI64 => I32WrapI64, - I32TRUNCSF32 => I32TruncSF32, - I32TRUNCUF32 => I32TruncUF32, - I32TRUNCSF64 => I32TruncSF64, - I32TRUNCUF64 => I32TruncUF64, - I64EXTENDSI32 => I64ExtendSI32, - I64EXTENDUI32 => I64ExtendUI32, - I64TRUNCSF32 => I64TruncSF32, - I64TRUNCUF32 => I64TruncUF32, - I64TRUNCSF64 => I64TruncSF64, - I64TRUNCUF64 => I64TruncUF64, - F32CONVERTSI32 => F32ConvertSI32, - F32CONVERTUI32 => F32ConvertUI32, - F32CONVERTSI64 => F32ConvertSI64, - F32CONVERTUI64 => F32ConvertUI64, - F32DEMOTEF64 => F32DemoteF64, - F64CONVERTSI32 => F64ConvertSI32, - F64CONVERTUI32 => F64ConvertUI32, - F64CONVERTSI64 => F64ConvertSI64, - F64CONVERTUI64 => F64ConvertUI64, - F64PROMOTEF32 => F64PromoteF32, - - I32REINTERPRETF32 => I32ReinterpretF32, - I64REINTERPRETF64 => I64ReinterpretF64, - F32REINTERPRETI32 => F32ReinterpretI32, - F64REINTERPRETI64 => F64ReinterpretI64, - I32_EXTEND8_S => I32Extend8S, - I32_EXTEND16_S => I32Extend16S, - I64_EXTEND8_S => I64Extend8S, - I64_EXTEND16_S => I64Extend16S, - I64_EXTEND32_S => I64Extend32S, - - ATOMIC_PREFIX => return deserialize_atomic(reader), - SIMD_PREFIX => return deserialize_simd(reader), - - BULK_PREFIX => return deserialize_bulk(reader), - - _ => { return Err(Error::UnknownOpcode(val)); } - } - ) - } + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + use self::Instruction::*; + use self::opcodes::*; + + let val: u8 = Uint8::deserialize(reader)?.into(); + + Ok( + match val { + UNREACHABLE => Unreachable, + NOP => Nop, + BLOCK => Block(BlockType::deserialize(reader)?), + LOOP => Loop(BlockType::deserialize(reader)?), + IF => If(BlockType::deserialize(reader)?), + ELSE => Else, + END => End, + + BR => Br(VarUint32::deserialize(reader)?.into()), + BRIF => BrIf(VarUint32::deserialize(reader)?.into()), + BRTABLE => { + let t1: Vec = CountedList::::deserialize(reader)? + .into_inner() + .into_iter() + .map(Into::into) + .collect(); + + BrTable(Box::new(BrTableData { + table: t1.into_boxed_slice(), + default: VarUint32::deserialize(reader)?.into(), + })) + }, + RETURN => Return, + CALL => Call(VarUint32::deserialize(reader)?.into()), + CALLINDIRECT => { + let signature: u32 = VarUint32::deserialize(reader)?.into(); + let table_ref: u8 = Uint8::deserialize(reader)?.into(); + if table_ref != 0 { return Err(Error::InvalidTableReference(table_ref)); } + + CallIndirect( + signature, + table_ref, + ) + }, + DROP => Drop, + SELECT => Select, + + GETLOCAL => GetLocal(VarUint32::deserialize(reader)?.into()), + SETLOCAL => SetLocal(VarUint32::deserialize(reader)?.into()), + TEELOCAL => TeeLocal(VarUint32::deserialize(reader)?.into()), + GETGLOBAL => GetGlobal(VarUint32::deserialize(reader)?.into()), + SETGLOBAL => SetGlobal(VarUint32::deserialize(reader)?.into()), + + I32LOAD => I32Load( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64LOAD => I64Load( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + F32LOAD => F32Load( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + F64LOAD => F64Load( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I32LOAD8S => I32Load8S( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I32LOAD8U => I32Load8U( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I32LOAD16S => I32Load16S( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I32LOAD16U => I32Load16U( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64LOAD8S => I64Load8S( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64LOAD8U => I64Load8U( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64LOAD16S => I64Load16S( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64LOAD16U => I64Load16U( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64LOAD32S => I64Load32S( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64LOAD32U => I64Load32U( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I32STORE => I32Store( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64STORE => I64Store( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + F32STORE => F32Store( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + F64STORE => F64Store( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I32STORE8 => I32Store8( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I32STORE16 => I32Store16( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64STORE8 => I64Store8( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64STORE16 => I64Store16( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + I64STORE32 => I64Store32( + VarUint32::deserialize(reader)?.into(), + VarUint32::deserialize(reader)?.into()), + + + CURRENTMEMORY => { + let mem_ref: u8 = Uint8::deserialize(reader)?.into(); + if mem_ref != 0 { return Err(Error::InvalidMemoryReference(mem_ref)); } + CurrentMemory(mem_ref) + }, + GROWMEMORY => { + let mem_ref: u8 = Uint8::deserialize(reader)?.into(); + if mem_ref != 0 { return Err(Error::InvalidMemoryReference(mem_ref)); } + GrowMemory(mem_ref) + } + + I32CONST => I32Const(VarInt32::deserialize(reader)?.into()), + I64CONST => I64Const(VarInt64::deserialize(reader)?.into()), + F32CONST => F32Const(Uint32::deserialize(reader)?.into()), + F64CONST => F64Const(Uint64::deserialize(reader)?.into()), + I32EQZ => I32Eqz, + I32EQ => I32Eq, + I32NE => I32Ne, + I32LTS => I32LtS, + I32LTU => I32LtU, + I32GTS => I32GtS, + I32GTU => I32GtU, + I32LES => I32LeS, + I32LEU => I32LeU, + I32GES => I32GeS, + I32GEU => I32GeU, + + I64EQZ => I64Eqz, + I64EQ => I64Eq, + I64NE => I64Ne, + I64LTS => I64LtS, + I64LTU => I64LtU, + I64GTS => I64GtS, + I64GTU => I64GtU, + I64LES => I64LeS, + I64LEU => I64LeU, + I64GES => I64GeS, + I64GEU => I64GeU, + + F32EQ => F32Eq, + F32NE => F32Ne, + F32LT => F32Lt, + F32GT => F32Gt, + F32LE => F32Le, + F32GE => F32Ge, + + F64EQ => F64Eq, + F64NE => F64Ne, + F64LT => F64Lt, + F64GT => F64Gt, + F64LE => F64Le, + F64GE => F64Ge, + + I32CLZ => I32Clz, + I32CTZ => I32Ctz, + I32POPCNT => I32Popcnt, + I32ADD => I32Add, + I32SUB => I32Sub, + I32MUL => I32Mul, + I32DIVS => I32DivS, + I32DIVU => I32DivU, + I32REMS => I32RemS, + I32REMU => I32RemU, + I32AND => I32And, + I32OR => I32Or, + I32XOR => I32Xor, + I32SHL => I32Shl, + I32SHRS => I32ShrS, + I32SHRU => I32ShrU, + I32ROTL => I32Rotl, + I32ROTR => I32Rotr, + + I64CLZ => I64Clz, + I64CTZ => I64Ctz, + I64POPCNT => I64Popcnt, + I64ADD => I64Add, + I64SUB => I64Sub, + I64MUL => I64Mul, + I64DIVS => I64DivS, + I64DIVU => I64DivU, + I64REMS => I64RemS, + I64REMU => I64RemU, + I64AND => I64And, + I64OR => I64Or, + I64XOR => I64Xor, + I64SHL => I64Shl, + I64SHRS => I64ShrS, + I64SHRU => I64ShrU, + I64ROTL => I64Rotl, + I64ROTR => I64Rotr, + F32ABS => F32Abs, + F32NEG => F32Neg, + F32CEIL => F32Ceil, + F32FLOOR => F32Floor, + F32TRUNC => F32Trunc, + F32NEAREST => F32Nearest, + F32SQRT => F32Sqrt, + F32ADD => F32Add, + F32SUB => F32Sub, + F32MUL => F32Mul, + F32DIV => F32Div, + F32MIN => F32Min, + F32MAX => F32Max, + F32COPYSIGN => F32Copysign, + F64ABS => F64Abs, + F64NEG => F64Neg, + F64CEIL => F64Ceil, + F64FLOOR => F64Floor, + F64TRUNC => F64Trunc, + F64NEAREST => F64Nearest, + F64SQRT => F64Sqrt, + F64ADD => F64Add, + F64SUB => F64Sub, + F64MUL => F64Mul, + F64DIV => F64Div, + F64MIN => F64Min, + F64MAX => F64Max, + F64COPYSIGN => F64Copysign, + + I32WRAPI64 => I32WrapI64, + I32TRUNCSF32 => I32TruncSF32, + I32TRUNCUF32 => I32TruncUF32, + I32TRUNCSF64 => I32TruncSF64, + I32TRUNCUF64 => I32TruncUF64, + I64EXTENDSI32 => I64ExtendSI32, + I64EXTENDUI32 => I64ExtendUI32, + I64TRUNCSF32 => I64TruncSF32, + I64TRUNCUF32 => I64TruncUF32, + I64TRUNCSF64 => I64TruncSF64, + I64TRUNCUF64 => I64TruncUF64, + F32CONVERTSI32 => F32ConvertSI32, + F32CONVERTUI32 => F32ConvertUI32, + F32CONVERTSI64 => F32ConvertSI64, + F32CONVERTUI64 => F32ConvertUI64, + F32DEMOTEF64 => F32DemoteF64, + F64CONVERTSI32 => F64ConvertSI32, + F64CONVERTUI32 => F64ConvertUI32, + F64CONVERTSI64 => F64ConvertSI64, + F64CONVERTUI64 => F64ConvertUI64, + F64PROMOTEF32 => F64PromoteF32, + + I32REINTERPRETF32 => I32ReinterpretF32, + I64REINTERPRETF64 => I64ReinterpretF64, + F32REINTERPRETI32 => F32ReinterpretI32, + F64REINTERPRETI64 => F64ReinterpretI64, + I32_EXTEND8_S => I32Extend8S, + I32_EXTEND16_S => I32Extend16S, + I64_EXTEND8_S => I64Extend8S, + I64_EXTEND16_S => I64Extend16S, + I64_EXTEND32_S => I64Extend32S, + + ATOMIC_PREFIX => return deserialize_atomic(reader), + SIMD_PREFIX => return deserialize_simd(reader), + + BULK_PREFIX => return deserialize_bulk(reader), + + _ => { return Err(Error::UnknownOpcode(val)); } + } + ) + } } fn deserialize_atomic(reader: &mut R) -> Result { - use self::Instruction::*; - use self::opcodes::*; - - let val: u8 = Uint8::deserialize(reader)?.into(); - let mem = MemArg::deserialize(reader)?; - Ok(match val { - ATOMIC_WAKE => AtomicWake(mem), - I32_ATOMIC_WAIT => I32AtomicWait(mem), - I64_ATOMIC_WAIT => I64AtomicWait(mem), - - I32_ATOMIC_LOAD => I32AtomicLoad(mem), - I64_ATOMIC_LOAD => I64AtomicLoad(mem), - I32_ATOMIC_LOAD8U => I32AtomicLoad8u(mem), - I32_ATOMIC_LOAD16U => I32AtomicLoad16u(mem), - I64_ATOMIC_LOAD8U => I64AtomicLoad8u(mem), - I64_ATOMIC_LOAD16U => I64AtomicLoad16u(mem), - I64_ATOMIC_LOAD32U => I64AtomicLoad32u(mem), - I32_ATOMIC_STORE => I32AtomicStore(mem), - I64_ATOMIC_STORE => I64AtomicStore(mem), - I32_ATOMIC_STORE8U => I32AtomicStore8u(mem), - I32_ATOMIC_STORE16U => I32AtomicStore16u(mem), - I64_ATOMIC_STORE8U => I64AtomicStore8u(mem), - I64_ATOMIC_STORE16U => I64AtomicStore16u(mem), - I64_ATOMIC_STORE32U => I64AtomicStore32u(mem), - - I32_ATOMIC_RMW_ADD => I32AtomicRmwAdd(mem), - I64_ATOMIC_RMW_ADD => I64AtomicRmwAdd(mem), - I32_ATOMIC_RMW_ADD8U => I32AtomicRmwAdd8u(mem), - I32_ATOMIC_RMW_ADD16U => I32AtomicRmwAdd16u(mem), - I64_ATOMIC_RMW_ADD8U => I64AtomicRmwAdd8u(mem), - I64_ATOMIC_RMW_ADD16U => I64AtomicRmwAdd16u(mem), - I64_ATOMIC_RMW_ADD32U => I64AtomicRmwAdd32u(mem), - - I32_ATOMIC_RMW_SUB => I32AtomicRmwSub(mem), - I64_ATOMIC_RMW_SUB => I64AtomicRmwSub(mem), - I32_ATOMIC_RMW_SUB8U => I32AtomicRmwSub8u(mem), - I32_ATOMIC_RMW_SUB16U => I32AtomicRmwSub16u(mem), - I64_ATOMIC_RMW_SUB8U => I64AtomicRmwSub8u(mem), - I64_ATOMIC_RMW_SUB16U => I64AtomicRmwSub16u(mem), - I64_ATOMIC_RMW_SUB32U => I64AtomicRmwSub32u(mem), - - I32_ATOMIC_RMW_OR => I32AtomicRmwOr(mem), - I64_ATOMIC_RMW_OR => I64AtomicRmwOr(mem), - I32_ATOMIC_RMW_OR8U => I32AtomicRmwOr8u(mem), - I32_ATOMIC_RMW_OR16U => I32AtomicRmwOr16u(mem), - I64_ATOMIC_RMW_OR8U => I64AtomicRmwOr8u(mem), - I64_ATOMIC_RMW_OR16U => I64AtomicRmwOr16u(mem), - I64_ATOMIC_RMW_OR32U => I64AtomicRmwOr32u(mem), - - I32_ATOMIC_RMW_XOR => I32AtomicRmwXor(mem), - I64_ATOMIC_RMW_XOR => I64AtomicRmwXor(mem), - I32_ATOMIC_RMW_XOR8U => I32AtomicRmwXor8u(mem), - I32_ATOMIC_RMW_XOR16U => I32AtomicRmwXor16u(mem), - I64_ATOMIC_RMW_XOR8U => I64AtomicRmwXor8u(mem), - I64_ATOMIC_RMW_XOR16U => I64AtomicRmwXor16u(mem), - I64_ATOMIC_RMW_XOR32U => I64AtomicRmwXor32u(mem), - - I32_ATOMIC_RMW_XCHG => I32AtomicRmwXchg(mem), - I64_ATOMIC_RMW_XCHG => I64AtomicRmwXchg(mem), - I32_ATOMIC_RMW_XCHG8U => I32AtomicRmwXchg8u(mem), - I32_ATOMIC_RMW_XCHG16U => I32AtomicRmwXchg16u(mem), - I64_ATOMIC_RMW_XCHG8U => I64AtomicRmwXchg8u(mem), - I64_ATOMIC_RMW_XCHG16U => I64AtomicRmwXchg16u(mem), - I64_ATOMIC_RMW_XCHG32U => I64AtomicRmwXchg32u(mem), - - I32_ATOMIC_RMW_CMPXCHG => I32AtomicRmwCmpxchg(mem), - I64_ATOMIC_RMW_CMPXCHG => I64AtomicRmwCmpxchg(mem), - I32_ATOMIC_RMW_CMPXCHG8U => I32AtomicRmwCmpxchg8u(mem), - I32_ATOMIC_RMW_CMPXCHG16U => I32AtomicRmwCmpxchg16u(mem), - I64_ATOMIC_RMW_CMPXCHG8U => I64AtomicRmwCmpxchg8u(mem), - I64_ATOMIC_RMW_CMPXCHG16U => I64AtomicRmwCmpxchg16u(mem), - I64_ATOMIC_RMW_CMPXCHG32U => I64AtomicRmwCmpxchg32u(mem), - - _ => return Err(Error::UnknownOpcode(val)), - }) + use self::Instruction::*; + use self::opcodes::*; + + let val: u8 = Uint8::deserialize(reader)?.into(); + let mem = MemArg::deserialize(reader)?; + Ok(match val { + ATOMIC_WAKE => AtomicWake(mem), + I32_ATOMIC_WAIT => I32AtomicWait(mem), + I64_ATOMIC_WAIT => I64AtomicWait(mem), + + I32_ATOMIC_LOAD => I32AtomicLoad(mem), + I64_ATOMIC_LOAD => I64AtomicLoad(mem), + I32_ATOMIC_LOAD8U => I32AtomicLoad8u(mem), + I32_ATOMIC_LOAD16U => I32AtomicLoad16u(mem), + I64_ATOMIC_LOAD8U => I64AtomicLoad8u(mem), + I64_ATOMIC_LOAD16U => I64AtomicLoad16u(mem), + I64_ATOMIC_LOAD32U => I64AtomicLoad32u(mem), + I32_ATOMIC_STORE => I32AtomicStore(mem), + I64_ATOMIC_STORE => I64AtomicStore(mem), + I32_ATOMIC_STORE8U => I32AtomicStore8u(mem), + I32_ATOMIC_STORE16U => I32AtomicStore16u(mem), + I64_ATOMIC_STORE8U => I64AtomicStore8u(mem), + I64_ATOMIC_STORE16U => I64AtomicStore16u(mem), + I64_ATOMIC_STORE32U => I64AtomicStore32u(mem), + + I32_ATOMIC_RMW_ADD => I32AtomicRmwAdd(mem), + I64_ATOMIC_RMW_ADD => I64AtomicRmwAdd(mem), + I32_ATOMIC_RMW_ADD8U => I32AtomicRmwAdd8u(mem), + I32_ATOMIC_RMW_ADD16U => I32AtomicRmwAdd16u(mem), + I64_ATOMIC_RMW_ADD8U => I64AtomicRmwAdd8u(mem), + I64_ATOMIC_RMW_ADD16U => I64AtomicRmwAdd16u(mem), + I64_ATOMIC_RMW_ADD32U => I64AtomicRmwAdd32u(mem), + + I32_ATOMIC_RMW_SUB => I32AtomicRmwSub(mem), + I64_ATOMIC_RMW_SUB => I64AtomicRmwSub(mem), + I32_ATOMIC_RMW_SUB8U => I32AtomicRmwSub8u(mem), + I32_ATOMIC_RMW_SUB16U => I32AtomicRmwSub16u(mem), + I64_ATOMIC_RMW_SUB8U => I64AtomicRmwSub8u(mem), + I64_ATOMIC_RMW_SUB16U => I64AtomicRmwSub16u(mem), + I64_ATOMIC_RMW_SUB32U => I64AtomicRmwSub32u(mem), + + I32_ATOMIC_RMW_OR => I32AtomicRmwOr(mem), + I64_ATOMIC_RMW_OR => I64AtomicRmwOr(mem), + I32_ATOMIC_RMW_OR8U => I32AtomicRmwOr8u(mem), + I32_ATOMIC_RMW_OR16U => I32AtomicRmwOr16u(mem), + I64_ATOMIC_RMW_OR8U => I64AtomicRmwOr8u(mem), + I64_ATOMIC_RMW_OR16U => I64AtomicRmwOr16u(mem), + I64_ATOMIC_RMW_OR32U => I64AtomicRmwOr32u(mem), + + I32_ATOMIC_RMW_XOR => I32AtomicRmwXor(mem), + I64_ATOMIC_RMW_XOR => I64AtomicRmwXor(mem), + I32_ATOMIC_RMW_XOR8U => I32AtomicRmwXor8u(mem), + I32_ATOMIC_RMW_XOR16U => I32AtomicRmwXor16u(mem), + I64_ATOMIC_RMW_XOR8U => I64AtomicRmwXor8u(mem), + I64_ATOMIC_RMW_XOR16U => I64AtomicRmwXor16u(mem), + I64_ATOMIC_RMW_XOR32U => I64AtomicRmwXor32u(mem), + + I32_ATOMIC_RMW_XCHG => I32AtomicRmwXchg(mem), + I64_ATOMIC_RMW_XCHG => I64AtomicRmwXchg(mem), + I32_ATOMIC_RMW_XCHG8U => I32AtomicRmwXchg8u(mem), + I32_ATOMIC_RMW_XCHG16U => I32AtomicRmwXchg16u(mem), + I64_ATOMIC_RMW_XCHG8U => I64AtomicRmwXchg8u(mem), + I64_ATOMIC_RMW_XCHG16U => I64AtomicRmwXchg16u(mem), + I64_ATOMIC_RMW_XCHG32U => I64AtomicRmwXchg32u(mem), + + I32_ATOMIC_RMW_CMPXCHG => I32AtomicRmwCmpxchg(mem), + I64_ATOMIC_RMW_CMPXCHG => I64AtomicRmwCmpxchg(mem), + I32_ATOMIC_RMW_CMPXCHG8U => I32AtomicRmwCmpxchg8u(mem), + I32_ATOMIC_RMW_CMPXCHG16U => I32AtomicRmwCmpxchg16u(mem), + I64_ATOMIC_RMW_CMPXCHG8U => I64AtomicRmwCmpxchg8u(mem), + I64_ATOMIC_RMW_CMPXCHG16U => I64AtomicRmwCmpxchg16u(mem), + I64_ATOMIC_RMW_CMPXCHG32U => I64AtomicRmwCmpxchg32u(mem), + + _ => return Err(Error::UnknownOpcode(val)), + }) } fn deserialize_simd(reader: &mut R) -> Result { - use self::Instruction::*; - use self::opcodes::*; - - let val = VarUint32::deserialize(reader)?.into(); - Ok(match val { - V128_CONST => { - let mut buf = [0; 16]; - reader.read(&mut buf)?; - V128Const(Box::new(buf)) - } - V128_LOAD => V128Load(MemArg::deserialize(reader)?), - V128_STORE => V128Store(MemArg::deserialize(reader)?), - I8X16_SPLAT => I8x16Splat, - I16X8_SPLAT => I16x8Splat, - I32X4_SPLAT => I32x4Splat, - I64X2_SPLAT => I64x2Splat, - F32X4_SPLAT => F32x4Splat, - F64X2_SPLAT => F64x2Splat, - I8X16_EXTRACT_LANE_S => I8x16ExtractLaneS(Uint8::deserialize(reader)?.into()), - I8X16_EXTRACT_LANE_U => I8x16ExtractLaneU(Uint8::deserialize(reader)?.into()), - I16X8_EXTRACT_LANE_S => I16x8ExtractLaneS(Uint8::deserialize(reader)?.into()), - I16X8_EXTRACT_LANE_U => I16x8ExtractLaneU(Uint8::deserialize(reader)?.into()), - I32X4_EXTRACT_LANE => I32x4ExtractLane(Uint8::deserialize(reader)?.into()), - I64X2_EXTRACT_LANE => I64x2ExtractLane(Uint8::deserialize(reader)?.into()), - F32X4_EXTRACT_LANE => F32x4ExtractLane(Uint8::deserialize(reader)?.into()), - F64X2_EXTRACT_LANE => F64x2ExtractLane(Uint8::deserialize(reader)?.into()), - I8X16_REPLACE_LANE => I8x16ReplaceLane(Uint8::deserialize(reader)?.into()), - I16X8_REPLACE_LANE => I16x8ReplaceLane(Uint8::deserialize(reader)?.into()), - I32X4_REPLACE_LANE => I32x4ReplaceLane(Uint8::deserialize(reader)?.into()), - I64X2_REPLACE_LANE => I64x2ReplaceLane(Uint8::deserialize(reader)?.into()), - F32X4_REPLACE_LANE => F32x4ReplaceLane(Uint8::deserialize(reader)?.into()), - F64X2_REPLACE_LANE => F64x2ReplaceLane(Uint8::deserialize(reader)?.into()), - V8X16_SHUFFLE => { - let mut buf = [0; 16]; - reader.read(&mut buf)?; - V8x16Shuffle(Box::new(buf)) - } - I8X16_ADD => I8x16Add, - I16X8_ADD => I16x8Add, - I32X4_ADD => I32x4Add, - I64X2_ADD => I64x2Add, - I8X16_SUB => I8x16Sub, - I16X8_SUB => I16x8Sub, - I32X4_SUB => I32x4Sub, - I64X2_SUB => I64x2Sub, - I8X16_MUL => I8x16Mul, - I16X8_MUL => I16x8Mul, - I32X4_MUL => I32x4Mul, - // I64X2_MUL => I64x2Mul, - I8X16_NEG => I8x16Neg, - I16X8_NEG => I16x8Neg, - I32X4_NEG => I32x4Neg, - I64X2_NEG => I64x2Neg, - - I8X16_ADD_SATURATE_S => I8x16AddSaturateS, - I8X16_ADD_SATURATE_U => I8x16AddSaturateU, - I16X8_ADD_SATURATE_S => I16x8AddSaturateS, - I16X8_ADD_SATURATE_U => I16x8AddSaturateU, - I8X16_SUB_SATURATE_S => I8x16SubSaturateS, - I8X16_SUB_SATURATE_U => I8x16SubSaturateU, - I16X8_SUB_SATURATE_S => I16x8SubSaturateS, - I16X8_SUB_SATURATE_U => I16x8SubSaturateU, - I8X16_SHL => I8x16Shl, - I16X8_SHL => I16x8Shl, - I32X4_SHL => I32x4Shl, - I64X2_SHL => I64x2Shl, - I8X16_SHR_S => I8x16ShrS, - I8X16_SHR_U => I8x16ShrU, - I16X8_SHR_S => I16x8ShrS, - I16X8_SHR_U => I16x8ShrU, - I32X4_SHR_S => I32x4ShrS, - I32X4_SHR_U => I32x4ShrU, - I64X2_SHR_S => I64x2ShrS, - I64X2_SHR_U => I64x2ShrU, - V128_AND => V128And, - V128_OR => V128Or, - V128_XOR => V128Xor, - V128_NOT => V128Not, - V128_BITSELECT => V128Bitselect, - I8X16_ANY_TRUE => I8x16AnyTrue, - I16X8_ANY_TRUE => I16x8AnyTrue, - I32X4_ANY_TRUE => I32x4AnyTrue, - I64X2_ANY_TRUE => I64x2AnyTrue, - I8X16_ALL_TRUE => I8x16AllTrue, - I16X8_ALL_TRUE => I16x8AllTrue, - I32X4_ALL_TRUE => I32x4AllTrue, - I64X2_ALL_TRUE => I64x2AllTrue, - I8X16_EQ => I8x16Eq, - I16X8_EQ => I16x8Eq, - I32X4_EQ => I32x4Eq, - // I64X2_EQ => I64x2Eq, - F32X4_EQ => F32x4Eq, - F64X2_EQ => F64x2Eq, - I8X16_NE => I8x16Ne, - I16X8_NE => I16x8Ne, - I32X4_NE => I32x4Ne, - // I64X2_NE => I64x2Ne, - F32X4_NE => F32x4Ne, - F64X2_NE => F64x2Ne, - I8X16_LT_S => I8x16LtS, - I8X16_LT_U => I8x16LtU, - I16X8_LT_S => I16x8LtS, - I16X8_LT_U => I16x8LtU, - I32X4_LT_S => I32x4LtS, - I32X4_LT_U => I32x4LtU, - // I64X2_LT_S => I64x2LtS, - // I64X2_LT_U => I64x2LtU, - F32X4_LT => F32x4Lt, - F64X2_LT => F64x2Lt, - I8X16_LE_S => I8x16LeS, - I8X16_LE_U => I8x16LeU, - I16X8_LE_S => I16x8LeS, - I16X8_LE_U => I16x8LeU, - I32X4_LE_S => I32x4LeS, - I32X4_LE_U => I32x4LeU, - // I64X2_LE_S => I64x2LeS, - // I64X2_LE_U => I64x2LeU, - F32X4_LE => F32x4Le, - F64X2_LE => F64x2Le, - I8X16_GT_S => I8x16GtS, - I8X16_GT_U => I8x16GtU, - I16X8_GT_S => I16x8GtS, - I16X8_GT_U => I16x8GtU, - I32X4_GT_S => I32x4GtS, - I32X4_GT_U => I32x4GtU, - // I64X2_GT_S => I64x2GtS, - // I64X2_GT_U => I64x2GtU, - F32X4_GT => F32x4Gt, - F64X2_GT => F64x2Gt, - I8X16_GE_S => I8x16GeS, - I8X16_GE_U => I8x16GeU, - I16X8_GE_S => I16x8GeS, - I16X8_GE_U => I16x8GeU, - I32X4_GE_S => I32x4GeS, - I32X4_GE_U => I32x4GeU, - // I64X2_GE_S => I64x2GeS, - // I64X2_GE_U => I64x2GeU, - F32X4_GE => F32x4Ge, - F64X2_GE => F64x2Ge, - F32X4_NEG => F32x4Neg, - F64X2_NEG => F64x2Neg, - F32X4_ABS => F32x4Abs, - F64X2_ABS => F64x2Abs, - F32X4_MIN => F32x4Min, - F64X2_MIN => F64x2Min, - F32X4_MAX => F32x4Max, - F64X2_MAX => F64x2Max, - F32X4_ADD => F32x4Add, - F64X2_ADD => F64x2Add, - F32X4_SUB => F32x4Sub, - F64X2_SUB => F64x2Sub, - F32X4_DIV => F32x4Div, - F64X2_DIV => F64x2Div, - F32X4_MUL => F32x4Mul, - F64X2_MUL => F64x2Mul, - F32X4_SQRT => F32x4Sqrt, - F64X2_SQRT => F64x2Sqrt, - F32X4_CONVERT_S_I32X4 => F32x4ConvertSI32x4, - F32X4_CONVERT_U_I32X4 => F32x4ConvertUI32x4, - F64X2_CONVERT_S_I64X2 => F64x2ConvertSI64x2, - F64X2_CONVERT_U_I64X2 => F64x2ConvertUI64x2, - I32X4_TRUNC_S_F32X4_SAT => I32x4TruncSF32x4Sat, - I32X4_TRUNC_U_F32X4_SAT => I32x4TruncUF32x4Sat, - I64X2_TRUNC_S_F64X2_SAT => I64x2TruncSF64x2Sat, - I64X2_TRUNC_U_F64X2_SAT => I64x2TruncUF64x2Sat, - - _ => return Err(Error::UnknownSimdOpcode(val)), - }) + use self::Instruction::*; + use self::opcodes::*; + + let val = VarUint32::deserialize(reader)?.into(); + Ok(match val { + V128_CONST => { + let mut buf = [0; 16]; + reader.read(&mut buf)?; + V128Const(Box::new(buf)) + } + V128_LOAD => V128Load(MemArg::deserialize(reader)?), + V128_STORE => V128Store(MemArg::deserialize(reader)?), + I8X16_SPLAT => I8x16Splat, + I16X8_SPLAT => I16x8Splat, + I32X4_SPLAT => I32x4Splat, + I64X2_SPLAT => I64x2Splat, + F32X4_SPLAT => F32x4Splat, + F64X2_SPLAT => F64x2Splat, + I8X16_EXTRACT_LANE_S => I8x16ExtractLaneS(Uint8::deserialize(reader)?.into()), + I8X16_EXTRACT_LANE_U => I8x16ExtractLaneU(Uint8::deserialize(reader)?.into()), + I16X8_EXTRACT_LANE_S => I16x8ExtractLaneS(Uint8::deserialize(reader)?.into()), + I16X8_EXTRACT_LANE_U => I16x8ExtractLaneU(Uint8::deserialize(reader)?.into()), + I32X4_EXTRACT_LANE => I32x4ExtractLane(Uint8::deserialize(reader)?.into()), + I64X2_EXTRACT_LANE => I64x2ExtractLane(Uint8::deserialize(reader)?.into()), + F32X4_EXTRACT_LANE => F32x4ExtractLane(Uint8::deserialize(reader)?.into()), + F64X2_EXTRACT_LANE => F64x2ExtractLane(Uint8::deserialize(reader)?.into()), + I8X16_REPLACE_LANE => I8x16ReplaceLane(Uint8::deserialize(reader)?.into()), + I16X8_REPLACE_LANE => I16x8ReplaceLane(Uint8::deserialize(reader)?.into()), + I32X4_REPLACE_LANE => I32x4ReplaceLane(Uint8::deserialize(reader)?.into()), + I64X2_REPLACE_LANE => I64x2ReplaceLane(Uint8::deserialize(reader)?.into()), + F32X4_REPLACE_LANE => F32x4ReplaceLane(Uint8::deserialize(reader)?.into()), + F64X2_REPLACE_LANE => F64x2ReplaceLane(Uint8::deserialize(reader)?.into()), + V8X16_SHUFFLE => { + let mut buf = [0; 16]; + reader.read(&mut buf)?; + V8x16Shuffle(Box::new(buf)) + } + I8X16_ADD => I8x16Add, + I16X8_ADD => I16x8Add, + I32X4_ADD => I32x4Add, + I64X2_ADD => I64x2Add, + I8X16_SUB => I8x16Sub, + I16X8_SUB => I16x8Sub, + I32X4_SUB => I32x4Sub, + I64X2_SUB => I64x2Sub, + I8X16_MUL => I8x16Mul, + I16X8_MUL => I16x8Mul, + I32X4_MUL => I32x4Mul, + // I64X2_MUL => I64x2Mul, + I8X16_NEG => I8x16Neg, + I16X8_NEG => I16x8Neg, + I32X4_NEG => I32x4Neg, + I64X2_NEG => I64x2Neg, + + I8X16_ADD_SATURATE_S => I8x16AddSaturateS, + I8X16_ADD_SATURATE_U => I8x16AddSaturateU, + I16X8_ADD_SATURATE_S => I16x8AddSaturateS, + I16X8_ADD_SATURATE_U => I16x8AddSaturateU, + I8X16_SUB_SATURATE_S => I8x16SubSaturateS, + I8X16_SUB_SATURATE_U => I8x16SubSaturateU, + I16X8_SUB_SATURATE_S => I16x8SubSaturateS, + I16X8_SUB_SATURATE_U => I16x8SubSaturateU, + I8X16_SHL => I8x16Shl, + I16X8_SHL => I16x8Shl, + I32X4_SHL => I32x4Shl, + I64X2_SHL => I64x2Shl, + I8X16_SHR_S => I8x16ShrS, + I8X16_SHR_U => I8x16ShrU, + I16X8_SHR_S => I16x8ShrS, + I16X8_SHR_U => I16x8ShrU, + I32X4_SHR_S => I32x4ShrS, + I32X4_SHR_U => I32x4ShrU, + I64X2_SHR_S => I64x2ShrS, + I64X2_SHR_U => I64x2ShrU, + V128_AND => V128And, + V128_OR => V128Or, + V128_XOR => V128Xor, + V128_NOT => V128Not, + V128_BITSELECT => V128Bitselect, + I8X16_ANY_TRUE => I8x16AnyTrue, + I16X8_ANY_TRUE => I16x8AnyTrue, + I32X4_ANY_TRUE => I32x4AnyTrue, + I64X2_ANY_TRUE => I64x2AnyTrue, + I8X16_ALL_TRUE => I8x16AllTrue, + I16X8_ALL_TRUE => I16x8AllTrue, + I32X4_ALL_TRUE => I32x4AllTrue, + I64X2_ALL_TRUE => I64x2AllTrue, + I8X16_EQ => I8x16Eq, + I16X8_EQ => I16x8Eq, + I32X4_EQ => I32x4Eq, + // I64X2_EQ => I64x2Eq, + F32X4_EQ => F32x4Eq, + F64X2_EQ => F64x2Eq, + I8X16_NE => I8x16Ne, + I16X8_NE => I16x8Ne, + I32X4_NE => I32x4Ne, + // I64X2_NE => I64x2Ne, + F32X4_NE => F32x4Ne, + F64X2_NE => F64x2Ne, + I8X16_LT_S => I8x16LtS, + I8X16_LT_U => I8x16LtU, + I16X8_LT_S => I16x8LtS, + I16X8_LT_U => I16x8LtU, + I32X4_LT_S => I32x4LtS, + I32X4_LT_U => I32x4LtU, + // I64X2_LT_S => I64x2LtS, + // I64X2_LT_U => I64x2LtU, + F32X4_LT => F32x4Lt, + F64X2_LT => F64x2Lt, + I8X16_LE_S => I8x16LeS, + I8X16_LE_U => I8x16LeU, + I16X8_LE_S => I16x8LeS, + I16X8_LE_U => I16x8LeU, + I32X4_LE_S => I32x4LeS, + I32X4_LE_U => I32x4LeU, + // I64X2_LE_S => I64x2LeS, + // I64X2_LE_U => I64x2LeU, + F32X4_LE => F32x4Le, + F64X2_LE => F64x2Le, + I8X16_GT_S => I8x16GtS, + I8X16_GT_U => I8x16GtU, + I16X8_GT_S => I16x8GtS, + I16X8_GT_U => I16x8GtU, + I32X4_GT_S => I32x4GtS, + I32X4_GT_U => I32x4GtU, + // I64X2_GT_S => I64x2GtS, + // I64X2_GT_U => I64x2GtU, + F32X4_GT => F32x4Gt, + F64X2_GT => F64x2Gt, + I8X16_GE_S => I8x16GeS, + I8X16_GE_U => I8x16GeU, + I16X8_GE_S => I16x8GeS, + I16X8_GE_U => I16x8GeU, + I32X4_GE_S => I32x4GeS, + I32X4_GE_U => I32x4GeU, + // I64X2_GE_S => I64x2GeS, + // I64X2_GE_U => I64x2GeU, + F32X4_GE => F32x4Ge, + F64X2_GE => F64x2Ge, + F32X4_NEG => F32x4Neg, + F64X2_NEG => F64x2Neg, + F32X4_ABS => F32x4Abs, + F64X2_ABS => F64x2Abs, + F32X4_MIN => F32x4Min, + F64X2_MIN => F64x2Min, + F32X4_MAX => F32x4Max, + F64X2_MAX => F64x2Max, + F32X4_ADD => F32x4Add, + F64X2_ADD => F64x2Add, + F32X4_SUB => F32x4Sub, + F64X2_SUB => F64x2Sub, + F32X4_DIV => F32x4Div, + F64X2_DIV => F64x2Div, + F32X4_MUL => F32x4Mul, + F64X2_MUL => F64x2Mul, + F32X4_SQRT => F32x4Sqrt, + F64X2_SQRT => F64x2Sqrt, + F32X4_CONVERT_S_I32X4 => F32x4ConvertSI32x4, + F32X4_CONVERT_U_I32X4 => F32x4ConvertUI32x4, + F64X2_CONVERT_S_I64X2 => F64x2ConvertSI64x2, + F64X2_CONVERT_U_I64X2 => F64x2ConvertUI64x2, + I32X4_TRUNC_S_F32X4_SAT => I32x4TruncSF32x4Sat, + I32X4_TRUNC_U_F32X4_SAT => I32x4TruncUF32x4Sat, + I64X2_TRUNC_S_F64X2_SAT => I64x2TruncSF64x2Sat, + I64X2_TRUNC_U_F64X2_SAT => I64x2TruncUF64x2Sat, + + _ => return Err(Error::UnknownSimdOpcode(val)), + }) } fn deserialize_bulk(reader: &mut R) -> Result { - use self::Instruction::*; - use self::opcodes::*; - - let val: u8 = Uint8::deserialize(reader)?.into(); - Ok(match val { - MEMORY_INIT => { - if u8::from(Uint8::deserialize(reader)?) != 0 { - return Err(Error::UnknownOpcode(val)) - } - MemoryInit(VarUint32::deserialize(reader)?.into()) - } - MEMORY_DROP => MemoryDrop(VarUint32::deserialize(reader)?.into()), - MEMORY_FILL => { - if u8::from(Uint8::deserialize(reader)?) != 0 { - return Err(Error::UnknownOpcode(val)) - } - MemoryFill - } - MEMORY_COPY => { - if u8::from(Uint8::deserialize(reader)?) != 0 { - return Err(Error::UnknownOpcode(val)) - } - MemoryCopy - } - - TABLE_INIT => { - if u8::from(Uint8::deserialize(reader)?) != 0 { - return Err(Error::UnknownOpcode(val)) - } - TableInit(VarUint32::deserialize(reader)?.into()) - } - TABLE_DROP => TableDrop(VarUint32::deserialize(reader)?.into()), - TABLE_COPY => { - if u8::from(Uint8::deserialize(reader)?) != 0 { - return Err(Error::UnknownOpcode(val)) - } - TableCopy - } - - _ => return Err(Error::UnknownOpcode(val)), - }) + use self::Instruction::*; + use self::opcodes::*; + + let val: u8 = Uint8::deserialize(reader)?.into(); + Ok(match val { + MEMORY_INIT => { + if u8::from(Uint8::deserialize(reader)?) != 0 { + return Err(Error::UnknownOpcode(val)) + } + MemoryInit(VarUint32::deserialize(reader)?.into()) + } + MEMORY_DROP => MemoryDrop(VarUint32::deserialize(reader)?.into()), + MEMORY_FILL => { + if u8::from(Uint8::deserialize(reader)?) != 0 { + return Err(Error::UnknownOpcode(val)) + } + MemoryFill + } + MEMORY_COPY => { + if u8::from(Uint8::deserialize(reader)?) != 0 { + return Err(Error::UnknownOpcode(val)) + } + MemoryCopy + } + + TABLE_INIT => { + if u8::from(Uint8::deserialize(reader)?) != 0 { + return Err(Error::UnknownOpcode(val)) + } + TableInit(VarUint32::deserialize(reader)?.into()) + } + TABLE_DROP => TableDrop(VarUint32::deserialize(reader)?.into()), + TABLE_COPY => { + if u8::from(Uint8::deserialize(reader)?) != 0 { + return Err(Error::UnknownOpcode(val)) + } + TableCopy + } + + _ => return Err(Error::UnknownOpcode(val)), + }) } impl Deserialize for MemArg { - type Error = Error; + type Error = Error; - fn deserialize(reader: &mut R) -> Result { - let align = Uint8::deserialize(reader)?; - let offset = VarUint32::deserialize(reader)?; - Ok(MemArg { align: align.into(), offset: offset.into() }) - } + fn deserialize(reader: &mut R) -> Result { + let align = Uint8::deserialize(reader)?; + let offset = VarUint32::deserialize(reader)?; + Ok(MemArg { align: align.into(), offset: offset.into() }) + } } - -macro_rules! op { - ($writer: expr, $byte: expr) => ({ - let b: u8 = $byte; - $writer.write(&[b])?; - }); - ($writer: expr, $byte: expr, $s: block) => ({ - op!($writer, $byte); - $s; - }); -} - -macro_rules! atomic { - ($writer: expr, $byte: expr, $mem:expr) => ({ - $writer.write(&[ATOMIC_PREFIX, $byte])?; - MemArg::serialize($mem, $writer)?; - }); -} - -macro_rules! simd { - ($writer: expr, $byte: expr, $other:expr) => ({ - $writer.write(&[SIMD_PREFIX])?; - VarUint32::from($byte).serialize($writer)?; - $other; - }) -} - -macro_rules! bulk { - ($writer: expr, $byte: expr) => ({ - $writer.write(&[BULK_PREFIX, $byte])?; - }); - ($writer: expr, $byte: expr, $remaining:expr) => ({ - bulk!($writer, $byte); - $remaining; - }); -} - -// impl Serialize for Instruction { -// type Error = Error; - -// fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { -// use self::Instruction::*; -// use self::opcodes::*; - -// match self { -// Unreachable => op!(writer, UNREACHABLE), -// Nop => op!(writer, NOP), -// Block(block_type) => op!(writer, BLOCK, { -// block_type.serialize(writer)?; -// }), -// Loop(block_type) => op!(writer, LOOP, { -// block_type.serialize(writer)?; -// }), -// If(block_type) => op!(writer, IF, { -// block_type.serialize(writer)?; -// }), -// Else => op!(writer, ELSE), -// End => op!(writer, END), -// Br(idx) => op!(writer, BR, { -// VarUint32::from(idx).serialize(writer)?; -// }), -// BrIf(idx) => op!(writer, BRIF, { -// VarUint32::from(idx).serialize(writer)?; -// }), -// BrTable(ref table) => op!(writer, BRTABLE, { -// let list_writer = CountedListWriter::( -// table.table.len(), -// table.table.into_iter().map(|x| VarUint32::from(*x)), -// ); -// list_writer.serialize(writer)?; -// VarUint32::from(table.default).serialize(writer)?; -// }), -// Return => op!(writer, RETURN), -// Call(index) => op!(writer, CALL, { -// VarUint32::from(index).serialize(writer)?; -// }), -// CallIndirect(index, reserved) => op!(writer, CALLINDIRECT, { -// VarUint32::from(index).serialize(writer)?; -// Uint8::from(reserved).serialize(writer)?; -// }), -// Drop => op!(writer, DROP), -// Select => op!(writer, SELECT), -// GetLocal(index) => op!(writer, GETLOCAL, { -// VarUint32::from(index).serialize(writer)?; -// }), -// SetLocal(index) => op!(writer, SETLOCAL, { -// VarUint32::from(index).serialize(writer)?; -// }), -// TeeLocal(index) => op!(writer, TEELOCAL, { -// VarUint32::from(index).serialize(writer)?; -// }), -// GetGlobal(index) => op!(writer, GETGLOBAL, { -// VarUint32::from(index).serialize(writer)?; -// }), -// SetGlobal(index) => op!(writer, SETGLOBAL, { -// VarUint32::from(index).serialize(writer)?; -// }), -// I32Load(flags, offset) => op!(writer, I32LOAD, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I64Load(flags, offset) => op!(writer, I64LOAD, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// F32Load(flags, offset) => op!(writer, F32LOAD, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// F64Load(flags, offset) => op!(writer, F64LOAD, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I32Load8S(flags, offset) => op!(writer, I32LOAD8S, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I32Load8U(flags, offset) => op!(writer, I32LOAD8U, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I32Load16S(flags, offset) => op!(writer, I32LOAD16S, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I32Load16U(flags, offset) => op!(writer, I32LOAD16U, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I64Load8S(flags, offset) => op!(writer, I64LOAD8S, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I64Load8U(flags, offset) => op!(writer, I64LOAD8U, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I64Load16S(flags, offset) => op!(writer, I64LOAD16S, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I64Load16U(flags, offset) => op!(writer, I64LOAD16U, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I64Load32S(flags, offset) => op!(writer, I64LOAD32S, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I64Load32U(flags, offset) => op!(writer, I64LOAD32U, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I32Store(flags, offset) => op!(writer, I32STORE, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I64Store(flags, offset) => op!(writer, I64STORE, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// F32Store(flags, offset) => op!(writer, F32STORE, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// F64Store(flags, offset) => op!(writer, F64STORE, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I32Store8(flags, offset) => op!(writer, I32STORE8, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I32Store16(flags, offset) => op!(writer, I32STORE16, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I64Store8(flags, offset) => op!(writer, I64STORE8, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I64Store16(flags, offset) => op!(writer, I64STORE16, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// I64Store32(flags, offset) => op!(writer, I64STORE32, { -// VarUint32::from(flags).serialize(writer)?; -// VarUint32::from(offset).serialize(writer)?; -// }), -// CurrentMemory(flag) => op!(writer, CURRENTMEMORY, { -// Uint8::from(flag).serialize(writer)?; -// }), -// GrowMemory(flag) => op!(writer, GROWMEMORY, { -// Uint8::from(flag).serialize(writer)?; -// }), -// I32Const(def) => op!(writer, I32CONST, { -// VarInt32::from(def).serialize(writer)?; -// }), -// I64Const(def) => op!(writer, I64CONST, { -// VarInt64::from(def).serialize(writer)?; -// }), -// F32Const(def) => op!(writer, F32CONST, { -// Uint32::from(def).serialize(writer)?; -// }), -// F64Const(def) => op!(writer, F64CONST, { -// Uint64::from(def).serialize(writer)?; -// }), -// I32Eqz => op!(writer, I32EQZ), -// I32Eq => op!(writer, I32EQ), -// I32Ne => op!(writer, I32NE), -// I32LtS => op!(writer, I32LTS), -// I32LtU => op!(writer, I32LTU), -// I32GtS => op!(writer, I32GTS), -// I32GtU => op!(writer, I32GTU), -// I32LeS => op!(writer, I32LES), -// I32LeU => op!(writer, I32LEU), -// I32GeS => op!(writer, I32GES), -// I32GeU => op!(writer, I32GEU), - -// I64Eqz => op!(writer, I64EQZ), -// I64Eq => op!(writer, I64EQ), -// I64Ne => op!(writer, I64NE), -// I64LtS => op!(writer, I64LTS), -// I64LtU => op!(writer, I64LTU), -// I64GtS => op!(writer, I64GTS), -// I64GtU => op!(writer, I64GTU), -// I64LeS => op!(writer, I64LES), -// I64LeU => op!(writer, I64LEU), -// I64GeS => op!(writer, I64GES), -// I64GeU => op!(writer, I64GEU), - -// F32Eq => op!(writer, F32EQ), -// F32Ne => op!(writer, F32NE), -// F32Lt => op!(writer, F32LT), -// F32Gt => op!(writer, F32GT), -// F32Le => op!(writer, F32LE), -// F32Ge => op!(writer, F32GE), - -// F64Eq => op!(writer, F64EQ), -// F64Ne => op!(writer, F64NE), -// F64Lt => op!(writer, F64LT), -// F64Gt => op!(writer, F64GT), -// F64Le => op!(writer, F64LE), -// F64Ge => op!(writer, F64GE), - -// I32Clz => op!(writer, I32CLZ), -// I32Ctz => op!(writer, I32CTZ), -// I32Popcnt => op!(writer, I32POPCNT), -// I32Add => op!(writer, I32ADD), -// I32Sub => op!(writer, I32SUB), -// I32Mul => op!(writer, I32MUL), -// I32DivS => op!(writer, I32DIVS), -// I32DivU => op!(writer, I32DIVU), -// I32RemS => op!(writer, I32REMS), -// I32RemU => op!(writer, I32REMU), -// I32And => op!(writer, I32AND), -// I32Or => op!(writer, I32OR), -// I32Xor => op!(writer, I32XOR), -// I32Shl => op!(writer, I32SHL), -// I32ShrS => op!(writer, I32SHRS), -// I32ShrU => op!(writer, I32SHRU), -// I32Rotl => op!(writer, I32ROTL), -// I32Rotr => op!(writer, I32ROTR), - -// I64Clz => op!(writer, I64CLZ), -// I64Ctz => op!(writer, I64CTZ), -// I64Popcnt => op!(writer, I64POPCNT), -// I64Add => op!(writer, I64ADD), -// I64Sub => op!(writer, I64SUB), -// I64Mul => op!(writer, I64MUL), -// I64DivS => op!(writer, I64DIVS), -// I64DivU => op!(writer, I64DIVU), -// I64RemS => op!(writer, I64REMS), -// I64RemU => op!(writer, I64REMU), -// I64And => op!(writer, I64AND), -// I64Or => op!(writer, I64OR), -// I64Xor => op!(writer, I64XOR), -// I64Shl => op!(writer, I64SHL), -// I64ShrS => op!(writer, I64SHRS), -// I64ShrU => op!(writer, I64SHRU), -// I64Rotl => op!(writer, I64ROTL), -// I64Rotr => op!(writer, I64ROTR), -// F32Abs => op!(writer, F32ABS), -// F32Neg => op!(writer, F32NEG), -// F32Ceil => op!(writer, F32CEIL), -// F32Floor => op!(writer, F32FLOOR), -// F32Trunc => op!(writer, F32TRUNC), -// F32Nearest => op!(writer, F32NEAREST), -// F32Sqrt => op!(writer, F32SQRT), -// F32Add => op!(writer, F32ADD), -// F32Sub => op!(writer, F32SUB), -// F32Mul => op!(writer, F32MUL), -// F32Div => op!(writer, F32DIV), -// F32Min => op!(writer, F32MIN), -// F32Max => op!(writer, F32MAX), -// F32Copysign => op!(writer, F32COPYSIGN), -// F64Abs => op!(writer, F64ABS), -// F64Neg => op!(writer, F64NEG), -// F64Ceil => op!(writer, F64CEIL), -// F64Floor => op!(writer, F64FLOOR), -// F64Trunc => op!(writer, F64TRUNC), -// F64Nearest => op!(writer, F64NEAREST), -// F64Sqrt => op!(writer, F64SQRT), -// F64Add => op!(writer, F64ADD), -// F64Sub => op!(writer, F64SUB), -// F64Mul => op!(writer, F64MUL), -// F64Div => op!(writer, F64DIV), -// F64Min => op!(writer, F64MIN), -// F64Max => op!(writer, F64MAX), -// F64Copysign => op!(writer, F64COPYSIGN), - -// I32WrapI64 => op!(writer, I32WRAPI64), -// I32TruncSF32 => op!(writer, I32TRUNCSF32), -// I32TruncUF32 => op!(writer, I32TRUNCUF32), -// I32TruncSF64 => op!(writer, I32TRUNCSF64), -// I32TruncUF64 => op!(writer, I32TRUNCUF64), -// I64ExtendSI32 => op!(writer, I64EXTENDSI32), -// I64ExtendUI32 => op!(writer, I64EXTENDUI32), -// I64TruncSF32 => op!(writer, I64TRUNCSF32), -// I64TruncUF32 => op!(writer, I64TRUNCUF32), -// I64TruncSF64 => op!(writer, I64TRUNCSF64), -// I64TruncUF64 => op!(writer, I64TRUNCUF64), -// F32ConvertSI32 => op!(writer, F32CONVERTSI32), -// F32ConvertUI32 => op!(writer, F32CONVERTUI32), -// F32ConvertSI64 => op!(writer, F32CONVERTSI64), -// F32ConvertUI64 => op!(writer, F32CONVERTUI64), -// F32DemoteF64 => op!(writer, F32DEMOTEF64), -// F64ConvertSI32 => op!(writer, F64CONVERTSI32), -// F64ConvertUI32 => op!(writer, F64CONVERTUI32), -// F64ConvertSI64 => op!(writer, F64CONVERTSI64), -// F64ConvertUI64 => op!(writer, F64CONVERTUI64), -// F64PromoteF32 => op!(writer, F64PROMOTEF32), - -// I32ReinterpretF32 => op!(writer, I32REINTERPRETF32), -// I64ReinterpretF64 => op!(writer, I64REINTERPRETF64), -// F32ReinterpretI32 => op!(writer, F32REINTERPRETI32), -// F64ReinterpretI64 => op!(writer, F64REINTERPRETI64), - -// I32Extend8S => op!(writer, I32_EXTEND8_S), -// I32Extend16S => op!(writer, I32_EXTEND16_S), -// I64Extend8S => op!(writer, I64_EXTEND8_S), -// I64Extend16S => op!(writer, I64_EXTEND16_S), -// I64Extend32S => op!(writer, I64_EXTEND32_S), - -// AtomicWake(m) => atomic!(writer, ATOMIC_WAKE, m), -// I32AtomicWait(m) => atomic!(writer, I32_ATOMIC_WAIT, m), -// I64AtomicWait(m) => atomic!(writer, I64_ATOMIC_WAIT, m), - -// I32AtomicLoad(m) => atomic!(writer, I32_ATOMIC_LOAD, m), -// I64AtomicLoad(m) => atomic!(writer, I64_ATOMIC_LOAD, m), -// I32AtomicLoad8u(m) => atomic!(writer, I32_ATOMIC_LOAD8U, m), -// I32AtomicLoad16u(m) => atomic!(writer, I32_ATOMIC_LOAD16U, m), -// I64AtomicLoad8u(m) => atomic!(writer, I64_ATOMIC_LOAD8U, m), -// I64AtomicLoad16u(m) => atomic!(writer, I64_ATOMIC_LOAD16U, m), -// I64AtomicLoad32u(m) => atomic!(writer, I64_ATOMIC_LOAD32U, m), -// I32AtomicStore(m) => atomic!(writer, I32_ATOMIC_STORE, m), -// I64AtomicStore(m) => atomic!(writer, I64_ATOMIC_STORE, m), -// I32AtomicStore8u(m) => atomic!(writer, I32_ATOMIC_STORE8U, m), -// I32AtomicStore16u(m) => atomic!(writer, I32_ATOMIC_STORE16U, m), -// I64AtomicStore8u(m) => atomic!(writer, I64_ATOMIC_STORE8U, m), -// I64AtomicStore16u(m) => atomic!(writer, I64_ATOMIC_STORE16U, m), -// I64AtomicStore32u(m) => atomic!(writer, I64_ATOMIC_STORE32U, m), - -// I32AtomicRmwAdd(m) => atomic!(writer, I32_ATOMIC_RMW_ADD, m), -// I64AtomicRmwAdd(m) => atomic!(writer, I64_ATOMIC_RMW_ADD, m), -// I32AtomicRmwAdd8u(m) => atomic!(writer, I32_ATOMIC_RMW_ADD8U, m), -// I32AtomicRmwAdd16u(m) => atomic!(writer, I32_ATOMIC_RMW_ADD16U, m), -// I64AtomicRmwAdd8u(m) => atomic!(writer, I64_ATOMIC_RMW_ADD8U, m), -// I64AtomicRmwAdd16u(m) => atomic!(writer, I64_ATOMIC_RMW_ADD16U, m), -// I64AtomicRmwAdd32u(m) => atomic!(writer, I64_ATOMIC_RMW_ADD32U, m), - -// I32AtomicRmwSub(m) => atomic!(writer, I32_ATOMIC_RMW_SUB, m), -// I64AtomicRmwSub(m) => atomic!(writer, I64_ATOMIC_RMW_SUB, m), -// I32AtomicRmwSub8u(m) => atomic!(writer, I32_ATOMIC_RMW_SUB8U, m), -// I32AtomicRmwSub16u(m) => atomic!(writer, I32_ATOMIC_RMW_SUB16U, m), -// I64AtomicRmwSub8u(m) => atomic!(writer, I64_ATOMIC_RMW_SUB8U, m), -// I64AtomicRmwSub16u(m) => atomic!(writer, I64_ATOMIC_RMW_SUB16U, m), -// I64AtomicRmwSub32u(m) => atomic!(writer, I64_ATOMIC_RMW_SUB32U, m), - -// I32AtomicRmwAnd(m) => atomic!(writer, I32_ATOMIC_RMW_AND, m), -// I64AtomicRmwAnd(m) => atomic!(writer, I64_ATOMIC_RMW_AND, m), -// I32AtomicRmwAnd8u(m) => atomic!(writer, I32_ATOMIC_RMW_AND8U, m), -// I32AtomicRmwAnd16u(m) => atomic!(writer, I32_ATOMIC_RMW_AND16U, m), -// I64AtomicRmwAnd8u(m) => atomic!(writer, I64_ATOMIC_RMW_AND8U, m), -// I64AtomicRmwAnd16u(m) => atomic!(writer, I64_ATOMIC_RMW_AND16U, m), -// I64AtomicRmwAnd32u(m) => atomic!(writer, I64_ATOMIC_RMW_AND32U, m), - -// I32AtomicRmwOr(m) => atomic!(writer, I32_ATOMIC_RMW_OR, m), -// I64AtomicRmwOr(m) => atomic!(writer, I64_ATOMIC_RMW_OR, m), -// I32AtomicRmwOr8u(m) => atomic!(writer, I32_ATOMIC_RMW_OR8U, m), -// I32AtomicRmwOr16u(m) => atomic!(writer, I32_ATOMIC_RMW_OR16U, m), -// I64AtomicRmwOr8u(m) => atomic!(writer, I64_ATOMIC_RMW_OR8U, m), -// I64AtomicRmwOr16u(m) => atomic!(writer, I64_ATOMIC_RMW_OR16U, m), -// I64AtomicRmwOr32u(m) => atomic!(writer, I64_ATOMIC_RMW_OR32U, m), - -// I32AtomicRmwXor(m) => atomic!(writer, I32_ATOMIC_RMW_XOR, m), -// I64AtomicRmwXor(m) => atomic!(writer, I64_ATOMIC_RMW_XOR, m), -// I32AtomicRmwXor8u(m) => atomic!(writer, I32_ATOMIC_RMW_XOR8U, m), -// I32AtomicRmwXor16u(m) => atomic!(writer, I32_ATOMIC_RMW_XOR16U, m), -// I64AtomicRmwXor8u(m) => atomic!(writer, I64_ATOMIC_RMW_XOR8U, m), -// I64AtomicRmwXor16u(m) => atomic!(writer, I64_ATOMIC_RMW_XOR16U, m), -// I64AtomicRmwXor32u(m) => atomic!(writer, I64_ATOMIC_RMW_XOR32U, m), - -// I32AtomicRmwXchg(m) => atomic!(writer, I32_ATOMIC_RMW_XCHG, m), -// I64AtomicRmwXchg(m) => atomic!(writer, I64_ATOMIC_RMW_XCHG, m), -// I32AtomicRmwXchg8u(m) => atomic!(writer, I32_ATOMIC_RMW_XCHG8U, m), -// I32AtomicRmwXchg16u(m) => atomic!(writer, I32_ATOMIC_RMW_XCHG16U, m), -// I64AtomicRmwXchg8u(m) => atomic!(writer, I64_ATOMIC_RMW_XCHG8U, m), -// I64AtomicRmwXchg16u(m) => atomic!(writer, I64_ATOMIC_RMW_XCHG16U, m), -// I64AtomicRmwXchg32u(m) => atomic!(writer, I64_ATOMIC_RMW_XCHG32U, m), - -// I32AtomicRmwCmpxchg(m) => atomic!(writer, I32_ATOMIC_RMW_CMPXCHG, m), -// I64AtomicRmwCmpxchg(m) => atomic!(writer, I64_ATOMIC_RMW_CMPXCHG, m), -// I32AtomicRmwCmpxchg8u(m) => atomic!(writer, I32_ATOMIC_RMW_CMPXCHG8U, m), -// I32AtomicRmwCmpxchg16u(m) => atomic!(writer, I32_ATOMIC_RMW_CMPXCHG16U, m), -// I64AtomicRmwCmpxchg8u(m) => atomic!(writer, I64_ATOMIC_RMW_CMPXCHG8U, m), -// I64AtomicRmwCmpxchg16u(m) => atomic!(writer, I64_ATOMIC_RMW_CMPXCHG16U, m), -// I64AtomicRmwCmpxchg32u(m) => atomic!(writer, I64_ATOMIC_RMW_CMPXCHG32U, m), - -// V128Const(ref c) => simd!(writer, opcodes::V128_CONST, writer.write(&c[..])?), -// V128Load(m) => simd!(writer, opcodes::V128_LOAD, MemArg::serialize(m, writer)?), -// V128Store(m) => simd!(writer, opcodes::V128_STORE, MemArg::serialize(m, writer)?), -// I8x16Splat => simd!(writer, opcodes::I8X16_SPLAT, ()), -// I16x8Splat => simd!(writer, opcodes::I16X8_SPLAT, ()), -// I32x4Splat => simd!(writer, opcodes::I32X4_SPLAT, ()), -// I64x2Splat => simd!(writer, opcodes::I64X2_SPLAT, ()), -// F32x4Splat => simd!(writer, opcodes::F32X4_SPLAT, ()), -// F64x2Splat => simd!(writer, opcodes::F64X2_SPLAT, ()), -// I8x16ExtractLaneS(i) => simd!(writer, opcodes::I8X16_EXTRACT_LANE_S, writer.write(&[i])?), -// I8x16ExtractLaneU(i) => simd!(writer, opcodes::I8X16_EXTRACT_LANE_U, writer.write(&[i])?), -// I16x8ExtractLaneS(i) => simd!(writer, opcodes::I16X8_EXTRACT_LANE_S, writer.write(&[i])?), -// I16x8ExtractLaneU(i) => simd!(writer, opcodes::I16X8_EXTRACT_LANE_U, writer.write(&[i])?), -// I32x4ExtractLane(i) => simd!(writer, opcodes::I32X4_EXTRACT_LANE, writer.write(&[i])?), -// I64x2ExtractLane(i) => simd!(writer, opcodes::I64X2_EXTRACT_LANE, writer.write(&[i])?), -// F32x4ExtractLane(i) => simd!(writer, opcodes::F32X4_EXTRACT_LANE, writer.write(&[i])?), -// F64x2ExtractLane(i) => simd!(writer, opcodes::F64X2_EXTRACT_LANE, writer.write(&[i])?), -// I8x16ReplaceLane(i) => simd!(writer, opcodes::I8X16_REPLACE_LANE, writer.write(&[i])?), -// I16x8ReplaceLane(i) => simd!(writer, opcodes::I16X8_REPLACE_LANE, writer.write(&[i])?), -// I32x4ReplaceLane(i) => simd!(writer, opcodes::I32X4_REPLACE_LANE, writer.write(&[i])?), -// I64x2ReplaceLane(i) => simd!(writer, opcodes::I64X2_REPLACE_LANE, writer.write(&[i])?), -// F32x4ReplaceLane(i) => simd!(writer, opcodes::F32X4_REPLACE_LANE, writer.write(&[i])?), -// F64x2ReplaceLane(i) => simd!(writer, opcodes::F64X2_REPLACE_LANE, writer.write(&[i])?), -// V8x16Shuffle(ref i) => simd!(writer, opcodes::V8X16_SHUFFLE, writer.write(&i[..])?), -// I8x16Add => simd!(writer, opcodes::I8X16_ADD, ()), -// I16x8Add => simd!(writer, opcodes::I16X8_ADD, ()), -// I32x4Add => simd!(writer, opcodes::I32X4_ADD, ()), -// I64x2Add => simd!(writer, opcodes::I64X2_ADD, ()), -// I8x16Sub => simd!(writer, opcodes::I8X16_SUB, ()), -// I16x8Sub => simd!(writer, opcodes::I16X8_SUB, ()), -// I32x4Sub => simd!(writer, opcodes::I32X4_SUB, ()), -// I64x2Sub => simd!(writer, opcodes::I64X2_SUB, ()), -// I8x16Mul => simd!(writer, opcodes::I8X16_MUL, ()), -// I16x8Mul => simd!(writer, opcodes::I16X8_MUL, ()), -// I32x4Mul => simd!(writer, opcodes::I32X4_MUL, ()), -// // I64x2Mul => simd!(writer, opcodes::I64X2_MUL, ()), -// I8x16Neg => simd!(writer, opcodes::I8X16_NEG, ()), -// I16x8Neg => simd!(writer, opcodes::I16X8_NEG, ()), -// I32x4Neg => simd!(writer, opcodes::I32X4_NEG, ()), -// I64x2Neg => simd!(writer, opcodes::I64X2_NEG, ()), -// I8x16AddSaturateS => simd!(writer, opcodes::I8X16_ADD_SATURATE_S, ()), -// I8x16AddSaturateU => simd!(writer, opcodes::I8X16_ADD_SATURATE_U, ()), -// I16x8AddSaturateS => simd!(writer, opcodes::I16X8_ADD_SATURATE_S, ()), -// I16x8AddSaturateU => simd!(writer, opcodes::I16X8_ADD_SATURATE_U, ()), -// I8x16SubSaturateS => simd!(writer, opcodes::I8X16_SUB_SATURATE_S, ()), -// I8x16SubSaturateU => simd!(writer, opcodes::I8X16_SUB_SATURATE_U, ()), -// I16x8SubSaturateS => simd!(writer, opcodes::I16X8_SUB_SATURATE_S, ()), -// I16x8SubSaturateU => simd!(writer, opcodes::I16X8_SUB_SATURATE_U, ()), -// I8x16Shl => simd!(writer, opcodes::I8X16_SHL, ()), -// I16x8Shl => simd!(writer, opcodes::I16X8_SHL, ()), -// I32x4Shl => simd!(writer, opcodes::I32X4_SHL, ()), -// I64x2Shl => simd!(writer, opcodes::I64X2_SHL, ()), -// I8x16ShrS => simd!(writer, opcodes::I8X16_SHR_S, ()), -// I8x16ShrU => simd!(writer, opcodes::I8X16_SHR_U, ()), -// I16x8ShrS => simd!(writer, opcodes::I16X8_SHR_S, ()), -// I16x8ShrU => simd!(writer, opcodes::I16X8_SHR_U, ()), -// I32x4ShrU => simd!(writer, opcodes::I32X4_SHR_U, ()), -// I32x4ShrS => simd!(writer, opcodes::I32X4_SHR_S, ()), -// I64x2ShrU => simd!(writer, opcodes::I64X2_SHR_U, ()), -// I64x2ShrS => simd!(writer, opcodes::I64X2_SHR_S, ()), -// V128And => simd!(writer, opcodes::V128_AND, ()), -// V128Or => simd!(writer, opcodes::V128_OR, ()), -// V128Xor => simd!(writer, opcodes::V128_XOR, ()), -// V128Not => simd!(writer, opcodes::V128_NOT, ()), -// V128Bitselect => simd!(writer, opcodes::V128_BITSELECT, ()), -// I8x16AnyTrue => simd!(writer, opcodes::I8X16_ANY_TRUE, ()), -// I16x8AnyTrue => simd!(writer, opcodes::I16X8_ANY_TRUE, ()), -// I32x4AnyTrue => simd!(writer, opcodes::I32X4_ANY_TRUE, ()), -// I64x2AnyTrue => simd!(writer, opcodes::I64X2_ANY_TRUE, ()), -// I8x16AllTrue => simd!(writer, opcodes::I8X16_ALL_TRUE, ()), -// I16x8AllTrue => simd!(writer, opcodes::I16X8_ALL_TRUE, ()), -// I32x4AllTrue => simd!(writer, opcodes::I32X4_ALL_TRUE, ()), -// I64x2AllTrue => simd!(writer, opcodes::I64X2_ALL_TRUE, ()), -// I8x16Eq => simd!(writer, opcodes::I8X16_EQ, ()), -// I16x8Eq => simd!(writer, opcodes::I16X8_EQ, ()), -// I32x4Eq => simd!(writer, opcodes::I32X4_EQ, ()), -// // I64x2Eq => simd!(writer, opcodes::I64X2_EQ, ()), -// F32x4Eq => simd!(writer, opcodes::F32X4_EQ, ()), -// F64x2Eq => simd!(writer, opcodes::F64X2_EQ, ()), -// I8x16Ne => simd!(writer, opcodes::I8X16_NE, ()), -// I16x8Ne => simd!(writer, opcodes::I16X8_NE, ()), -// I32x4Ne => simd!(writer, opcodes::I32X4_NE, ()), -// // I64x2Ne => simd!(writer, opcodes::I64X2_NE, ()), -// F32x4Ne => simd!(writer, opcodes::F32X4_NE, ()), -// F64x2Ne => simd!(writer, opcodes::F64X2_NE, ()), -// I8x16LtS => simd!(writer, opcodes::I8X16_LT_S, ()), -// I8x16LtU => simd!(writer, opcodes::I8X16_LT_U, ()), -// I16x8LtS => simd!(writer, opcodes::I16X8_LT_S, ()), -// I16x8LtU => simd!(writer, opcodes::I16X8_LT_U, ()), -// I32x4LtS => simd!(writer, opcodes::I32X4_LT_S, ()), -// I32x4LtU => simd!(writer, opcodes::I32X4_LT_U, ()), -// // I64x2LtS => simd!(writer, opcodes::I64X2_LT_S, ()), -// // I64x2LtU => simd!(writer, opcodes::I64X2_LT_U, ()), -// F32x4Lt => simd!(writer, opcodes::F32X4_LT, ()), -// F64x2Lt => simd!(writer, opcodes::F64X2_LT, ()), -// I8x16LeS => simd!(writer, opcodes::I8X16_LE_S, ()), -// I8x16LeU => simd!(writer, opcodes::I8X16_LE_U, ()), -// I16x8LeS => simd!(writer, opcodes::I16X8_LE_S, ()), -// I16x8LeU => simd!(writer, opcodes::I16X8_LE_U, ()), -// I32x4LeS => simd!(writer, opcodes::I32X4_LE_S, ()), -// I32x4LeU => simd!(writer, opcodes::I32X4_LE_U, ()), -// // I64x2LeS => simd!(writer, opcodes::I64X2_LE_S, ()), -// // I64x2LeU => simd!(writer, opcodes::I64X2_LE_U, ()), -// F32x4Le => simd!(writer, opcodes::F32X4_LE, ()), -// F64x2Le => simd!(writer, opcodes::F64X2_LE, ()), -// I8x16GtS => simd!(writer, opcodes::I8X16_GT_S, ()), -// I8x16GtU => simd!(writer, opcodes::I8X16_GT_U, ()), -// I16x8GtS => simd!(writer, opcodes::I16X8_GT_S, ()), -// I16x8GtU => simd!(writer, opcodes::I16X8_GT_U, ()), -// I32x4GtS => simd!(writer, opcodes::I32X4_GT_S, ()), -// I32x4GtU => simd!(writer, opcodes::I32X4_GT_U, ()), -// // I64x2GtS => simd!(writer, opcodes::I64X2_GT_S, ()), -// // I64x2GtU => simd!(writer, opcodes::I64X2_GT_U, ()), -// F32x4Gt => simd!(writer, opcodes::F32X4_GT, ()), -// F64x2Gt => simd!(writer, opcodes::F64X2_GT, ()), -// I8x16GeS => simd!(writer, opcodes::I8X16_GE_S, ()), -// I8x16GeU => simd!(writer, opcodes::I8X16_GE_U, ()), -// I16x8GeS => simd!(writer, opcodes::I16X8_GE_S, ()), -// I16x8GeU => simd!(writer, opcodes::I16X8_GE_U, ()), -// I32x4GeS => simd!(writer, opcodes::I32X4_GE_S, ()), -// I32x4GeU => simd!(writer, opcodes::I32X4_GE_U, ()), -// // I64x2GeS => simd!(writer, opcodes::I64X2_GE_S, ()), -// // I64x2GeU => simd!(writer, opcodes::I64X2_GE_U, ()), -// F32x4Ge => simd!(writer, opcodes::F32X4_GE, ()), -// F64x2Ge => simd!(writer, opcodes::F64X2_GE, ()), -// F32x4Neg => simd!(writer, opcodes::F32X4_NEG, ()), -// F64x2Neg => simd!(writer, opcodes::F64X2_NEG, ()), -// F32x4Abs => simd!(writer, opcodes::F32X4_ABS, ()), -// F64x2Abs => simd!(writer, opcodes::F64X2_ABS, ()), -// F32x4Min => simd!(writer, opcodes::F32X4_MIN, ()), -// F64x2Min => simd!(writer, opcodes::F64X2_MIN, ()), -// F32x4Max => simd!(writer, opcodes::F32X4_MAX, ()), -// F64x2Max => simd!(writer, opcodes::F64X2_MAX, ()), -// F32x4Add => simd!(writer, opcodes::F32X4_ADD, ()), -// F64x2Add => simd!(writer, opcodes::F64X2_ADD, ()), -// F32x4Sub => simd!(writer, opcodes::F32X4_SUB, ()), -// F64x2Sub => simd!(writer, opcodes::F64X2_SUB, ()), -// F32x4Div => simd!(writer, opcodes::F32X4_DIV, ()), -// F64x2Div => simd!(writer, opcodes::F64X2_DIV, ()), -// F32x4Mul => simd!(writer, opcodes::F32X4_MUL, ()), -// F64x2Mul => simd!(writer, opcodes::F64X2_MUL, ()), -// F32x4Sqrt => simd!(writer, opcodes::F32X4_SQRT, ()), -// F64x2Sqrt => simd!(writer, opcodes::F64X2_SQRT, ()), -// F32x4ConvertSI32x4 => simd!(writer, opcodes::F32X4_CONVERT_S_I32X4, ()), -// F32x4ConvertUI32x4 => simd!(writer, opcodes::F32X4_CONVERT_U_I32X4, ()), -// F64x2ConvertSI64x2 => simd!(writer, opcodes::F64X2_CONVERT_S_I64X2, ()), -// F64x2ConvertUI64x2 => simd!(writer, opcodes::F64X2_CONVERT_U_I64X2, ()), -// I32x4TruncSF32x4Sat => simd!(writer, opcodes::I32X4_TRUNC_S_F32X4_SAT, ()), -// I32x4TruncUF32x4Sat => simd!(writer, opcodes::I32X4_TRUNC_U_F32X4_SAT, ()), -// I64x2TruncSF64x2Sat => simd!(writer, opcodes::I64X2_TRUNC_S_F64X2_SAT, ()), -// I64x2TruncUF64x2Sat => simd!(writer, opcodes::I64X2_TRUNC_U_F64X2_SAT, ()), - -// MemoryInit(seg) => bulk!(writer, MEMORY_INIT, { -// Uint8::from(0).serialize(writer)?; -// VarUint32::from(seg).serialize(writer)?; -// }), -// MemoryDrop(seg) => bulk!(writer, MEMORY_DROP, VarUint32::from(seg).serialize(writer)?), -// MemoryFill => bulk!(writer, MEMORY_FILL, Uint8::from(0).serialize(writer)?), -// MemoryCopy => bulk!(writer, MEMORY_COPY, Uint8::from(0).serialize(writer)?), -// TableInit(seg) => bulk!(writer, TABLE_INIT, { -// Uint8::from(0).serialize(writer)?; -// VarUint32::from(seg).serialize(writer)?; -// }), -// TableDrop(seg) => bulk!(writer, TABLE_DROP, VarUint32::from(seg).serialize(writer)?), -// TableCopy => bulk!(writer, TABLE_COPY, Uint8::from(0).serialize(writer)?), -// } - -// Ok(()) -// } -// } - -impl Serialize for MemArg { - type Error = Error; - - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - Uint8::from(self.align).serialize(writer)?; - VarUint32::from(self.offset).serialize(writer)?; - Ok(()) - } -} - -// macro_rules! fmt_op { -// ($f: expr, $mnemonic: expr) => ({ -// write!($f, "{}", $mnemonic) -// }); -// ($f: expr, $mnemonic: expr, $immediate: expr) => ({ -// write!($f, "{} {}", $mnemonic, $immediate) -// }); -// ($f: expr, $mnemonic: expr, $immediate1: expr, $immediate2: expr) => ({ -// write!($f, "{} {} {}", $mnemonic, $immediate1, $immediate2) -// }); -// } - -// impl fmt::Display for Instruction { -// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -// use self::Instruction::*; -// use super::BlockType; - -// match *self { -// Unreachable => fmt_op!(f, "unreachable"), -// Nop => fmt_op!(f, "nop"), -// Block(BlockType::NoResult) => fmt_op!(f, "block"), -// Block(BlockType::Value(value_type)) => fmt_op!(f, "block", value_type), -// Loop(BlockType::NoResult) => fmt_op!(f, "loop"), -// Loop(BlockType::Value(value_type)) => fmt_op!(f, "loop", value_type), -// If(BlockType::NoResult) => fmt_op!(f, "if"), -// If(BlockType::Value(value_type)) => fmt_op!(f, "if", value_type), -// Else => fmt_op!(f, "else"), -// End => fmt_op!(f, "end"), -// Br(idx) => fmt_op!(f, "br", idx), -// BrIf(idx) => fmt_op!(f, "br_if", idx), -// BrTable(ref table) => fmt_op!(f, "br_table", table.default), -// Return => fmt_op!(f, "return"), -// Call(index) => fmt_op!(f, "call", index), -// CallIndirect(index, _) => fmt_op!(f, "call_indirect", index), -// Drop => fmt_op!(f, "drop"), -// Select => fmt_op!(f, "select"), -// GetLocal(index) => fmt_op!(f, "get_local", index), -// SetLocal(index) => fmt_op!(f, "set_local", index), -// TeeLocal(index) => fmt_op!(f, "tee_local", index), -// GetGlobal(index) => fmt_op!(f, "get_global", index), -// SetGlobal(index) => fmt_op!(f, "set_global", index), - -// I32Load(_, 0) => write!(f, "i32.load"), -// I32Load(_, offset) => write!(f, "i32.load offset={}", offset), - -// I64Load(_, 0) => write!(f, "i64.load"), -// I64Load(_, offset) => write!(f, "i64.load offset={}", offset), - -// F32Load(_, 0) => write!(f, "f32.load"), -// F32Load(_, offset) => write!(f, "f32.load offset={}", offset), - -// F64Load(_, 0) => write!(f, "f64.load"), -// F64Load(_, offset) => write!(f, "f64.load offset={}", offset), - -// I32Load8S(_, 0) => write!(f, "i32.load8_s"), -// I32Load8S(_, offset) => write!(f, "i32.load8_s offset={}", offset), - -// I32Load8U(_, 0) => write!(f, "i32.load8_u"), -// I32Load8U(_, offset) => write!(f, "i32.load8_u offset={}", offset), - -// I32Load16S(_, 0) => write!(f, "i32.load16_s"), -// I32Load16S(_, offset) => write!(f, "i32.load16_s offset={}", offset), - -// I32Load16U(_, 0) => write!(f, "i32.load16_u"), -// I32Load16U(_, offset) => write!(f, "i32.load16_u offset={}", offset), - -// I64Load8S(_, 0) => write!(f, "i64.load8_s"), -// I64Load8S(_, offset) => write!(f, "i64.load8_s offset={}", offset), - -// I64Load8U(_, 0) => write!(f, "i64.load8_u"), -// I64Load8U(_, offset) => write!(f, "i64.load8_u offset={}", offset), - -// I64Load16S(_, 0) => write!(f, "i64.load16_s"), -// I64Load16S(_, offset) => write!(f, "i64.load16_s offset={}", offset), - -// I64Load16U(_, 0) => write!(f, "i64.load16_u"), -// I64Load16U(_, offset) => write!(f, "i64.load16_u offset={}", offset), - -// I64Load32S(_, 0) => write!(f, "i64.load32_s"), -// I64Load32S(_, offset) => write!(f, "i64.load32_s offset={}", offset), - -// I64Load32U(_, 0) => write!(f, "i64.load32_u"), -// I64Load32U(_, offset) => write!(f, "i64.load32_u offset={}", offset), - -// I32Store(_, 0) => write!(f, "i32.store"), -// I32Store(_, offset) => write!(f, "i32.store offset={}", offset), - -// I64Store(_, 0) => write!(f, "i64.store"), -// I64Store(_, offset) => write!(f, "i64.store offset={}", offset), - -// F32Store(_, 0) => write!(f, "f32.store"), -// F32Store(_, offset) => write!(f, "f32.store offset={}", offset), - -// F64Store(_, 0) => write!(f, "f64.store"), -// F64Store(_, offset) => write!(f, "f64.store offset={}", offset), - -// I32Store8(_, 0) => write!(f, "i32.store8"), -// I32Store8(_, offset) => write!(f, "i32.store8 offset={}", offset), - -// I32Store16(_, 0) => write!(f, "i32.store16"), -// I32Store16(_, offset) => write!(f, "i32.store16 offset={}", offset), - -// I64Store8(_, 0) => write!(f, "i64.store8"), -// I64Store8(_, offset) => write!(f, "i64.store8 offset={}", offset), - -// I64Store16(_, 0) => write!(f, "i64.store16"), -// I64Store16(_, offset) => write!(f, "i64.store16 offset={}", offset), - -// I64Store32(_, 0) => write!(f, "i64.store32"), -// I64Store32(_, offset) => write!(f, "i64.store32 offset={}", offset), - -// CurrentMemory(_) => fmt_op!(f, "current_memory"), -// GrowMemory(_) => fmt_op!(f, "grow_memory"), - -// I32Const(def) => fmt_op!(f, "i32.const", def), -// I64Const(def) => fmt_op!(f, "i64.const", def), -// F32Const(def) => fmt_op!(f, "f32.const", def), -// F64Const(def) => fmt_op!(f, "f64.const", def), - -// I32Eq => write!(f, "i32.eq"), -// I32Eqz => write!(f, "i32.eqz"), -// I32Ne => write!(f, "i32.ne"), -// I32LtS => write!(f, "i32.lt_s"), -// I32LtU => write!(f, "i32.lt_u"), -// I32GtS => write!(f, "i32.gt_s"), -// I32GtU => write!(f, "i32.gt_u"), -// I32LeS => write!(f, "i32.le_s"), -// I32LeU => write!(f, "i32.le_u"), -// I32GeS => write!(f, "i32.ge_s"), -// I32GeU => write!(f, "i32.ge_u"), - -// I64Eq => write!(f, "i64.eq"), -// I64Eqz => write!(f, "i64.eqz"), -// I64Ne => write!(f, "i64.ne"), -// I64LtS => write!(f, "i64.lt_s"), -// I64LtU => write!(f, "i64.lt_u"), -// I64GtS => write!(f, "i64.gt_s"), -// I64GtU => write!(f, "i64.gt_u"), -// I64LeS => write!(f, "i64.le_s"), -// I64LeU => write!(f, "i64.le_u"), -// I64GeS => write!(f, "i64.ge_s"), -// I64GeU => write!(f, "i64.ge_u"), - -// F32Eq => write!(f, "f32.eq"), -// F32Ne => write!(f, "f32.ne"), -// F32Lt => write!(f, "f32.lt"), -// F32Gt => write!(f, "f32.gt"), -// F32Le => write!(f, "f32.le"), -// F32Ge => write!(f, "f32.ge"), - -// F64Eq => write!(f, "f64.eq"), -// F64Ne => write!(f, "f64.ne"), -// F64Lt => write!(f, "f64.lt"), -// F64Gt => write!(f, "f64.gt"), -// F64Le => write!(f, "f64.le"), -// F64Ge => write!(f, "f64.ge"), - -// I32Clz => write!(f, "i32.clz"), -// I32Ctz => write!(f, "i32.ctz"), -// I32Popcnt => write!(f, "i32.popcnt"), -// I32Add => write!(f, "i32.add"), -// I32Sub => write!(f, "i32.sub"), -// I32Mul => write!(f, "i32.mul"), -// I32DivS => write!(f, "i32.div_s"), -// I32DivU => write!(f, "i32.div_u"), -// I32RemS => write!(f, "i32.rem_s"), -// I32RemU => write!(f, "i32.rem_u"), -// I32And => write!(f, "i32.and"), -// I32Or => write!(f, "i32.or"), -// I32Xor => write!(f, "i32.xor"), -// I32Shl => write!(f, "i32.shl"), -// I32ShrS => write!(f, "i32.shr_s"), -// I32ShrU => write!(f, "i32.shr_u"), -// I32Rotl => write!(f, "i32.rotl"), -// I32Rotr => write!(f, "i32.rotr"), - -// I64Clz => write!(f, "i64.clz"), -// I64Ctz => write!(f, "i64.ctz"), -// I64Popcnt => write!(f, "i64.popcnt"), -// I64Add => write!(f, "i64.add"), -// I64Sub => write!(f, "i64.sub"), -// I64Mul => write!(f, "i64.mul"), -// I64DivS => write!(f, "i64.div_s"), -// I64DivU => write!(f, "i64.div_u"), -// I64RemS => write!(f, "i64.rem_s"), -// I64RemU => write!(f, "i64.rem_u"), -// I64And => write!(f, "i64.and"), -// I64Or => write!(f, "i64.or"), -// I64Xor => write!(f, "i64.xor"), -// I64Shl => write!(f, "i64.shl"), -// I64ShrS => write!(f, "i64.shr_s"), -// I64ShrU => write!(f, "i64.shr_u"), -// I64Rotl => write!(f, "i64.rotl"), -// I64Rotr => write!(f, "i64.rotr"), - -// F32Abs => write!(f, "f32.abs"), -// F32Neg => write!(f, "f32.neg"), -// F32Ceil => write!(f, "f32.ceil"), -// F32Floor => write!(f, "f32.floor"), -// F32Trunc => write!(f, "f32.trunc"), -// F32Nearest => write!(f, "f32.nearest"), -// F32Sqrt => write!(f, "f32.sqrt"), -// F32Add => write!(f, "f32.add"), -// F32Sub => write!(f, "f32.sub"), -// F32Mul => write!(f, "f32.mul"), -// F32Div => write!(f, "f32.div"), -// F32Min => write!(f, "f32.min"), -// F32Max => write!(f, "f32.max"), -// F32Copysign => write!(f, "f32.copysign"), - -// F64Abs => write!(f, "f64.abs"), -// F64Neg => write!(f, "f64.neg"), -// F64Ceil => write!(f, "f64.ceil"), -// F64Floor => write!(f, "f64.floor"), -// F64Trunc => write!(f, "f64.trunc"), -// F64Nearest => write!(f, "f64.nearest"), -// F64Sqrt => write!(f, "f64.sqrt"), -// F64Add => write!(f, "f64.add"), -// F64Sub => write!(f, "f64.sub"), -// F64Mul => write!(f, "f64.mul"), -// F64Div => write!(f, "f64.div"), -// F64Min => write!(f, "f64.min"), -// F64Max => write!(f, "f64.max"), -// F64Copysign => write!(f, "f64.copysign"), - -// I32WrapI64 => write!(f, "i32.wrap/i64"), -// I32TruncSF32 => write!(f, "i32.trunc_s/f32"), -// I32TruncUF32 => write!(f, "i32.trunc_u/f32"), -// I32TruncSF64 => write!(f, "i32.trunc_s/f64"), -// I32TruncUF64 => write!(f, "i32.trunc_u/f64"), - -// I64ExtendSI32 => write!(f, "i64.extend_s/i32"), -// I64ExtendUI32 => write!(f, "i64.extend_u/i32"), - -// I64TruncSF32 => write!(f, "i64.trunc_s/f32"), -// I64TruncUF32 => write!(f, "i64.trunc_u/f32"), -// I64TruncSF64 => write!(f, "i64.trunc_s/f64"), -// I64TruncUF64 => write!(f, "i64.trunc_u/f64"), - -// F32ConvertSI32 => write!(f, "f32.convert_s/i32"), -// F32ConvertUI32 => write!(f, "f32.convert_u/i32"), -// F32ConvertSI64 => write!(f, "f32.convert_s/i64"), -// F32ConvertUI64 => write!(f, "f32.convert_u/i64"), -// F32DemoteF64 => write!(f, "f32.demote/f64"), - -// F64ConvertSI32 => write!(f, "f64.convert_s/i32"), -// F64ConvertUI32 => write!(f, "f64.convert_u/i32"), -// F64ConvertSI64 => write!(f, "f64.convert_s/i64"), -// F64ConvertUI64 => write!(f, "f64.convert_u/i64"), -// F64PromoteF32 => write!(f, "f64.promote/f32"), - -// I32ReinterpretF32 => write!(f, "i32.reinterpret/f32"), -// I64ReinterpretF64 => write!(f, "i64.reinterpret/f64"), -// F32ReinterpretI32 => write!(f, "f32.reinterpret/i32"), -// F64ReinterpretI64 => write!(f, "f64.reinterpret/i64"), - -// I32Extend8S => write!(f, "i32.extend8_s"), -// I32Extend16S => write!(f, "i32.extend16_s"), -// I64Extend8S => write!(f, "i64.extend8_s"), -// I64Extend16S => write!(f, "i64.extend16_s"), -// I64Extend32S => write!(f, "i64.extend32_s"), - -// AtomicWake(_) => write!(f, "atomic.wake"), -// I32AtomicWait(_) => write!(f, "i32.atomic.wait"), -// I64AtomicWait(_) => write!(f, "i64.atomic.wait"), - -// I32AtomicLoad(_) => write!(f, "i32.atomic.load"), -// I64AtomicLoad(_) => write!(f, "i64.atomic.load"), -// I32AtomicLoad8u(_) => write!(f, "i32.atomic.load8_u"), -// I32AtomicLoad16u(_) => write!(f, "i32.atomic.load16_u"), -// I64AtomicLoad8u(_) => write!(f, "i64.atomic.load8_u"), -// I64AtomicLoad16u(_) => write!(f, "i64.atomic.load16_u"), -// I64AtomicLoad32u(_) => write!(f, "i64.atomic.load32_u"), -// I32AtomicStore(_) => write!(f, "i32.atomic.store"), -// I64AtomicStore(_) => write!(f, "i64.atomic.store"), -// I32AtomicStore8u(_) => write!(f, "i32.atomic.store8_u"), -// I32AtomicStore16u(_) => write!(f, "i32.atomic.store16_u"), -// I64AtomicStore8u(_) => write!(f, "i64.atomic.store8_u"), -// I64AtomicStore16u(_) => write!(f, "i64.atomic.store16_u"), -// I64AtomicStore32u(_) => write!(f, "i64.atomic.store32_u"), - -// I32AtomicRmwAdd(_) => write!(f, "i32.atomic.rmw.add"), -// I64AtomicRmwAdd(_) => write!(f, "i64.atomic.rmw.add"), -// I32AtomicRmwAdd8u(_) => write!(f, "i32.atomic.rmw8_u.add"), -// I32AtomicRmwAdd16u(_) => write!(f, "i32.atomic.rmw16_u.add"), -// I64AtomicRmwAdd8u(_) => write!(f, "i64.atomic.rmw8_u.add"), -// I64AtomicRmwAdd16u(_) => write!(f, "i64.atomic.rmw16_u.add"), -// I64AtomicRmwAdd32u(_) => write!(f, "i64.atomic.rmw32_u.add"), - -// I32AtomicRmwSub(_) => write!(f, "i32.atomic.rmw.sub"), -// I64AtomicRmwSub(_) => write!(f, "i64.atomic.rmw.sub"), -// I32AtomicRmwSub8u(_) => write!(f, "i32.atomic.rmw8_u.sub"), -// I32AtomicRmwSub16u(_) => write!(f, "i32.atomic.rmw16_u.sub"), -// I64AtomicRmwSub8u(_) => write!(f, "i64.atomic.rmw8_u.sub"), -// I64AtomicRmwSub16u(_) => write!(f, "i64.atomic.rmw16_u.sub"), -// I64AtomicRmwSub32u(_) => write!(f, "i64.atomic.rmw32_u.sub"), - -// I32AtomicRmwAnd(_) => write!(f, "i32.atomic.rmw.and"), -// I64AtomicRmwAnd(_) => write!(f, "i64.atomic.rmw.and"), -// I32AtomicRmwAnd8u(_) => write!(f, "i32.atomic.rmw8_u.and"), -// I32AtomicRmwAnd16u(_) => write!(f, "i32.atomic.rmw16_u.and"), -// I64AtomicRmwAnd8u(_) => write!(f, "i64.atomic.rmw8_u.and"), -// I64AtomicRmwAnd16u(_) => write!(f, "i64.atomic.rmw16_u.and"), -// I64AtomicRmwAnd32u(_) => write!(f, "i64.atomic.rmw32_u.and"), - -// I32AtomicRmwOr(_) => write!(f, "i32.atomic.rmw.or"), -// I64AtomicRmwOr(_) => write!(f, "i64.atomic.rmw.or"), -// I32AtomicRmwOr8u(_) => write!(f, "i32.atomic.rmw8_u.or"), -// I32AtomicRmwOr16u(_) => write!(f, "i32.atomic.rmw16_u.or"), -// I64AtomicRmwOr8u(_) => write!(f, "i64.atomic.rmw8_u.or"), -// I64AtomicRmwOr16u(_) => write!(f, "i64.atomic.rmw16_u.or"), -// I64AtomicRmwOr32u(_) => write!(f, "i64.atomic.rmw32_u.or"), - -// I32AtomicRmwXor(_) => write!(f, "i32.atomic.rmw.xor"), -// I64AtomicRmwXor(_) => write!(f, "i64.atomic.rmw.xor"), -// I32AtomicRmwXor8u(_) => write!(f, "i32.atomic.rmw8_u.xor"), -// I32AtomicRmwXor16u(_) => write!(f, "i32.atomic.rmw16_u.xor"), -// I64AtomicRmwXor8u(_) => write!(f, "i64.atomic.rmw8_u.xor"), -// I64AtomicRmwXor16u(_) => write!(f, "i64.atomic.rmw16_u.xor"), -// I64AtomicRmwXor32u(_) => write!(f, "i64.atomic.rmw32_u.xor"), - -// I32AtomicRmwXchg(_) => write!(f, "i32.atomic.rmw.xchg"), -// I64AtomicRmwXchg(_) => write!(f, "i64.atomic.rmw.xchg"), -// I32AtomicRmwXchg8u(_) => write!(f, "i32.atomic.rmw8_u.xchg"), -// I32AtomicRmwXchg16u(_) => write!(f, "i32.atomic.rmw16_u.xchg"), -// I64AtomicRmwXchg8u(_) => write!(f, "i64.atomic.rmw8_u.xchg"), -// I64AtomicRmwXchg16u(_) => write!(f, "i64.atomic.rmw16_u.xchg"), -// I64AtomicRmwXchg32u(_) => write!(f, "i64.atomic.rmw32_u.xchg"), - -// I32AtomicRmwCmpxchg(_) => write!(f, "i32.atomic.rmw.cmpxchg"), -// I64AtomicRmwCmpxchg(_) => write!(f, "i64.atomic.rmw.cmpxchg"), -// I32AtomicRmwCmpxchg8u(_) => write!(f, "i32.atomic.rmw8_u.cmpxchg"), -// I32AtomicRmwCmpxchg16u(_) => write!(f, "i32.atomic.rmw16_u.cmpxchg"), -// I64AtomicRmwCmpxchg8u(_) => write!(f, "i64.atomic.rmw8_u.cmpxchg"), -// I64AtomicRmwCmpxchg16u(_) => write!(f, "i64.atomic.rmw16_u.cmpxchg"), -// I64AtomicRmwCmpxchg32u(_) => write!(f, "i64.atomic.rmw32_u.cmpxchg"), - -// V128Const(_) => write!(f, "v128.const"), -// V128Load(_) => write!(f, "v128.load"), -// V128Store(_) => write!(f, "v128.store"), -// I8x16Splat => write!(f, "i8x16.splat"), -// I16x8Splat => write!(f, "i16x8.splat"), -// I32x4Splat => write!(f, "i32x4.splat"), -// I64x2Splat => write!(f, "i64x2.splat"), -// F32x4Splat => write!(f, "f32x4.splat"), -// F64x2Splat => write!(f, "f64x2.splat"), -// I8x16ExtractLaneS(_) => write!(f, "i8x16.extract_lane_s"), -// I8x16ExtractLaneU(_) => write!(f, "i8x16.extract_lane_u"), -// I16x8ExtractLaneS(_) => write!(f, "i16x8.extract_lane_s"), -// I16x8ExtractLaneU(_) => write!(f, "i16x8.extract_lane_u"), -// I32x4ExtractLane(_) => write!(f, "i32x4.extract_lane"), -// I64x2ExtractLane(_) => write!(f, "i64x2.extract_lane"), -// F32x4ExtractLane(_) => write!(f, "f32x4.extract_lane"), -// F64x2ExtractLane(_) => write!(f, "f64x2.extract_lane"), -// I8x16ReplaceLane(_) => write!(f, "i8x16.replace_lane"), -// I16x8ReplaceLane(_) => write!(f, "i16x8.replace_lane"), -// I32x4ReplaceLane(_) => write!(f, "i32x4.replace_lane"), -// I64x2ReplaceLane(_) => write!(f, "i64x2.replace_lane"), -// F32x4ReplaceLane(_) => write!(f, "f32x4.replace_lane"), -// F64x2ReplaceLane(_) => write!(f, "f64x2.replace_lane"), -// V8x16Shuffle(_) => write!(f, "v8x16.shuffle"), -// I8x16Add => write!(f, "i8x16.add"), -// I16x8Add => write!(f, "i16x8.add"), -// I32x4Add => write!(f, "i32x4.add"), -// I64x2Add => write!(f, "i64x2.add"), -// I8x16Sub => write!(f, "i8x16.sub"), -// I16x8Sub => write!(f, "i16x8.sub"), -// I32x4Sub => write!(f, "i32x4.sub"), -// I64x2Sub => write!(f, "i64x2.sub"), -// I8x16Mul => write!(f, "i8x16.mul"), -// I16x8Mul => write!(f, "i16x8.mul"), -// I32x4Mul => write!(f, "i32x4.mul"), -// // I64x2Mul => write!(f, "i64x2.mul"), -// I8x16Neg => write!(f, "i8x16.neg"), -// I16x8Neg => write!(f, "i16x8.neg"), -// I32x4Neg => write!(f, "i32x4.neg"), -// I64x2Neg => write!(f, "i64x2.neg"), -// I8x16AddSaturateS => write!(f, "i8x16.add_saturate_s"), -// I8x16AddSaturateU => write!(f, "i8x16.add_saturate_u"), -// I16x8AddSaturateS => write!(f, "i16x8.add_saturate_S"), -// I16x8AddSaturateU => write!(f, "i16x8.add_saturate_u"), -// I8x16SubSaturateS => write!(f, "i8x16.sub_saturate_S"), -// I8x16SubSaturateU => write!(f, "i8x16.sub_saturate_u"), -// I16x8SubSaturateS => write!(f, "i16x8.sub_saturate_S"), -// I16x8SubSaturateU => write!(f, "i16x8.sub_saturate_u"), -// I8x16Shl => write!(f, "i8x16.shl"), -// I16x8Shl => write!(f, "i16x8.shl"), -// I32x4Shl => write!(f, "i32x4.shl"), -// I64x2Shl => write!(f, "i64x2.shl"), -// I8x16ShrS => write!(f, "i8x16.shr_s"), -// I8x16ShrU => write!(f, "i8x16.shr_u"), -// I16x8ShrS => write!(f, "i16x8.shr_s"), -// I16x8ShrU => write!(f, "i16x8.shr_u"), -// I32x4ShrS => write!(f, "i32x4.shr_s"), -// I32x4ShrU => write!(f, "i32x4.shr_u"), -// I64x2ShrS => write!(f, "i64x2.shr_s"), -// I64x2ShrU => write!(f, "i64x2.shr_u"), -// V128And => write!(f, "v128.and"), -// V128Or => write!(f, "v128.or"), -// V128Xor => write!(f, "v128.xor"), -// V128Not => write!(f, "v128.not"), -// V128Bitselect => write!(f, "v128.bitselect"), -// I8x16AnyTrue => write!(f, "i8x16.any_true"), -// I16x8AnyTrue => write!(f, "i16x8.any_true"), -// I32x4AnyTrue => write!(f, "i32x4.any_true"), -// I64x2AnyTrue => write!(f, "i64x2.any_true"), -// I8x16AllTrue => write!(f, "i8x16.all_true"), -// I16x8AllTrue => write!(f, "i16x8.all_true"), -// I32x4AllTrue => write!(f, "i32x4.all_true"), -// I64x2AllTrue => write!(f, "i64x2.all_true"), -// I8x16Eq => write!(f, "i8x16.eq"), -// I16x8Eq => write!(f, "i16x8.eq"), -// I32x4Eq => write!(f, "i32x4.eq"), -// // I64x2Eq => write!(f, "i64x2.eq"), -// F32x4Eq => write!(f, "f32x4.eq"), -// F64x2Eq => write!(f, "f64x2.eq"), -// I8x16Ne => write!(f, "i8x16.ne"), -// I16x8Ne => write!(f, "i16x8.ne"), -// I32x4Ne => write!(f, "i32x4.ne"), -// // I64x2Ne => write!(f, "i64x2.ne"), -// F32x4Ne => write!(f, "f32x4.ne"), -// F64x2Ne => write!(f, "f64x2.ne"), -// I8x16LtS => write!(f, "i8x16.lt_s"), -// I8x16LtU => write!(f, "i8x16.lt_u"), -// I16x8LtS => write!(f, "i16x8.lt_s"), -// I16x8LtU => write!(f, "i16x8.lt_u"), -// I32x4LtS => write!(f, "i32x4.lt_s"), -// I32x4LtU => write!(f, "i32x4.lt_u"), -// // I64x2LtS => write!(f, "// I64x2.lt_s"), -// // I64x2LtU => write!(f, "// I64x2.lt_u"), -// F32x4Lt => write!(f, "f32x4.lt"), -// F64x2Lt => write!(f, "f64x2.lt"), -// I8x16LeS => write!(f, "i8x16.le_s"), -// I8x16LeU => write!(f, "i8x16.le_u"), -// I16x8LeS => write!(f, "i16x8.le_s"), -// I16x8LeU => write!(f, "i16x8.le_u"), -// I32x4LeS => write!(f, "i32x4.le_s"), -// I32x4LeU => write!(f, "i32x4.le_u"), -// // I64x2LeS => write!(f, "// I64x2.le_s"), -// // I64x2LeU => write!(f, "// I64x2.le_u"), -// F32x4Le => write!(f, "f32x4.le"), -// F64x2Le => write!(f, "f64x2.le"), -// I8x16GtS => write!(f, "i8x16.gt_s"), -// I8x16GtU => write!(f, "i8x16.gt_u"), -// I16x8GtS => write!(f, "i16x8.gt_s"), -// I16x8GtU => write!(f, "i16x8.gt_u"), -// I32x4GtS => write!(f, "i32x4.gt_s"), -// I32x4GtU => write!(f, "i32x4.gt_u"), -// // I64x2GtS => write!(f, "// I64x2.gt_s"), -// // I64x2GtU => write!(f, "// I64x2.gt_u"), -// F32x4Gt => write!(f, "f32x4.gt"), -// F64x2Gt => write!(f, "f64x2.gt"), -// I8x16GeS => write!(f, "i8x16.ge_s"), -// I8x16GeU => write!(f, "i8x16.ge_u"), -// I16x8GeS => write!(f, "i16x8.ge_s"), -// I16x8GeU => write!(f, "i16x8.ge_u"), -// I32x4GeS => write!(f, "i32x4.ge_s"), -// I32x4GeU => write!(f, "i32x4.ge_u"), -// // I64x2GeS => write!(f, "// I64x2.ge_s"), -// // I64x2GeU => write!(f, "// I64x2.ge_u"), -// F32x4Ge => write!(f, "f32x4.ge"), -// F64x2Ge => write!(f, "f64x2.ge"), -// F32x4Neg => write!(f, "f32x4.neg"), -// F64x2Neg => write!(f, "f64x2.neg"), -// F32x4Abs => write!(f, "f32x4.abs"), -// F64x2Abs => write!(f, "f64x2.abs"), -// F32x4Min => write!(f, "f32x4.min"), -// F64x2Min => write!(f, "f64x2.min"), -// F32x4Max => write!(f, "f32x4.max"), -// F64x2Max => write!(f, "f64x2.max"), -// F32x4Add => write!(f, "f32x4.add"), -// F64x2Add => write!(f, "f64x2.add"), -// F32x4Sub => write!(f, "f32x4.sub"), -// F64x2Sub => write!(f, "f64x2.sub"), -// F32x4Div => write!(f, "f32x4.div"), -// F64x2Div => write!(f, "f64x2.div"), -// F32x4Mul => write!(f, "f32x4.mul"), -// F64x2Mul => write!(f, "f64x2.mul"), -// F32x4Sqrt => write!(f, "f32x4.sqrt"), -// F64x2Sqrt => write!(f, "f64x2.sqrt"), -// F32x4ConvertSI32x4 => write!(f, "f32x4.convert_s/i32x4"), -// F32x4ConvertUI32x4 => write!(f, "f32x4.convert_u/i32x4"), -// F64x2ConvertSI64x2 => write!(f, "f64x2.convert_s/i64x2"), -// F64x2ConvertUI64x2 => write!(f, "f64x2.convert_u/i64x2"), -// I32x4TruncSF32x4Sat => write!(f, "i32x4.trunc_s/f32x4:sat"), -// I32x4TruncUF32x4Sat => write!(f, "i32x4.trunc_u/f32x4:sat"), -// I64x2TruncSF64x2Sat => write!(f, "i64x2.trunc_s/f64x2:sat"), -// I64x2TruncUF64x2Sat => write!(f, "i64x2.trunc_u/f64x2:sat"), - -// MemoryInit(_) => write!(f, "memory.init"), -// MemoryDrop(_) => write!(f, "memory.drop"), -// MemoryFill => write!(f, "memory.fill"), -// MemoryCopy => write!(f, "memory.copy"), -// TableInit(_) => write!(f, "table.init"), -// TableDrop(_) => write!(f, "table.drop"), -// TableCopy => write!(f, "table.copy"), -// } -// } -// } - -// impl Serialize for Instructions { -// type Error = Error; - -// fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { -// for op in self.0.into_iter() { -// op.serialize(writer)?; -// } - -// Ok(()) -// } -// } - -// impl Serialize for InitExpr { -// type Error = Error; - -// fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { -// for op in self.0.into_iter() { -// op.serialize(writer)?; -// } - -// Ok(()) -// } -// } - -// #[test] -// fn ifelse() { -// // see if-else.wast/if-else.wasm -// let instruction_list = super::deserialize_buffer::(&[0x04, 0x7F, 0x41, 0x05, 0x05, 0x41, 0x07, 0x0B, 0x0B]) -// .expect("valid hex of if instruction"); -// let instructions = instruction_list.elements(); -// match &instructions[0] { -// &Instruction::If(_) => (), -// _ => panic!("Should be deserialized as if instruction"), -// } -// let before_else = instructions.iter().skip(1) -// .take_while(|op| match **op { Instruction::Else => false, _ => true }).count(); -// let after_else = instructions.iter().skip(1) -// .skip_while(|op| match **op { Instruction::Else => false, _ => true }) -// .take_while(|op| match **op { Instruction::End => false, _ => true }) -// .count() -// - 1; // minus Instruction::Else itself -// assert_eq!(before_else, after_else); -// } - -// #[test] -// fn display() { -// let instruction = Instruction::GetLocal(0); -// assert_eq!("get_local 0", format!("{}", instruction)); - -// let instruction = Instruction::F64Store(0, 24); -// assert_eq!("f64.store offset=24", format!("{}", instruction)); - -// let instruction = Instruction::I64Store(0, 0); -// assert_eq!("i64.store", format!("{}", instruction)); -// } - -// #[test] -// fn size_off() { -// assert!(::std::mem::size_of::() <= 24); -// } - -// #[test] -// fn instructions_hashset() { -// use self::Instruction::{Call, Block, Drop}; -// use super::types::{BlockType::Value, ValueType}; - -// let set: std::collections::HashSet = -// vec![Call(1), Block(Value(ValueType::I32)), Drop].into_iter().collect(); -// assert_eq!(set.contains(&Drop), true) -// } diff --git a/kernel-ewasm/validator/src/io.rs b/kernel-ewasm/validator/src/io.rs index cfb437e..e1062e9 100644 --- a/kernel-ewasm/validator/src/io.rs +++ b/kernel-ewasm/validator/src/io.rs @@ -1,130 +1,120 @@ -//! Simple abstractions for the IO operations. -//! -//! Basically it just a replacement for the std::io that is usable from -//! the `no_std` environment. - -// use crate::rust::result; - #[cfg(feature="std")] use std::io; +#[cfg(not(feature = "std"))] use pwasm_std::vec::Vec; -use pwasm_std::String; - -// #[cfg(not(feature="std"))] -// use crate::rust::vec::Vec; /// IO specific error. #[derive(Debug)] pub enum Error { - /// Some unexpected data left in the buffer after reading all data. - TrailingData, + /// Some unexpected data left in the buffer after reading all data. + TrailingData, - /// Unexpected End-Of-File - UnexpectedEof, + /// Unexpected End-Of-File + UnexpectedEof, - /// Invalid data is encountered. - InvalidData, + /// Invalid data is encountered. + InvalidData, - #[cfg(feature = "std")] - IoError(io::Error), + #[cfg(feature = "std")] + IoError(io::Error), } /// IO specific Result. pub type Result = core::result::Result; pub trait Write { - /// Write a buffer of data into this write. - /// - /// All data is written at once. - fn write(&mut self, buf: &[u8]) -> Result<()>; + /// Write a buffer of data into this write. + /// + /// All data is written at once. + fn write(&mut self, buf: &[u8]) -> Result<()>; } pub trait Read { - /// Read a data from this read to a buffer. - /// - /// If there is not enough data in this read then `UnexpectedEof` will be returned. - fn read(&mut self, buf: &mut [u8]) -> Result<()>; + /// Read a data from this read to a buffer. + /// + /// If there is not enough data in this read then `UnexpectedEof` will be returned. + fn read(&mut self, buf: &mut [u8]) -> Result<()>; } /// Reader that saves the last position. pub struct Cursor { - inner: T, - pos: usize, + inner: T, + pos: usize, } impl Cursor { - pub fn new(inner: T) -> Cursor { - Cursor { - inner, - pos: 0, - } - } - - pub fn position(&self) -> usize { - self.pos - } + pub fn new(inner: T) -> Cursor { + Cursor { + inner, + pos: 0, + } + } + + pub fn position(&self) -> usize { + self.pos + } } impl> Read for Cursor { - fn read(&mut self, buf: &mut [u8]) -> Result<()> { - let slice = self.inner.as_ref(); - let remainder = slice.len() - self.pos; - let requested = buf.len(); - if requested > remainder { - return Err(Error::UnexpectedEof); - } - buf.copy_from_slice(&slice[self.pos..(self.pos + requested)]); - self.pos += requested; - Ok(()) - } + fn read(&mut self, buf: &mut [u8]) -> Result<()> { + let slice = self.inner.as_ref(); + let remainder = slice.len() - self.pos; + let requested = buf.len(); + if requested > remainder { + return Err(Error::UnexpectedEof); + } + buf.copy_from_slice(&slice[self.pos..(self.pos + requested)]); + self.pos += requested; + Ok(()) + } } #[cfg(not(feature = "std"))] impl Write for Vec { - fn write(&mut self, buf: &[u8]) -> Result<()> { - self.extend(buf); - Ok(()) - } + fn write(&mut self, buf: &[u8]) -> Result<()> { + self.extend(buf); + Ok(()) + } } #[cfg(feature = "std")] impl Read for T { - fn read(&mut self, buf: &mut [u8]) -> Result<()> { - self.read_exact(buf) - .map_err(Error::IoError) - } + fn read(&mut self, buf: &mut [u8]) -> Result<()> { + self.read_exact(buf) + .map_err(Error::IoError) + } } #[cfg(feature = "std")] impl Write for T { - fn write(&mut self, buf: &[u8]) -> Result<()> { - self.write_all(buf).map_err(Error::IoError) - } + fn write(&mut self, buf: &[u8]) -> Result<()> { + self.write_all(buf).map_err(Error::IoError) + } } #[cfg(test)] mod tests { - use super::*; - - #[test] - fn cursor() { - let mut cursor = Cursor::new(vec![0xFFu8, 0x7Fu8]); - assert_eq!(cursor.position(), 0); - - let mut buf = [0u8]; - assert!(cursor.read(&mut buf[..]).is_ok()); - assert_eq!(cursor.position(), 1); - assert_eq!(buf[0], 0xFFu8); - assert!(cursor.read(&mut buf[..]).is_ok()); - assert_eq!(buf[0], 0x7Fu8); - assert_eq!(cursor.position(), 2); - } - - #[test] - fn overflow_in_cursor() { - let mut cursor = Cursor::new(vec![0u8]); - let mut buf = [0, 1, 2]; - assert!(cursor.read(&mut buf[..]).is_err()); - } + use super::*; + + #[test] + fn cursor() { + let mut cursor = Cursor::new(vec![0xFFu8, 0x7Fu8]); + assert_eq!(cursor.position(), 0); + + let mut buf = [0u8]; + assert!(cursor.read(&mut buf[..]).is_ok()); + assert_eq!(cursor.position(), 1); + assert_eq!(buf[0], 0xFFu8); + assert!(cursor.read(&mut buf[..]).is_ok()); + assert_eq!(buf[0], 0x7Fu8); + assert_eq!(cursor.position(), 2); + } + + #[test] + fn overflow_in_cursor() { + let mut cursor = Cursor::new(vec![0u8]); + let mut buf = [0, 1, 2]; + assert!(cursor.read(&mut buf[..]).is_err()); + } } diff --git a/kernel-ewasm/validator/src/lib.rs b/kernel-ewasm/validator/src/lib.rs index 369dd90..9e3adea 100644 --- a/kernel-ewasm/validator/src/lib.rs +++ b/kernel-ewasm/validator/src/lib.rs @@ -1,40 +1,28 @@ #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(not(feature = "std"), feature(alloc))] - #[cfg(not(feature="std"))] #[macro_use] extern crate alloc; use pwasm_std; -// use parity_wasm; - -// pub use parity_wasm::elements::{ImportEntry, Module}; -// use parity_wasm::elements::Instruction; -// use parity_wasm::elements::{ValueType}; - use pwasm_std::vec::Vec; use pwasm_std::String; -mod instructions; +pub mod instructions; pub mod func; mod primitives; pub mod io; pub mod serialization; pub mod import_entry; pub mod types; -use io::Read; pub use self::io::{Error}; pub use self::serialization::{Serialize, Deserialize}; - pub use self::primitives::{ VarUint32, VarUint7, Uint8, VarUint1, VarInt7, Uint32, VarInt32, VarInt64, Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter, }; -// pub use parity_wasm::deserialize_buffer; - /// As per the wasm spec: /// /// Function Index Space @@ -125,22 +113,6 @@ impl Listed for ImportEntry { } } -/// Information on why the contract was considered invalid. -#[derive(Debug)] -pub struct ValidityReport { - pub validation_errors: Vec, -} - -#[derive(Debug)] -pub enum ValidityError { - // BlacklistedImport(ImportEntry), - UnsafeGreylistedCall { - // import: ImportEntry, - function_index: u32, - instruction_index: u32, - }, -} - /// Be able to determine a contracts validity. pub trait Validity { fn is_valid(&self) -> bool; @@ -149,21 +121,21 @@ pub trait Validity { // Seek does not seem to be implemented in core, so we'll reimplement what we // need. #[derive(Debug)] -struct Cursor { +struct Cursor<'a> { i: usize, - // data: &'a [u8], + data: &'a [u8], } -impl<'a> Cursor { +impl<'a> Cursor<'a> { // Read the byte at the cusor, and increment the pointer by 1. - fn read(&mut self, data: &'a [u8]) -> &'a u8 { - let val = &data[self.i]; + fn read(&mut self) -> &'a u8 { + let val = &self.data[self.i]; self.i += 1; val } - fn read_n(&mut self, n: usize, data: &'a [u8]) -> &'a [u8] { - let val = &data[self.i..(self.i+n)]; + fn read_n(&mut self, n: usize) -> &'a [u8] { + let val = &self.data[self.i..(self.i+n)]; self.i += n; val } @@ -178,21 +150,22 @@ impl Validity for &[u8] { // Set an index value, which is our offset into the wasm bytes. let mut cursor = Cursor { i: 0, - // data: self, + data: self, }; - if self.len() < 100 { - // println!("data: {:?}", &self); - } else { - // println!("data: {:?}", &self[0..100]); - } + + // The first two steps are to take the magic number and version to check + // that it is valid wasm. This is not strictly necessary, as it is the + // job of the runtime to ensure the wasm is valid (ad we rely on that + // fact), however, it's cheap and allows us prevent future versions of + // wasm code being deployed (for which our assumptions may not hold). + // Take the magic number, check that it matches - if cursor.read_n(4, &self) != &[0, 97, 115, 109] { + if cursor.read_n(4) != &[0, 97, 115, 109] { panic!("magic number not found"); } - // Take the version, check that it matches - if cursor.read_n(4, &self) != &[1, 0, 0, 0] { + if cursor.read_n(4) != &[1, 0, 0, 0] { panic!("proper version number not found"); } @@ -206,10 +179,7 @@ impl Validity for &[u8] { let mut function_section_offset: Option = None; let mut code_section_offset: Option = None; while cursor.i < self.len() { - // let section: Section = parse_section(&mut i, &self[d..]); - // println!("i: {:?}", cursor.i); - let section: Section = parse_section(&mut cursor, &self); - // println!("section: {:?}: index: {}", section.type_, section.offset); + let section: Section = parse_section(&mut cursor); // There are many section types we don't care about, for example, // Custom sections generally contain debugging symbols and // meaningful function names which are irrelevant to the current @@ -248,17 +218,17 @@ impl Validity for &[u8] { let mut dcall_index: Option = None; if let Some(imports_offset) = import_section_offset { // Make a new cursor for imports - let mut imports_cursor = Cursor {i:imports_offset}; - let section_size = parse_varuint_32(&mut imports_cursor, &self); + let mut imports_cursor = Cursor {i:imports_offset,data:&self}; + let _section_size = parse_varuint_32(&mut imports_cursor); // How many imports do we have? - let n_imports = parse_varuint_32(&mut imports_cursor, &self); + let n_imports = parse_varuint_32(&mut imports_cursor); // println!("n_imports: {}", n_imports); for i in 0..n_imports { // let mut cursor = Cursor {i:0}; // Here we parse the names of the import, and its function // index. - let import = parse_import(&mut imports_cursor, &self, i); + let import = parse_import(&mut imports_cursor, i); // println!("mod_name: {}, field_name: {}, f_index: {}, listing: {:?}", // import.mod_name, import.field_name, import.index, import.listing()); @@ -283,16 +253,16 @@ impl Validity for &[u8] { // a vector of type ids. We don't care about types at this stage. if let (Some(functions_offset), Some(code_offset)) = (function_section_offset, code_section_offset) { // Make a new cursor for functions - let mut functions_cursor = Cursor {i:functions_offset}; + let mut functions_cursor = Cursor {i:functions_offset,data:&self}; // Make a new cursor for code - let mut code_cursor = Cursor {i:code_offset}; + let mut code_cursor = Cursor {i:code_offset,data:&self}; // We will have to try and update these in parallel - let function_section_size = parse_varuint_32(&mut functions_cursor, &self); - let code_section_size = parse_varuint_32(&mut code_cursor, &self); + let _function_section_size = parse_varuint_32(&mut functions_cursor); + let _code_section_size = parse_varuint_32(&mut code_cursor); // println!("functions_offset: {:?}", functions_offset); // println!("code_offset: {:?}", code_offset); - let n_functions = parse_varuint_32(&mut functions_cursor, &self); - let n_bodies = parse_varuint_32(&mut code_cursor, &self); + let n_functions = parse_varuint_32(&mut functions_cursor); + let n_bodies = parse_varuint_32(&mut code_cursor); // println!("functions_size: {:?}", function_section_size); // println!("code_size: {:?}", code_section_size); @@ -301,8 +271,8 @@ impl Validity for &[u8] { // Next we iterate through the function bodies and check if they // violate any of our rules. - for i in 0..n_bodies { - let body_size = parse_varuint_32(&mut code_cursor, &self); + for _i in 0..n_bodies { + let body_size = parse_varuint_32(&mut code_cursor); // First we check if it is a system call if is_syscall(&self[(code_cursor.i)..(code_cursor.i+body_size as usize)]) { // If the function is a system call we can continue past it @@ -401,17 +371,13 @@ struct Section { offset: usize, } -fn parse_section(cursor: &mut Cursor, data: &[u8]) -> Section { - let type_n = cursor.read(data); +fn parse_section(cursor: &mut Cursor) -> Section { + let type_n = cursor.read(); let offset = cursor.i; - // println!("type_n: {:?}", type_n); - let size_n = parse_varuint_32(cursor, data); - // println!("size_n: {:?}", size_n); + let size_n = parse_varuint_32(cursor); let type_ = n_to_section(type_n); let section = Section { type_, - // data: &cursor.data[0..0], - // data: &data[(cursor.i)..(cursor.i+size_n as usize)], offset, }; cursor.i += size_n as usize; @@ -436,13 +402,13 @@ fn n_to_section(byte: &u8) -> SectionType { } } -fn parse_varuint_32(cursor: &mut Cursor, data: &[u8]) -> u32 { +fn parse_varuint_32(cursor: &mut Cursor) -> u32 { let mut res = 0; let mut shift = 0; loop { if shift > 31 { panic!("invalid varuint32"); } - let b = cursor.read(data).clone() as u32; + let b = cursor.read().clone() as u32; res |= (b & 0x7f).checked_shl(shift).expect("invalid varuint32"); shift += 7; if (b >> 7) == 0 { @@ -455,10 +421,10 @@ fn parse_varuint_32(cursor: &mut Cursor, data: &[u8]) -> u32 { res } -fn parse_import(cursor: &mut Cursor, data: &[u8], index: u32) -> ImportEntry { +fn parse_import(cursor: &mut Cursor, index: u32) -> ImportEntry { let mut reader = CodeCursor { current_offset: cursor.i, - body: data, + body: cursor.data, }; let import: import_entry::ImportEntry = import_entry::ImportEntry::deserialize(&mut reader).expect("counted list"); ImportEntry { @@ -623,8 +589,8 @@ impl<'a> Code<'a> { current_offset: 0, body: body, }; - let locals: Vec = CountedList::::deserialize(&mut reader).expect("counted list").into_inner(); - // println!("locals: {:?}", locals); + // We currently don't care about locals + let _locals: Vec = CountedList::::deserialize(&mut reader).expect("counted list").into_inner(); Code { current_offset: reader.current_offset, body: body, @@ -637,11 +603,12 @@ struct CodeCursor<'a> { body: &'a [u8], } +// This is basically the rust definition of read for slice impl<'a> io::Read for CodeCursor<'a> { fn read(&mut self, buf: &mut [u8]) -> io::Result<()> { let actual_self = &self.body[self.current_offset..]; let amt = core::cmp::min(buf.len(), actual_self.len()); - let (a, b) = actual_self.split_at(amt); + let (a, _) = actual_self.split_at(amt); if amt == 1 { buf[0] = a[0]; @@ -656,14 +623,9 @@ impl<'a> io::Read for CodeCursor<'a> { impl<'a> Iterator for Code<'a> { - // we will be counting with usize type Item = crate::instructions::Instruction; - // next() is the only required method fn next(&mut self) -> Option { - // Increment our count. This is why we started at zero. - - // Check to see if we've finished counting or not. if self.current_offset < self.body.len() { // We need to parse the code into something meaningful let mut reader = CodeCursor { @@ -698,7 +660,7 @@ pub fn is_syscall(body: &[u8]) -> bool { // 0. call gasleft - if let Some((instr_index, instructions::Instruction::Call(f_ind))) = indexed_iter.next() { + if let Some((_instr_index, instructions::Instruction::Call(_f_ind))) = indexed_iter.next() { // Check that f_ind is the function index of "gasleft" // println!("call_index: {}", f_ind); } @@ -779,17 +741,10 @@ pub fn is_syscall(body: &[u8]) -> bool { #[cfg(test)] mod tests { - // extern crate pwasm_test; - // use std; use super::*; use wabt::wat2wasm; - // use core::str::FromStr; - // use pwasm_abi::types::*; - // use self::pwasm_test::{ext_reset, ext_get}; - // use token::TokenInterface; - use std::io; - use std::io::prelude::*; use std::fs::File; + use std::io::Read; #[test] fn module_only_pass() { diff --git a/kernel-ewasm/validator/src/primitives.rs b/kernel-ewasm/validator/src/primitives.rs index 79bd589..192de55 100644 --- a/kernel-ewasm/validator/src/primitives.rs +++ b/kernel-ewasm/validator/src/primitives.rs @@ -5,24 +5,23 @@ use crate::{Deserialize, Serialize}; use pwasm_std::vec::Vec; use pwasm_std::String; use crate::serialization::{Error}; -use crate::serialization::{deserialize_buffer}; macro_rules! buffered_read { - ($buffer_size: expr, $length: expr, $reader: expr) => { - { - let mut vec_buf = Vec::new(); - let mut total_read = 0; - let mut buf = [0u8; $buffer_size]; - while total_read < $length { - let next_to_read = if $length - total_read > $buffer_size { $buffer_size } else { $length - total_read }; - $reader.read(&mut buf[0..next_to_read])?; - vec_buf.extend_from_slice(&buf[0..next_to_read]); - total_read += next_to_read; - } - vec_buf - } - } + ($buffer_size: expr, $length: expr, $reader: expr) => { + { + let mut vec_buf = Vec::new(); + let mut total_read = 0; + let mut buf = [0u8; $buffer_size]; + while total_read < $length { + let next_to_read = if $length - total_read > $buffer_size { $buffer_size } else { $length - total_read }; + $reader.read(&mut buf[0..next_to_read])?; + vec_buf.extend_from_slice(&buf[0..next_to_read]); + total_read += next_to_read; + } + vec_buf + } + } } @@ -33,73 +32,73 @@ macro_rules! buffered_read { pub struct VarUint32(u32); impl From for usize { - fn from(var: VarUint32) -> usize { - var.0 as usize - } + fn from(var: VarUint32) -> usize { + var.0 as usize + } } impl From for u32 { - fn from(var: VarUint32) -> u32 { - var.0 - } + fn from(var: VarUint32) -> u32 { + var.0 + } } impl From for VarUint32 { - fn from(i: u32) -> VarUint32 { - VarUint32(i) - } + fn from(i: u32) -> VarUint32 { + VarUint32(i) + } } impl From for VarUint32 { - fn from(i: usize) -> VarUint32 { - assert!(i <= u32::max_value() as usize); - VarUint32(i as u32) - } + fn from(i: usize) -> VarUint32 { + assert!(i <= u32::max_value() as usize); + VarUint32(i as u32) + } } impl Deserialize for VarUint32 { - type Error = Error; - - fn deserialize(reader: &mut R) -> Result { - let mut res = 0; - let mut shift = 0; - let mut u8buf = [0u8; 1]; - loop { - if shift > 31 { return Err(Error::InvalidVarUint32); } - - reader.read(&mut u8buf)?; - let b = u8buf[0] as u32; - res |= (b & 0x7f).checked_shl(shift).ok_or(Error::InvalidVarUint32)?; - shift += 7; - if (b >> 7) == 0 { - if shift >= 32 && (b as u8).leading_zeros() < 4 { - return Err(Error::InvalidVarInt32); - } - break; - } - } - Ok(VarUint32(res)) - } + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut res = 0; + let mut shift = 0; + let mut u8buf = [0u8; 1]; + loop { + if shift > 31 { return Err(Error::InvalidVarUint32); } + + reader.read(&mut u8buf)?; + let b = u8buf[0] as u32; + res |= (b & 0x7f).checked_shl(shift).ok_or(Error::InvalidVarUint32)?; + shift += 7; + if (b >> 7) == 0 { + if shift >= 32 && (b as u8).leading_zeros() < 4 { + return Err(Error::InvalidVarInt32); + } + break; + } + } + Ok(VarUint32(res)) + } } impl Serialize for VarUint32 { - type Error = Error; + type Error = Error; - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - let mut buf = [0u8; 1]; - let mut v = self.0; - loop { - buf[0] = (v & 0b0111_1111) as u8; - v >>= 7; - if v > 0 { - buf[0] |= 0b1000_0000; - } - writer.write(&buf[..])?; - if v == 0 { break; } - } + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + let mut buf = [0u8; 1]; + let mut v = self.0; + loop { + buf[0] = (v & 0b0111_1111) as u8; + v >>= 7; + if v > 0 { + buf[0] |= 0b1000_0000; + } + writer.write(&buf[..])?; + if v == 0 { break; } + } - Ok(()) - } + Ok(()) + } } /// Unsigned variable-length integer, limited to 64 bits, @@ -108,60 +107,60 @@ impl Serialize for VarUint32 { pub struct VarUint64(u64); impl From for u64 { - fn from(var: VarUint64) -> u64 { - var.0 - } + fn from(var: VarUint64) -> u64 { + var.0 + } } impl Deserialize for VarUint64 { - type Error = Error; - - fn deserialize(reader: &mut R) -> Result { - let mut res = 0; - let mut shift = 0; - let mut u8buf = [0u8; 1]; - loop { - if shift > 63 { return Err(Error::InvalidVarUint64); } - - reader.read(&mut u8buf)?; - let b = u8buf[0] as u64; - res |= (b & 0x7f).checked_shl(shift).ok_or(Error::InvalidVarUint64)?; - shift += 7; - if (b >> 7) == 0 { - if shift >= 64 && (b as u8).leading_zeros() < 7 { - return Err(Error::InvalidVarInt64); - } - break; - } - } - Ok(VarUint64(res)) - } + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut res = 0; + let mut shift = 0; + let mut u8buf = [0u8; 1]; + loop { + if shift > 63 { return Err(Error::InvalidVarUint64); } + + reader.read(&mut u8buf)?; + let b = u8buf[0] as u64; + res |= (b & 0x7f).checked_shl(shift).ok_or(Error::InvalidVarUint64)?; + shift += 7; + if (b >> 7) == 0 { + if shift >= 64 && (b as u8).leading_zeros() < 7 { + return Err(Error::InvalidVarInt64); + } + break; + } + } + Ok(VarUint64(res)) + } } impl Serialize for VarUint64 { - type Error = Error; + type Error = Error; - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - let mut buf = [0u8; 1]; - let mut v = self.0; - loop { - buf[0] = (v & 0b0111_1111) as u8; - v >>= 7; - if v > 0 { - buf[0] |= 0b1000_0000; - } - writer.write(&buf[..])?; - if v == 0 { break; } - } + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + let mut buf = [0u8; 1]; + let mut v = self.0; + loop { + buf[0] = (v & 0b0111_1111) as u8; + v >>= 7; + if v > 0 { + buf[0] |= 0b1000_0000; + } + writer.write(&buf[..])?; + if v == 0 { break; } + } - Ok(()) - } + Ok(()) + } } impl From for VarUint64 { - fn from(u: u64) -> VarUint64 { - VarUint64(u) - } + fn from(u: u64) -> VarUint64 { + VarUint64(u) + } } /// 7-bit unsigned integer, encoded in LEB128 (always 1 byte length). @@ -169,35 +168,35 @@ impl From for VarUint64 { pub struct VarUint7(u8); impl From for u8 { - fn from(v: VarUint7) -> u8 { - v.0 - } + fn from(v: VarUint7) -> u8 { + v.0 + } } impl From for VarUint7 { - fn from(v: u8) -> Self { - VarUint7(v) - } + fn from(v: u8) -> Self { + VarUint7(v) + } } impl Deserialize for VarUint7 { - type Error = Error; + type Error = Error; - fn deserialize(reader: &mut R) -> Result { - let mut u8buf = [0u8; 1]; - reader.read(&mut u8buf)?; - Ok(VarUint7(u8buf[0])) - } + fn deserialize(reader: &mut R) -> Result { + let mut u8buf = [0u8; 1]; + reader.read(&mut u8buf)?; + Ok(VarUint7(u8buf[0])) + } } impl Serialize for VarUint7 { - type Error = Error; + type Error = Error; - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - // todo check range? - writer.write(&[self.0])?; - Ok(()) - } + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + // todo check range? + writer.write(&[self.0])?; + Ok(()) + } } /// 7-bit signed integer, encoded in LEB128 (always 1 byte length) @@ -205,46 +204,46 @@ impl Serialize for VarUint7 { pub struct VarInt7(i8); impl From for i8 { - fn from(v: VarInt7) -> i8 { - v.0 - } + fn from(v: VarInt7) -> i8 { + v.0 + } } impl From for VarInt7 { - fn from(v: i8) -> VarInt7 { - VarInt7(v) - } + fn from(v: i8) -> VarInt7 { + VarInt7(v) + } } impl Deserialize for VarInt7 { - type Error = Error; + type Error = Error; - fn deserialize(reader: &mut R) -> Result { - let mut u8buf = [0u8; 1]; - reader.read(&mut u8buf)?; + fn deserialize(reader: &mut R) -> Result { + let mut u8buf = [0u8; 1]; + reader.read(&mut u8buf)?; - // check if number is not continued! - if u8buf[0] & 0b1000_0000 != 0 { - return Err(Error::InvalidVarInt7(u8buf[0])); - } + // check if number is not continued! + if u8buf[0] & 0b1000_0000 != 0 { + return Err(Error::InvalidVarInt7(u8buf[0])); + } - // expand sign - if u8buf[0] & 0b0100_0000 == 0b0100_0000 { u8buf[0] |= 0b1000_0000 } + // expand sign + if u8buf[0] & 0b0100_0000 == 0b0100_0000 { u8buf[0] |= 0b1000_0000 } - Ok(VarInt7(u8buf[0] as i8)) - } + Ok(VarInt7(u8buf[0] as i8)) + } } impl Serialize for VarInt7 { - type Error = Error; + type Error = Error; - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - // todo check range? - let mut b: u8 = self.0 as u8; - if self.0 < 0 { b |= 0b0100_0000; b &= 0b0111_1111; } - writer.write(&[b])?; - Ok(()) - } + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + // todo check range? + let mut b: u8 = self.0 as u8; + if self.0 < 0 { b |= 0b0100_0000; b &= 0b0111_1111; } + writer.write(&[b])?; + Ok(()) + } } /// 8-bit unsigned integer, NOT encoded in LEB128; @@ -253,34 +252,34 @@ impl Serialize for VarInt7 { pub struct Uint8(u8); impl From for u8 { - fn from(v: Uint8) -> u8 { - v.0 - } + fn from(v: Uint8) -> u8 { + v.0 + } } impl From for Uint8 { - fn from(v: u8) -> Self { - Uint8(v) - } + fn from(v: u8) -> Self { + Uint8(v) + } } impl Deserialize for Uint8 { - type Error = Error; + type Error = Error; - fn deserialize(reader: &mut R) -> Result { - let mut u8buf = [0u8; 1]; - reader.read(&mut u8buf)?; - Ok(Uint8(u8buf[0])) - } + fn deserialize(reader: &mut R) -> Result { + let mut u8buf = [0u8; 1]; + reader.read(&mut u8buf)?; + Ok(Uint8(u8buf[0])) + } } impl Serialize for Uint8 { - type Error = Error; + type Error = Error; - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - writer.write(&[self.0])?; - Ok(()) - } + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + writer.write(&[self.0])?; + Ok(()) + } } @@ -289,72 +288,72 @@ impl Serialize for Uint8 { pub struct VarInt32(i32); impl From for i32 { - fn from(v: VarInt32) -> i32 { - v.0 - } + fn from(v: VarInt32) -> i32 { + v.0 + } } impl From for VarInt32 { - fn from(v: i32) -> VarInt32 { - VarInt32(v) - } + fn from(v: i32) -> VarInt32 { + VarInt32(v) + } } impl Deserialize for VarInt32 { - type Error = Error; - - fn deserialize(reader: &mut R) -> Result { - let mut res = 0; - let mut shift = 0; - let mut u8buf = [0u8; 1]; - loop { - if shift > 31 { return Err(Error::InvalidVarInt32); } - reader.read(&mut u8buf)?; - let b = u8buf[0]; - - res |= ((b & 0x7f) as i32).checked_shl(shift).ok_or(Error::InvalidVarInt32)?; - - shift += 7; - if (b >> 7) == 0 { - if shift < 32 && b & 0b0100_0000 == 0b0100_0000 { - res |= (1i32 << shift).wrapping_neg(); - } else if shift >= 32 && b & 0b0100_0000 == 0b0100_0000 { - if (!(b | 0b1000_0000)).leading_zeros() < 5 { - return Err(Error::InvalidVarInt32); - } - } else if shift >= 32 && b & 0b0100_0000 == 0 { - if b.leading_zeros() < 5 { - return Err(Error::InvalidVarInt32); - } - } - break; - } - } - Ok(VarInt32(res)) - } + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut res = 0; + let mut shift = 0; + let mut u8buf = [0u8; 1]; + loop { + if shift > 31 { return Err(Error::InvalidVarInt32); } + reader.read(&mut u8buf)?; + let b = u8buf[0]; + + res |= ((b & 0x7f) as i32).checked_shl(shift).ok_or(Error::InvalidVarInt32)?; + + shift += 7; + if (b >> 7) == 0 { + if shift < 32 && b & 0b0100_0000 == 0b0100_0000 { + res |= (1i32 << shift).wrapping_neg(); + } else if shift >= 32 && b & 0b0100_0000 == 0b0100_0000 { + if (!(b | 0b1000_0000)).leading_zeros() < 5 { + return Err(Error::InvalidVarInt32); + } + } else if shift >= 32 && b & 0b0100_0000 == 0 { + if b.leading_zeros() < 5 { + return Err(Error::InvalidVarInt32); + } + } + break; + } + } + Ok(VarInt32(res)) + } } impl Serialize for VarInt32 { - type Error = Error; + type Error = Error; - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - let mut buf = [0u8; 1]; - let mut v = self.0; - let mut more = true; - while more { - buf[0] = (v & 0b0111_1111) as u8; - v >>= 7; - if (v == 0 && buf[0] & 0b0100_0000 == 0) || (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) { - more = false - } else { - buf[0] |= 0b1000_0000 - } + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + let mut buf = [0u8; 1]; + let mut v = self.0; + let mut more = true; + while more { + buf[0] = (v & 0b0111_1111) as u8; + v >>= 7; + if (v == 0 && buf[0] & 0b0100_0000 == 0) || (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) { + more = false + } else { + buf[0] |= 0b1000_0000 + } - writer.write(&buf[..])?; - } + writer.write(&buf[..])?; + } - Ok(()) - } + Ok(()) + } } /// 64-bit signed integer, encoded in LEB128 (can be 1-9 bytes length). @@ -362,71 +361,71 @@ impl Serialize for VarInt32 { pub struct VarInt64(i64); impl From for i64 { - fn from(v: VarInt64) -> i64 { - v.0 - } + fn from(v: VarInt64) -> i64 { + v.0 + } } impl From for VarInt64 { - fn from(v: i64) -> VarInt64 { - VarInt64(v) - } + fn from(v: i64) -> VarInt64 { + VarInt64(v) + } } impl Deserialize for VarInt64 { - type Error = Error; - - fn deserialize(reader: &mut R) -> Result { - let mut res = 0i64; - let mut shift = 0; - let mut u8buf = [0u8; 1]; - - loop { - if shift > 63 { return Err(Error::InvalidVarInt64); } - reader.read(&mut u8buf)?; - let b = u8buf[0]; - - res |= ((b & 0x7f) as i64).checked_shl(shift).ok_or(Error::InvalidVarInt64)?; - - shift += 7; - if (b >> 7) == 0 { - if shift < 64 && b & 0b0100_0000 == 0b0100_0000 { - res |= (1i64 << shift).wrapping_neg(); - } else if shift >= 64 && b & 0b0100_0000 == 0b0100_0000 { - if (b | 0b1000_0000) as i8 != -1 { - return Err(Error::InvalidVarInt64); - } - } else if shift >= 64 && b != 0 { - return Err(Error::InvalidVarInt64); - } - break; - } - } - Ok(VarInt64(res)) - } + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let mut res = 0i64; + let mut shift = 0; + let mut u8buf = [0u8; 1]; + + loop { + if shift > 63 { return Err(Error::InvalidVarInt64); } + reader.read(&mut u8buf)?; + let b = u8buf[0]; + + res |= ((b & 0x7f) as i64).checked_shl(shift).ok_or(Error::InvalidVarInt64)?; + + shift += 7; + if (b >> 7) == 0 { + if shift < 64 && b & 0b0100_0000 == 0b0100_0000 { + res |= (1i64 << shift).wrapping_neg(); + } else if shift >= 64 && b & 0b0100_0000 == 0b0100_0000 { + if (b | 0b1000_0000) as i8 != -1 { + return Err(Error::InvalidVarInt64); + } + } else if shift >= 64 && b != 0 { + return Err(Error::InvalidVarInt64); + } + break; + } + } + Ok(VarInt64(res)) + } } impl Serialize for VarInt64 { - type Error = Error; + type Error = Error; - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - let mut buf = [0u8; 1]; - let mut v = self.0; - let mut more = true; - while more { - buf[0] = (v & 0b0111_1111) as u8; - v >>= 7; - if (v == 0 && buf[0] & 0b0100_0000 == 0) || (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) { - more = false - } else { - buf[0] |= 0b1000_0000 - } + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + let mut buf = [0u8; 1]; + let mut v = self.0; + let mut more = true; + while more { + buf[0] = (v & 0b0111_1111) as u8; + v >>= 7; + if (v == 0 && buf[0] & 0b0100_0000 == 0) || (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) { + more = false + } else { + buf[0] |= 0b1000_0000 + } - writer.write(&buf[..])?; - } + writer.write(&buf[..])?; + } - Ok(()) - } + Ok(()) + } } /// 32-bit unsigned integer, encoded in little endian. @@ -434,33 +433,33 @@ impl Serialize for VarInt64 { pub struct Uint32(u32); impl Deserialize for Uint32 { - type Error = Error; + type Error = Error; - fn deserialize(reader: &mut R) -> Result { - let mut buf = [0u8; 4]; - reader.read(&mut buf)?; - // todo check range - Ok(u32::from_le_bytes(buf).into()) - } + fn deserialize(reader: &mut R) -> Result { + let mut buf = [0u8; 4]; + reader.read(&mut buf)?; + // todo check range + Ok(u32::from_le_bytes(buf).into()) + } } impl From for u32 { - fn from(var: Uint32) -> u32 { - var.0 - } + fn from(var: Uint32) -> u32 { + var.0 + } } impl Serialize for Uint32 { - type Error = Error; + type Error = Error; - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - writer.write(&self.0.to_le_bytes())?; - Ok(()) - } + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + writer.write(&self.0.to_le_bytes())?; + Ok(()) + } } impl From for Uint32 { - fn from(u: u32) -> Self { Uint32(u) } + fn from(u: u32) -> Self { Uint32(u) } } /// 64-bit unsigned integer, encoded in little endian. @@ -468,33 +467,33 @@ impl From for Uint32 { pub struct Uint64(u64); impl Deserialize for Uint64 { - type Error = Error; + type Error = Error; - fn deserialize(reader: &mut R) -> Result { - let mut buf = [0u8; 8]; - reader.read(&mut buf)?; - // todo check range - Ok(u64::from_le_bytes(buf).into()) - } + fn deserialize(reader: &mut R) -> Result { + let mut buf = [0u8; 8]; + reader.read(&mut buf)?; + // todo check range + Ok(u64::from_le_bytes(buf).into()) + } } impl Serialize for Uint64 { - type Error = Error; + type Error = Error; - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - writer.write(&self.0.to_le_bytes())?; - Ok(()) - } + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + writer.write(&self.0.to_le_bytes())?; + Ok(()) + } } impl From for Uint64 { - fn from(u: u64) -> Self { Uint64(u) } + fn from(u: u64) -> Self { Uint64(u) } } impl From for u64 { - fn from(var: Uint64) -> u64 { - var.0 - } + fn from(var: Uint64) -> u64 { + var.0 + } } @@ -503,64 +502,64 @@ impl From for u64 { pub struct VarUint1(bool); impl From for bool { - fn from(v: VarUint1) -> bool { - v.0 - } + fn from(v: VarUint1) -> bool { + v.0 + } } impl From for VarUint1 { - fn from(b: bool) -> Self { - VarUint1(b) - } + fn from(b: bool) -> Self { + VarUint1(b) + } } impl Deserialize for VarUint1 { - type Error = Error; + type Error = Error; - fn deserialize(reader: &mut R) -> Result { - let mut u8buf = [0u8; 1]; - reader.read(&mut u8buf)?; - match u8buf[0] { - 0 => Ok(VarUint1(false)), - 1 => Ok(VarUint1(true)), - v @ _ => Err(Error::InvalidVarUint1(v)), - } - } + fn deserialize(reader: &mut R) -> Result { + let mut u8buf = [0u8; 1]; + reader.read(&mut u8buf)?; + match u8buf[0] { + 0 => Ok(VarUint1(false)), + 1 => Ok(VarUint1(true)), + v @ _ => Err(Error::InvalidVarUint1(v)), + } + } } impl Serialize for VarUint1 { - type Error = Error; + type Error = Error; - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - writer.write(&[ - if self.0 { 1u8 } else { 0u8 } - ])?; - Ok(()) - } + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + writer.write(&[ + if self.0 { 1u8 } else { 0u8 } + ])?; + Ok(()) + } } impl Deserialize for String { - type Error = Error; + type Error = Error; - fn deserialize(reader: &mut R) -> Result { - let length = u32::from(VarUint32::deserialize(reader)?) as usize; - if length > 0 { - String::from_utf8(buffered_read!(1024, length, reader)).map_err(|_| Error::NonUtf8String) - } - else { - Ok(String::new()) - } - } + fn deserialize(reader: &mut R) -> Result { + let length = u32::from(VarUint32::deserialize(reader)?) as usize; + if length > 0 { + String::from_utf8(buffered_read!(1024, length, reader)).map_err(|_| Error::NonUtf8String) + } + else { + Ok(String::new()) + } + } } impl Serialize for String { - type Error = Error; + type Error = Error; - fn serialize(self, writer: &mut W) -> Result<(), Error> { - VarUint32::from(self.len()).serialize(writer)?; - writer.write(&self.into_bytes()[..])?; - Ok(()) - } + fn serialize(self, writer: &mut W) -> Result<(), Error> { + VarUint32::from(self.len()).serialize(writer)?; + writer.write(&self.into_bytes()[..])?; + Ok(()) + } } /// List for reading sequence of elements typed `T`, given @@ -569,56 +568,56 @@ impl Serialize for String { pub struct CountedList(Vec); impl CountedList { - /// Destroy counted list returing inner vector. - pub fn into_inner(self) -> Vec { self.0 } + /// Destroy counted list returing inner vector. + pub fn into_inner(self) -> Vec { self.0 } } impl Deserialize for CountedList where T::Error: From { - type Error = T::Error; + type Error = T::Error; - fn deserialize(reader: &mut R) -> Result { - let count: usize = VarUint32::deserialize(reader)?.into(); - let mut result = Vec::new(); - for _ in 0..count { result.push(T::deserialize(reader)?); } - Ok(CountedList(result)) - } + fn deserialize(reader: &mut R) -> Result { + let count: usize = VarUint32::deserialize(reader)?.into(); + let mut result = Vec::new(); + for _ in 0..count { result.push(T::deserialize(reader)?); } + Ok(CountedList(result)) + } } /// Helper struct to write payload which is preceded by /// it's own length in bytes. #[derive(Debug)] pub struct CountedWriter<'a, W: 'a + io::Write> { - writer: &'a mut W, - data: Vec, + writer: &'a mut W, + data: Vec, } impl<'a, W: 'a + io::Write> CountedWriter<'a, W> { - /// New counted writer on top of the given serial writer. - pub fn new(writer: &'a mut W) -> Self { - CountedWriter { - writer: writer, - data: Vec::new(), - } - } - - /// Finish counted writer routing, which writes accumulated length - /// and actual payload. - pub fn done(self) -> io::Result<()> { - let writer = self.writer; - let data = self.data; - VarUint32::from(data.len()) - .serialize(writer) - .map_err(|_| io::Error::InvalidData)?; - writer.write(&data[..])?; - Ok(()) - } + /// New counted writer on top of the given serial writer. + pub fn new(writer: &'a mut W) -> Self { + CountedWriter { + writer: writer, + data: Vec::new(), + } + } + + /// Finish counted writer routing, which writes accumulated length + /// and actual payload. + pub fn done(self) -> io::Result<()> { + let writer = self.writer; + let data = self.data; + VarUint32::from(data.len()) + .serialize(writer) + .map_err(|_| io::Error::InvalidData)?; + writer.write(&data[..])?; + Ok(()) + } } impl<'a, W: 'a + io::Write> io::Write for CountedWriter<'a, W> { - fn write(&mut self, buf: &[u8]) -> io::Result<()> { - self.data.extend_from_slice(buf); - Ok(()) - } + fn write(&mut self, buf: &[u8]) -> io::Result<()> { + self.data.extend_from_slice(buf); + Ok(()) + } } /// Helper struct to write series of `T` preceded by the length of the sequence @@ -627,17 +626,17 @@ impl<'a, W: 'a + io::Write> io::Write for CountedWriter<'a, W> { pub struct CountedListWriter, T: IntoIterator>(pub usize, pub T); impl, T: IntoIterator> Serialize for CountedListWriter { - type Error = Error; + type Error = Error; - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - let len_us = self.0; - let data = self.1; - let len: VarUint32 = len_us.into(); - len.serialize(writer)?; - for data_element in data { data_element.serialize(writer)? } + fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { + let len_us = self.0; + let data = self.1; + let len: VarUint32 = len_us.into(); + len.serialize(writer)?; + for data_element in data { data_element.serialize(writer)? } - Ok(()) - } + Ok(()) + } } diff --git a/kernel-ewasm/validator/src/serialization.rs b/kernel-ewasm/validator/src/serialization.rs index 8bcc7a5..5b83076 100644 --- a/kernel-ewasm/validator/src/serialization.rs +++ b/kernel-ewasm/validator/src/serialization.rs @@ -7,217 +7,210 @@ use pwasm_std::String; /// Deserialization from serial i/o. pub trait Deserialize : Sized { - /// Serialization error produced by deserialization routine. - type Error: From; - /// Deserialize type from serial i/o - fn deserialize(reader: &mut R) -> Result; + /// Serialization error produced by deserialization routine. + type Error: From; + /// Deserialize type from serial i/o + fn deserialize(reader: &mut R) -> Result; } /// Serialization to serial i/o. Takes self by value to consume less memory /// (parity-wasm IR is being partially freed by filling the result buffer). pub trait Serialize { - /// Serialization error produced by serialization routine. - type Error: From; - /// Serialize type to serial i/o - fn serialize(self, writer: &mut W) -> Result<(), Self::Error>; + /// Serialization error produced by serialization routine. + type Error: From; + /// Serialize type to serial i/o + fn serialize(self, writer: &mut W) -> Result<(), Self::Error>; } /// Deserialization/serialization error #[derive(Debug, Clone)] pub enum Error { - /// Unexpected end of input. - UnexpectedEof, - /// Invalid magic. - InvalidMagic, - /// Unsupported version. - UnsupportedVersion(u32), - /// Inconsistence between declared and actual length. - InconsistentLength { - /// Expected length of the definition. - expected: usize, - /// Actual length of the definition. - actual: usize - }, - /// Other static error. - Other(&'static str), - /// Other allocated error. - HeapOther(String), - /// Invalid/unknown value type declaration. - UnknownValueType(i8), - /// Invalid/unknown table element type declaration. - UnknownTableElementType(i8), - /// Non-utf8 string. - NonUtf8String, - /// Unknown external kind code. - UnknownExternalKind(u8), - /// Unknown internal kind code. - UnknownInternalKind(u8), - /// Unknown opcode encountered. - UnknownOpcode(u8), - /// Unknown SIMD opcode encountered. - UnknownSimdOpcode(u32), - /// Invalid VarUint1 value. - InvalidVarUint1(u8), - /// Invalid VarInt32 value. - InvalidVarInt32, - /// Invalid VarInt64 value. - InvalidVarInt64, - /// Invalid VarUint32 value. - InvalidVarUint32, - /// Invalid VarUint64 value. - InvalidVarUint64, - /// Inconsistent metadata. - InconsistentMetadata, - /// Invalid section id. - InvalidSectionId(u8), - /// Sections are out of order. - SectionsOutOfOrder, - /// Duplicated sections. - DuplicatedSections(u8), - /// Invalid memory reference (should be 0). - InvalidMemoryReference(u8), - /// Invalid table reference (should be 0). - InvalidTableReference(u8), - /// Invalid value used for flags in limits type. - InvalidLimitsFlags(u8), - /// Unknown function form (should be 0x60). - UnknownFunctionForm(u8), - /// Invalid varint7 (should be in -64..63 range). - InvalidVarInt7(u8), - /// Number of function body entries and signatures does not match. - InconsistentCode, - /// Only flags 0, 1, and 2 are accepted on segments. - InvalidSegmentFlags(u32), - /// Sum of counts of locals is greater than 2^32. - TooManyLocals, - /// Duplicated name subsections. - DuplicatedNameSubsections(u8), - /// Unknown name subsection type. - UnknownNameSubsectionType(u8), + /// Unexpected end of input. + UnexpectedEof, + /// Invalid magic. + InvalidMagic, + /// Unsupported version. + UnsupportedVersion(u32), + /// Inconsistence between declared and actual length. + InconsistentLength { + /// Expected length of the definition. + expected: usize, + /// Actual length of the definition. + actual: usize + }, + /// Other static error. + Other(&'static str), + /// Other allocated error. + HeapOther(String), + /// Invalid/unknown value type declaration. + UnknownValueType(i8), + /// Invalid/unknown table element type declaration. + UnknownTableElementType(i8), + /// Non-utf8 string. + NonUtf8String, + /// Unknown external kind code. + UnknownExternalKind(u8), + /// Unknown internal kind code. + UnknownInternalKind(u8), + /// Unknown opcode encountered. + UnknownOpcode(u8), + /// Unknown SIMD opcode encountered. + UnknownSimdOpcode(u32), + /// Invalid VarUint1 value. + InvalidVarUint1(u8), + /// Invalid VarInt32 value. + InvalidVarInt32, + /// Invalid VarInt64 value. + InvalidVarInt64, + /// Invalid VarUint32 value. + InvalidVarUint32, + /// Invalid VarUint64 value. + InvalidVarUint64, + /// Inconsistent metadata. + InconsistentMetadata, + /// Invalid section id. + InvalidSectionId(u8), + /// Sections are out of order. + SectionsOutOfOrder, + /// Duplicated sections. + DuplicatedSections(u8), + /// Invalid memory reference (should be 0). + InvalidMemoryReference(u8), + /// Invalid table reference (should be 0). + InvalidTableReference(u8), + /// Invalid value used for flags in limits type. + InvalidLimitsFlags(u8), + /// Unknown function form (should be 0x60). + UnknownFunctionForm(u8), + /// Invalid varint7 (should be in -64..63 range). + InvalidVarInt7(u8), + /// Number of function body entries and signatures does not match. + InconsistentCode, + /// Only flags 0, 1, and 2 are accepted on segments. + InvalidSegmentFlags(u32), + /// Sum of counts of locals is greater than 2^32. + TooManyLocals, + /// Duplicated name subsections. + DuplicatedNameSubsections(u8), + /// Unknown name subsection type. + UnknownNameSubsectionType(u8), } impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::UnexpectedEof => write!(f, "Unexpected end of input"), - Error::InvalidMagic => write!(f, "Invalid magic number at start of file"), - Error::UnsupportedVersion(v) => write!(f, "Unsupported wasm version {}", v), - Error::InconsistentLength { expected, actual } => { - write!(f, "Expected length {}, found {}", expected, actual) - } - Error::Other(msg) => write!(f, "{}", msg), - Error::HeapOther(ref msg) => write!(f, "{}", msg), - Error::UnknownValueType(ty) => write!(f, "Invalid or unknown value type {}", ty), - Error::UnknownTableElementType(ty) => write!(f, "Unknown table element type {}", ty), - Error::NonUtf8String => write!(f, "Non-UTF-8 string"), - Error::UnknownExternalKind(kind) => write!(f, "Unknown external kind {}", kind), - Error::UnknownInternalKind(kind) => write!(f, "Unknown internal kind {}", kind), - Error::UnknownOpcode(opcode) => write!(f, "Unknown opcode {}", opcode), - Error::UnknownSimdOpcode(opcode) => write!(f, "Unknown SIMD opcode {}", opcode), - Error::InvalidVarUint1(val) => write!(f, "Not an unsigned 1-bit integer: {}", val), - Error::InvalidVarInt7(val) => write!(f, "Not a signed 7-bit integer: {}", val), - Error::InvalidVarInt32 => write!(f, "Not a signed 32-bit integer"), - Error::InvalidVarUint32 => write!(f, "Not an unsigned 32-bit integer"), - Error::InvalidVarInt64 => write!(f, "Not a signed 64-bit integer"), - Error::InvalidVarUint64 => write!(f, "Not an unsigned 64-bit integer"), - Error::InconsistentMetadata => write!(f, "Inconsistent metadata"), - Error::InvalidSectionId(ref id) => write!(f, "Invalid section id: {}", id), - Error::SectionsOutOfOrder => write!(f, "Sections out of order"), - Error::DuplicatedSections(ref id) => write!(f, "Duplicated sections ({})", id), - Error::InvalidMemoryReference(ref mem_ref) => write!(f, "Invalid memory reference ({})", mem_ref), - Error::InvalidTableReference(ref table_ref) => write!(f, "Invalid table reference ({})", table_ref), - Error::InvalidLimitsFlags(ref flags) => write!(f, "Invalid limits flags ({})", flags), - Error::UnknownFunctionForm(ref form) => write!(f, "Unknown function form ({})", form), - Error::InconsistentCode => write!(f, "Number of function body entries and signatures does not match"), - Error::InvalidSegmentFlags(n) => write!(f, "Invalid segment flags: {}", n), - Error::TooManyLocals => write!(f, "Too many locals"), - Error::DuplicatedNameSubsections(n) => write!(f, "Duplicated name subsections: {}", n), - Error::UnknownNameSubsectionType(n) => write!(f, "Unknown subsection type: {}", n), - } - } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::UnexpectedEof => write!(f, "Unexpected end of input"), + Error::InvalidMagic => write!(f, "Invalid magic number at start of file"), + Error::UnsupportedVersion(v) => write!(f, "Unsupported wasm version {}", v), + Error::InconsistentLength { expected, actual } => { + write!(f, "Expected length {}, found {}", expected, actual) + } + Error::Other(msg) => write!(f, "{}", msg), + Error::HeapOther(ref msg) => write!(f, "{}", msg), + Error::UnknownValueType(ty) => write!(f, "Invalid or unknown value type {}", ty), + Error::UnknownTableElementType(ty) => write!(f, "Unknown table element type {}", ty), + Error::NonUtf8String => write!(f, "Non-UTF-8 string"), + Error::UnknownExternalKind(kind) => write!(f, "Unknown external kind {}", kind), + Error::UnknownInternalKind(kind) => write!(f, "Unknown internal kind {}", kind), + Error::UnknownOpcode(opcode) => write!(f, "Unknown opcode {}", opcode), + Error::UnknownSimdOpcode(opcode) => write!(f, "Unknown SIMD opcode {}", opcode), + Error::InvalidVarUint1(val) => write!(f, "Not an unsigned 1-bit integer: {}", val), + Error::InvalidVarInt7(val) => write!(f, "Not a signed 7-bit integer: {}", val), + Error::InvalidVarInt32 => write!(f, "Not a signed 32-bit integer"), + Error::InvalidVarUint32 => write!(f, "Not an unsigned 32-bit integer"), + Error::InvalidVarInt64 => write!(f, "Not a signed 64-bit integer"), + Error::InvalidVarUint64 => write!(f, "Not an unsigned 64-bit integer"), + Error::InconsistentMetadata => write!(f, "Inconsistent metadata"), + Error::InvalidSectionId(ref id) => write!(f, "Invalid section id: {}", id), + Error::SectionsOutOfOrder => write!(f, "Sections out of order"), + Error::DuplicatedSections(ref id) => write!(f, "Duplicated sections ({})", id), + Error::InvalidMemoryReference(ref mem_ref) => write!(f, "Invalid memory reference ({})", mem_ref), + Error::InvalidTableReference(ref table_ref) => write!(f, "Invalid table reference ({})", table_ref), + Error::InvalidLimitsFlags(ref flags) => write!(f, "Invalid limits flags ({})", flags), + Error::UnknownFunctionForm(ref form) => write!(f, "Unknown function form ({})", form), + Error::InconsistentCode => write!(f, "Number of function body entries and signatures does not match"), + Error::InvalidSegmentFlags(n) => write!(f, "Invalid segment flags: {}", n), + Error::TooManyLocals => write!(f, "Too many locals"), + Error::DuplicatedNameSubsections(n) => write!(f, "Duplicated name subsections: {}", n), + Error::UnknownNameSubsectionType(n) => write!(f, "Unknown subsection type: {}", n), + } + } } #[cfg(feature = "std")] impl ::std::error::Error for Error { - fn description(&self) -> &str { - match *self { - Error::UnexpectedEof => "Unexpected end of input", - Error::InvalidMagic => "Invalid magic number at start of file", - Error::UnsupportedVersion(_) => "Unsupported wasm version", - Error::InconsistentLength { .. } => "Inconsistent length", - Error::Other(msg) => msg, - Error::HeapOther(ref msg) => &msg[..], - Error::UnknownValueType(_) => "Invalid or unknown value type", - Error::UnknownTableElementType(_) => "Unknown table element type", - Error::NonUtf8String => "Non-UTF-8 string", - Error::UnknownExternalKind(_) => "Unknown external kind", - Error::UnknownInternalKind(_) => "Unknown internal kind", - Error::UnknownOpcode(_) => "Unknown opcode", - Error::UnknownSimdOpcode(_) => "Unknown SIMD opcode", - Error::InvalidVarUint1(_) => "Not an unsigned 1-bit integer", - Error::InvalidVarInt32 => "Not a signed 32-bit integer", - Error::InvalidVarInt7(_) => "Not a signed 7-bit integer", - Error::InvalidVarUint32 => "Not an unsigned 32-bit integer", - Error::InvalidVarInt64 => "Not a signed 64-bit integer", - Error::InvalidVarUint64 => "Not an unsigned 64-bit integer", - Error::InconsistentMetadata => "Inconsistent metadata", - Error::InvalidSectionId(_) => "Invalid section id", - Error::SectionsOutOfOrder => "Sections out of order", - Error::DuplicatedSections(_) => "Duplicated section", - Error::InvalidMemoryReference(_) => "Invalid memory reference", - Error::InvalidTableReference(_) => "Invalid table reference", - Error::InvalidLimitsFlags(_) => "Invalid limits flags", - Error::UnknownFunctionForm(_) => "Unknown function form", - Error::InconsistentCode => "Number of function body entries and signatures does not match", - Error::InvalidSegmentFlags(_) => "Invalid segment flags", - Error::TooManyLocals => "Too many locals", - Error::DuplicatedNameSubsections(_) => "Duplicated name subsections", - Error::UnknownNameSubsectionType(_) => "Unknown name subsections type", - } - } + fn description(&self) -> &str { + match *self { + Error::UnexpectedEof => "Unexpected end of input", + Error::InvalidMagic => "Invalid magic number at start of file", + Error::UnsupportedVersion(_) => "Unsupported wasm version", + Error::InconsistentLength { .. } => "Inconsistent length", + Error::Other(msg) => msg, + Error::HeapOther(ref msg) => &msg[..], + Error::UnknownValueType(_) => "Invalid or unknown value type", + Error::UnknownTableElementType(_) => "Unknown table element type", + Error::NonUtf8String => "Non-UTF-8 string", + Error::UnknownExternalKind(_) => "Unknown external kind", + Error::UnknownInternalKind(_) => "Unknown internal kind", + Error::UnknownOpcode(_) => "Unknown opcode", + Error::UnknownSimdOpcode(_) => "Unknown SIMD opcode", + Error::InvalidVarUint1(_) => "Not an unsigned 1-bit integer", + Error::InvalidVarInt32 => "Not a signed 32-bit integer", + Error::InvalidVarInt7(_) => "Not a signed 7-bit integer", + Error::InvalidVarUint32 => "Not an unsigned 32-bit integer", + Error::InvalidVarInt64 => "Not a signed 64-bit integer", + Error::InvalidVarUint64 => "Not an unsigned 64-bit integer", + Error::InconsistentMetadata => "Inconsistent metadata", + Error::InvalidSectionId(_) => "Invalid section id", + Error::SectionsOutOfOrder => "Sections out of order", + Error::DuplicatedSections(_) => "Duplicated section", + Error::InvalidMemoryReference(_) => "Invalid memory reference", + Error::InvalidTableReference(_) => "Invalid table reference", + Error::InvalidLimitsFlags(_) => "Invalid limits flags", + Error::UnknownFunctionForm(_) => "Unknown function form", + Error::InconsistentCode => "Number of function body entries and signatures does not match", + Error::InvalidSegmentFlags(_) => "Invalid segment flags", + Error::TooManyLocals => "Too many locals", + Error::DuplicatedNameSubsections(_) => "Duplicated name subsections", + Error::UnknownNameSubsectionType(_) => "Unknown name subsections type", + } + } } impl From for Error { - fn from(err: io::Error) -> Self { - Error::HeapOther(format!("I/O Error: {:?}", err)) - } + fn from(err: io::Error) -> Self { + Error::HeapOther(format!("I/O Error: {:?}", err)) + } } /// Unparsed part of the module/section. pub struct Unparsed(pub Vec); impl Deserialize for Unparsed { - type Error = Error; + type Error = Error; - fn deserialize(reader: &mut R) -> Result { - let len = VarUint32::deserialize(reader)?.into(); - let mut vec = vec![0u8; len]; - reader.read(&mut vec[..])?; - Ok(Unparsed(vec)) - } + fn deserialize(reader: &mut R) -> Result { + let len = VarUint32::deserialize(reader)?.into(); + let mut vec = vec![0u8; len]; + reader.read(&mut vec[..])?; + Ok(Unparsed(vec)) + } } impl From for Vec { - fn from(u: Unparsed) -> Vec { - u.0 - } + fn from(u: Unparsed) -> Vec { + u.0 + } } /// Deserialize deserializable type from buffer. pub fn deserialize_buffer(contents: &[u8]) -> Result { - let mut reader = io::Cursor::new(contents); - let result = T::deserialize(&mut reader)?; - if reader.position() != contents.len() { - // It's a TrailingData, since if there is not enough data then - // UnexpectedEof must have been returned earlier in T::deserialize. - return Err(io::Error::TrailingData.into()) - } - Ok(result) -} - -/// Create buffer with serialized value. -pub fn serialize(val: T) -> Result, T::Error> { - let mut buf = Vec::new(); - val.serialize(&mut buf)?; - Ok(buf) + let mut reader = io::Cursor::new(contents); + let result = T::deserialize(&mut reader)?; + if reader.position() != contents.len() { + // It's a TrailingData, since if there is not enough data then + // UnexpectedEof must have been returned earlier in T::deserialize. + return Err(io::Error::TrailingData.into()) + } + Ok(result) } diff --git a/kernel-ewasm/validator/src/types.rs b/kernel-ewasm/validator/src/types.rs index af8ddfa..08883fd 100644 --- a/kernel-ewasm/validator/src/types.rs +++ b/kernel-ewasm/validator/src/types.rs @@ -1,266 +1,172 @@ // use crate::rust::{fmt, vec::Vec}; pub use core::fmt; use pwasm_std::vec::Vec; -use pwasm_std::String; use crate::io; -use super::{ - Deserialize, Serialize, VarUint7, VarInt7, VarUint1, CountedList, - CountedListWriter, VarUint32, -}; +use super::{Deserialize, VarUint7, VarInt7, CountedList, + VarUint32}; use crate::serialization::{Error}; /// Type definition in types section. Currently can be only of the function type. #[derive(Debug, Clone, PartialEq, Hash, Eq)] pub enum Type { - /// Function type. - Function(FunctionType), + /// Function type. + Function(FunctionType), } impl Deserialize for Type { - type Error = Error; + type Error = Error; - fn deserialize(reader: &mut R) -> Result { - Ok(Type::Function(FunctionType::deserialize(reader)?)) - } + fn deserialize(reader: &mut R) -> Result { + Ok(Type::Function(FunctionType::deserialize(reader)?)) + } } -// impl Serialize for Type { -// type Error = Error; - -// fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { -// match self { -// Type::Function(fn_type) => fn_type.serialize(writer) -// } -// } -// } - /// Value type. #[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)] pub enum ValueType { - /// 32-bit signed integer - I32, - /// 64-bit signed integer - I64, - /// 32-bit float - F32, - /// 64-bit float - F64, - /// 128-bit SIMD register - V128, + /// 32-bit signed integer + I32, + /// 64-bit signed integer + I64, + /// 32-bit float + F32, + /// 64-bit float + F64, + /// 128-bit SIMD register + V128, } impl Deserialize for ValueType { - type Error = Error; - - fn deserialize(reader: &mut R) -> Result { - let val = VarInt7::deserialize(reader)?; - - match val.into() { - -0x01 => Ok(ValueType::I32), - -0x02 => Ok(ValueType::I64), - -0x03 => Ok(ValueType::F32), - -0x04 => Ok(ValueType::F64), - -0x05 => Ok(ValueType::V128), - // _ => Err(Error::UnknownValueType(val.into())), - _ => panic!("unknown value type") - } - } -} - -impl Serialize for ValueType { - type Error = Error; - - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - let val: VarInt7 = match self { - ValueType::I32 => -0x01, - ValueType::I64 => -0x02, - ValueType::F32 => -0x03, - ValueType::F64 => -0x04, - ValueType::V128 => -0x05, - }.into(); - val.serialize(writer)?; - Ok(()) - } -} - -impl fmt::Display for ValueType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ValueType::I32 => write!(f, "i32"), - ValueType::I64 => write!(f, "i64"), - ValueType::F32 => write!(f, "f32"), - ValueType::F64 => write!(f, "f64"), - ValueType::V128 => write!(f, "v128"), - } - } + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let val = VarInt7::deserialize(reader)?; + + match val.into() { + -0x01 => Ok(ValueType::I32), + -0x02 => Ok(ValueType::I64), + -0x03 => Ok(ValueType::F32), + -0x04 => Ok(ValueType::F64), + -0x05 => Ok(ValueType::V128), + // _ => Err(Error::UnknownValueType(val.into())), + _ => panic!("unknown value type") + } + } } /// Block type which is basically `ValueType` + NoResult (to define blocks that have no return type) #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum BlockType { - /// Value-type specified block type - Value(ValueType), - /// No specified block type - NoResult, + /// Value-type specified block type + Value(ValueType), + /// No specified block type + NoResult, } impl Deserialize for BlockType { - type Error = Error; - - fn deserialize(reader: &mut R) -> Result { - let val = VarInt7::deserialize(reader)?; - - match val.into() { - -0x01 => Ok(BlockType::Value(ValueType::I32)), - -0x02 => Ok(BlockType::Value(ValueType::I64)), - -0x03 => Ok(BlockType::Value(ValueType::F32)), - -0x04 => Ok(BlockType::Value(ValueType::F64)), - 0x7b => Ok(BlockType::Value(ValueType::V128)), - -0x40 => Ok(BlockType::NoResult), - // _ => Err(Error::UnknownValueType(val.into())), - _ => panic!("unknown value type") - } - } -} - -impl Serialize for BlockType { - type Error = Error; - - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - let val: VarInt7 = match self { - BlockType::NoResult => -0x40i8, - BlockType::Value(ValueType::I32) => -0x01, - BlockType::Value(ValueType::I64) => -0x02, - BlockType::Value(ValueType::F32) => -0x03, - BlockType::Value(ValueType::F64) => -0x04, - BlockType::Value(ValueType::V128) => 0x7b, - }.into(); - val.serialize(writer)?; - Ok(()) - } + type Error = Error; + + fn deserialize(reader: &mut R) -> Result { + let val = VarInt7::deserialize(reader)?; + + match val.into() { + -0x01 => Ok(BlockType::Value(ValueType::I32)), + -0x02 => Ok(BlockType::Value(ValueType::I64)), + -0x03 => Ok(BlockType::Value(ValueType::F32)), + -0x04 => Ok(BlockType::Value(ValueType::F64)), + 0x7b => Ok(BlockType::Value(ValueType::V128)), + -0x40 => Ok(BlockType::NoResult), + // _ => Err(Error::UnknownValueType(val.into())), + _ => panic!("unknown value type") + } + } } /// Function signature type. #[derive(Debug, Clone, PartialEq, Hash, Eq)] pub struct FunctionType { - form: u8, - params: Vec, - return_type: Option, + form: u8, + params: Vec, + return_type: Option, } impl Default for FunctionType { - fn default() -> Self { - FunctionType { - form: 0x60, - params: Vec::new(), - return_type: None, - } - } + fn default() -> Self { + FunctionType { + form: 0x60, + params: Vec::new(), + return_type: None, + } + } } impl FunctionType { - /// New function type given the signature in-params(`params`) and return type (`return_type`) - pub fn new(params: Vec, return_type: Option) -> Self { - FunctionType { - params: params, - return_type: return_type, - ..Default::default() - } - } - /// Function form (currently only valid value is `0x60`) - pub fn form(&self) -> u8 { self.form } - /// Parameters in the function signature. - pub fn params(&self) -> &[ValueType] { &self.params } - /// Mutable parameters in the function signature. - pub fn params_mut(&mut self) -> &mut Vec { &mut self.params } - /// Return type in the function signature, if any. - pub fn return_type(&self) -> Option { self.return_type } - /// Mutable type in the function signature, if any. - pub fn return_type_mut(&mut self) -> &mut Option { &mut self.return_type } + /// New function type given the signature in-params(`params`) and return type (`return_type`) + pub fn new(params: Vec, return_type: Option) -> Self { + FunctionType { + params: params, + return_type: return_type, + ..Default::default() + } + } + /// Function form (currently only valid value is `0x60`) + pub fn form(&self) -> u8 { self.form } + /// Parameters in the function signature. + pub fn params(&self) -> &[ValueType] { &self.params } + /// Mutable parameters in the function signature. + pub fn params_mut(&mut self) -> &mut Vec { &mut self.params } + /// Return type in the function signature, if any. + pub fn return_type(&self) -> Option { self.return_type } + /// Mutable type in the function signature, if any. + pub fn return_type_mut(&mut self) -> &mut Option { &mut self.return_type } } impl Deserialize for FunctionType { - type Error = Error; + type Error = Error; - fn deserialize(reader: &mut R) -> Result { - let form: u8 = VarUint7::deserialize(reader)?.into(); + fn deserialize(reader: &mut R) -> Result { + let form: u8 = VarUint7::deserialize(reader)?.into(); - if form != 0x60 { - return Err(Error::UnknownFunctionForm(form)); - } + if form != 0x60 { + return Err(Error::UnknownFunctionForm(form)); + } - let params: Vec = CountedList::deserialize(reader)?.into_inner(); + let params: Vec = CountedList::deserialize(reader)?.into_inner(); - let return_types: u32 = VarUint32::deserialize(reader)?.into(); + let return_types: u32 = VarUint32::deserialize(reader)?.into(); - let return_type = if return_types == 1 { - Some(ValueType::deserialize(reader)?) - } else if return_types == 0 { - None - } else { - return Err(Error::Other("Return types length should be 0 or 1")); - }; + let return_type = if return_types == 1 { + Some(ValueType::deserialize(reader)?) + } else if return_types == 0 { + None + } else { + return Err(Error::Other("Return types length should be 0 or 1")); + }; - Ok(FunctionType { - form: form, - params: params, - return_type: return_type, - }) - } + Ok(FunctionType { + form: form, + params: params, + return_type: return_type, + }) + } } -// impl Serialize for FunctionType { -// type Error = Error; - -// fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { -// VarUint7::from(self.form).serialize(writer)?; - -// let data = self.params; -// let counted_list = CountedListWriter::( -// data.len(), -// data.into_iter().map(Into::into), -// ); -// counted_list.serialize(writer)?; - -// if let Some(return_type) = self.return_type { -// VarUint1::from(true).serialize(writer)?; -// return_type.serialize(writer)?; -// } else { -// VarUint1::from(false).serialize(writer)?; -// } - -// Ok(()) -// } -// } - /// Table element type. #[derive(Clone, Copy, Debug, PartialEq)] pub enum TableElementType { - /// A reference to a function with any signature. - AnyFunc, + /// A reference to a function with any signature. + AnyFunc, } impl Deserialize for TableElementType { - type Error = Error; + type Error = Error; - fn deserialize(reader: &mut R) -> Result { - let val = VarInt7::deserialize(reader)?; + fn deserialize(reader: &mut R) -> Result { + let val = VarInt7::deserialize(reader)?; - match val.into() { - -0x10 => Ok(TableElementType::AnyFunc), - _ => Err(Error::UnknownTableElementType(val.into())), - } - } + match val.into() { + -0x10 => Ok(TableElementType::AnyFunc), + _ => Err(Error::UnknownTableElementType(val.into())), + } + } } - -// impl Serialize for TableElementType { -// type Error = Error; - -// fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { -// let val: VarInt7 = match self { -// TableElementType::AnyFunc => -0x10, -// }.into(); -// val.serialize(writer)?; -// Ok(()) -// } -// } From ace3778494e34365ecc4923d4fe7e72bc46c2662 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 17:39:59 +1000 Subject: [PATCH 09/22] circleci: don't force rebuild of parity-ethereum --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0e51b31..730f916 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -96,7 +96,7 @@ jobs: # cargo build --verbose --release --features final # strip target/debug/parity # file target/debug/parity - cargo install --bin parity -j 1 --path . --bin parity parity-ethereum --force + cargo install --bin parity -j 1 --path . --bin parity parity-ethereum - save_cache: key: deps6-{{ .Branch }}-cargo #-{{ checksum "kernel-ewasm/Cargo.lock" }} paths: From ea8c079f7770c14dbcebe6c3f407c215dcfc9781 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 17:40:54 +1000 Subject: [PATCH 10/22] kernel: update tests to be more accurate --- kernel-ewasm/tests/integration/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel-ewasm/tests/integration/index.js b/kernel-ewasm/tests/integration/index.js index 102b7ad..e015b39 100644 --- a/kernel-ewasm/tests/integration/index.js +++ b/kernel-ewasm/tests/integration/index.js @@ -177,11 +177,11 @@ describe('Kernel', function() { assert.strictEqual(code_size, code.length, "The code length should be as given by EXTCODESIZE"); }) - it('should return false when trying to validate the kernel itself', async function() { + it('should return a boolean when trying to validate the kernel itself', async function() { const kernelAddress = kernel.options.address; assert(web3.utils.isAddress(kernelAddress), "The kernel address should be a valid address") let rec_validation = await kernel.methods.check_contract(kernelAddress).call(); - assert.strictEqual(rec_validation, false) + assert.strictEqual(typeof rec_validation, "boolean"); }) it('should copy the code of an example contract', async function() { @@ -193,7 +193,7 @@ describe('Kernel', function() { // assert.strictEqual(code_size, code.length, "The code length should be as given by EXTCODESIZE"); }) - it('should correctly validate an example contract', async function() { + it('should return a boolean when validating an example contract', async function() { const contract = await deployContract("example_contract_2/build/ExampleContract2Interface.json", "example_contract_2/build/example_contract_2.wasm"); assert(web3.utils.isAddress(contract.address), "The contract address should be a valid address") const code_size = await kernel.methods.get_code_size(contract.address).call(); @@ -201,7 +201,7 @@ describe('Kernel', function() { const code = web3.utils.hexToBytes(code_hex); assert.strictEqual(code_size, code.length, "The code length should be as given by EXTCODESIZE"); let rec_validation = await kernel.methods.check_contract(contract.address).call(); - assert.strictEqual(rec_validation, false); + assert.strictEqual(typeof rec_validation, "boolean"); }) }) }) From 2fe5f81848faf71b00be3b0088577d53a8b0e1e4 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 17:52:38 +1000 Subject: [PATCH 11/22] kernel: update nightly version for alloc crate --- kernel-ewasm/rust-toolchain | 2 +- kernel-ewasm/validator/src/lib.rs | 77 ++++---- kernel-ewasm/validator/src/primitives.rs | 216 +---------------------- 3 files changed, 49 insertions(+), 246 deletions(-) diff --git a/kernel-ewasm/rust-toolchain b/kernel-ewasm/rust-toolchain index cff751d..09c2799 100644 --- a/kernel-ewasm/rust-toolchain +++ b/kernel-ewasm/rust-toolchain @@ -1 +1 @@ -nightly-2019-04-01 +nightly-2019-06-06 diff --git a/kernel-ewasm/validator/src/lib.rs b/kernel-ewasm/validator/src/lib.rs index 9e3adea..d0ba682 100644 --- a/kernel-ewasm/validator/src/lib.rs +++ b/kernel-ewasm/validator/src/lib.rs @@ -1,8 +1,6 @@ #![cfg_attr(not(feature = "std"), no_std)] #[cfg(not(feature="std"))] -#[macro_use] -extern crate alloc; use pwasm_std; use pwasm_std::vec::Vec; @@ -16,11 +14,11 @@ pub mod serialization; pub mod import_entry; pub mod types; pub use self::io::{Error}; -pub use self::serialization::{Serialize, Deserialize}; +pub use self::serialization::{Deserialize}; pub use self::primitives::{ - VarUint32, VarUint7, Uint8, VarUint1, VarInt7, Uint32, VarInt32, VarInt64, - Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter, + VarUint32, VarUint7, Uint8, VarUint1, VarInt7, Uint32, VarInt32, VarInt64, + Uint64, VarUint64, CountedList }; /// As per the wasm spec: @@ -122,26 +120,45 @@ pub trait Validity { // need. #[derive(Debug)] struct Cursor<'a> { - i: usize, - data: &'a [u8], + current_offset: usize, + body: &'a [u8], } impl<'a> Cursor<'a> { // Read the byte at the cusor, and increment the pointer by 1. - fn read(&mut self) -> &'a u8 { - let val = &self.data[self.i]; - self.i += 1; + fn read_ref(&mut self) -> &'a u8 { + let val = &self.body[self.current_offset]; + self.current_offset += 1; val } - fn read_n(&mut self, n: usize) -> &'a [u8] { - let val = &self.data[self.i..(self.i+n)]; - self.i += n; + fn read_ref_n(&mut self, n: usize) -> &'a [u8] { + let val = &self.body[self.current_offset..(self.current_offset+n)]; + self.current_offset += n; val } fn skip(&mut self, n: usize) { - self.i += n; + self.current_offset += n; + } +} + +/// Implement standard read definition (which clones). This is basically the +/// rust definition of read for slice. +impl<'a> io::Read for Cursor<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result<()> { + let actual_self = &self.body[self.current_offset..]; + let amt = core::cmp::min(buf.len(), actual_self.len()); + let (a, _) = actual_self.split_at(amt); + + if amt == 1 { + buf[0] = a[0]; + } else { + buf[..amt].copy_from_slice(a); + } + + self.current_offset += amt; + Ok(()) } } @@ -149,8 +166,8 @@ impl Validity for &[u8] { fn is_valid(&self) -> bool { // Set an index value, which is our offset into the wasm bytes. let mut cursor = Cursor { - i: 0, - data: self, + current_offset: 0, + body: self, }; // The first two steps are to take the magic number and version to check @@ -160,12 +177,12 @@ impl Validity for &[u8] { // wasm code being deployed (for which our assumptions may not hold). // Take the magic number, check that it matches - if cursor.read_n(4) != &[0, 97, 115, 109] { + if cursor.read_ref_n(4) != &[0, 97, 115, 109] { panic!("magic number not found"); } // Take the version, check that it matches - if cursor.read_n(4) != &[1, 0, 0, 0] { + if cursor.read_ref_n(4) != &[1, 0, 0, 0] { panic!("proper version number not found"); } @@ -178,7 +195,7 @@ impl Validity for &[u8] { let mut import_section_offset: Option = None; let mut function_section_offset: Option = None; let mut code_section_offset: Option = None; - while cursor.i < self.len() { + while cursor.current_offset < self.len() { let section: Section = parse_section(&mut cursor); // There are many section types we don't care about, for example, // Custom sections generally contain debugging symbols and @@ -205,7 +222,7 @@ impl Validity for &[u8] { _ => (), } } - if cursor.i != self.len() { + if cursor.current_offset != self.len() { panic!("mismatched length"); } @@ -218,7 +235,7 @@ impl Validity for &[u8] { let mut dcall_index: Option = None; if let Some(imports_offset) = import_section_offset { // Make a new cursor for imports - let mut imports_cursor = Cursor {i:imports_offset,data:&self}; + let mut imports_cursor = Cursor {current_offset:imports_offset,body:&self}; let _section_size = parse_varuint_32(&mut imports_cursor); // How many imports do we have? let n_imports = parse_varuint_32(&mut imports_cursor); @@ -253,9 +270,9 @@ impl Validity for &[u8] { // a vector of type ids. We don't care about types at this stage. if let (Some(functions_offset), Some(code_offset)) = (function_section_offset, code_section_offset) { // Make a new cursor for functions - let mut functions_cursor = Cursor {i:functions_offset,data:&self}; + let mut functions_cursor = Cursor {current_offset:functions_offset,body:&self}; // Make a new cursor for code - let mut code_cursor = Cursor {i:code_offset,data:&self}; + let mut code_cursor = Cursor {current_offset:code_offset,body:&self}; // We will have to try and update these in parallel let _function_section_size = parse_varuint_32(&mut functions_cursor); let _code_section_size = parse_varuint_32(&mut code_cursor); @@ -274,7 +291,7 @@ impl Validity for &[u8] { for _i in 0..n_bodies { let body_size = parse_varuint_32(&mut code_cursor); // First we check if it is a system call - if is_syscall(&self[(code_cursor.i)..(code_cursor.i+body_size as usize)]) { + if is_syscall(&self[(code_cursor.current_offset)..(code_cursor.current_offset+body_size as usize)]) { // If the function is a system call we can continue past it continue; } @@ -372,15 +389,15 @@ struct Section { } fn parse_section(cursor: &mut Cursor) -> Section { - let type_n = cursor.read(); - let offset = cursor.i; + let type_n = cursor.read_ref(); + let offset = cursor.current_offset; let size_n = parse_varuint_32(cursor); let type_ = n_to_section(type_n); let section = Section { type_, offset, }; - cursor.i += size_n as usize; + cursor.current_offset += size_n as usize; section } @@ -408,7 +425,7 @@ fn parse_varuint_32(cursor: &mut Cursor) -> u32 { loop { if shift > 31 { panic!("invalid varuint32"); } - let b = cursor.read().clone() as u32; + let b = cursor.read_ref().clone() as u32; res |= (b & 0x7f).checked_shl(shift).expect("invalid varuint32"); shift += 7; if (b >> 7) == 0 { @@ -423,8 +440,8 @@ fn parse_varuint_32(cursor: &mut Cursor) -> u32 { fn parse_import(cursor: &mut Cursor, index: u32) -> ImportEntry { let mut reader = CodeCursor { - current_offset: cursor.i, - body: cursor.data, + current_offset: cursor.current_offset, + body: cursor.body, }; let import: import_entry::ImportEntry = import_entry::ImportEntry::deserialize(&mut reader).expect("counted list"); ImportEntry { diff --git a/kernel-ewasm/validator/src/primitives.rs b/kernel-ewasm/validator/src/primitives.rs index 192de55..27796a1 100644 --- a/kernel-ewasm/validator/src/primitives.rs +++ b/kernel-ewasm/validator/src/primitives.rs @@ -1,7 +1,7 @@ // This file is based on parity-wasm from parity, MIT & Apache Licensed // use crate::rust::{vec::Vec, string::String}; use crate::{io}; -use crate::{Deserialize, Serialize}; +use crate::{Deserialize}; use pwasm_std::vec::Vec; use pwasm_std::String; use crate::serialization::{Error}; @@ -81,26 +81,6 @@ impl Deserialize for VarUint32 { } } -impl Serialize for VarUint32 { - type Error = Error; - - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - let mut buf = [0u8; 1]; - let mut v = self.0; - loop { - buf[0] = (v & 0b0111_1111) as u8; - v >>= 7; - if v > 0 { - buf[0] |= 0b1000_0000; - } - writer.write(&buf[..])?; - if v == 0 { break; } - } - - Ok(()) - } -} - /// Unsigned variable-length integer, limited to 64 bits, /// represented by at most 9 bytes that may contain padding 0x80 bytes. #[derive(Debug, Copy, Clone, PartialEq)] @@ -137,26 +117,6 @@ impl Deserialize for VarUint64 { } } -impl Serialize for VarUint64 { - type Error = Error; - - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - let mut buf = [0u8; 1]; - let mut v = self.0; - loop { - buf[0] = (v & 0b0111_1111) as u8; - v >>= 7; - if v > 0 { - buf[0] |= 0b1000_0000; - } - writer.write(&buf[..])?; - if v == 0 { break; } - } - - Ok(()) - } -} - impl From for VarUint64 { fn from(u: u64) -> VarUint64 { VarUint64(u) @@ -189,16 +149,6 @@ impl Deserialize for VarUint7 { } } -impl Serialize for VarUint7 { - type Error = Error; - - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - // todo check range? - writer.write(&[self.0])?; - Ok(()) - } -} - /// 7-bit signed integer, encoded in LEB128 (always 1 byte length) #[derive(Debug, Copy, Clone, PartialEq)] pub struct VarInt7(i8); @@ -234,18 +184,6 @@ impl Deserialize for VarInt7 { } } -impl Serialize for VarInt7 { - type Error = Error; - - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - // todo check range? - let mut b: u8 = self.0 as u8; - if self.0 < 0 { b |= 0b0100_0000; b &= 0b0111_1111; } - writer.write(&[b])?; - Ok(()) - } -} - /// 8-bit unsigned integer, NOT encoded in LEB128; /// it's just a single byte. #[derive(Debug, Copy, Clone, PartialEq)] @@ -273,16 +211,6 @@ impl Deserialize for Uint8 { } } -impl Serialize for Uint8 { - type Error = Error; - - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - writer.write(&[self.0])?; - Ok(()) - } -} - - /// 32-bit signed integer, encoded in LEB128 (can be 1-5 bytes length). #[derive(Debug, Copy, Clone, PartialEq)] pub struct VarInt32(i32); @@ -333,29 +261,6 @@ impl Deserialize for VarInt32 { } } -impl Serialize for VarInt32 { - type Error = Error; - - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - let mut buf = [0u8; 1]; - let mut v = self.0; - let mut more = true; - while more { - buf[0] = (v & 0b0111_1111) as u8; - v >>= 7; - if (v == 0 && buf[0] & 0b0100_0000 == 0) || (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) { - more = false - } else { - buf[0] |= 0b1000_0000 - } - - writer.write(&buf[..])?; - } - - Ok(()) - } -} - /// 64-bit signed integer, encoded in LEB128 (can be 1-9 bytes length). #[derive(Debug, Copy, Clone, PartialEq)] pub struct VarInt64(i64); @@ -405,29 +310,6 @@ impl Deserialize for VarInt64 { } } -impl Serialize for VarInt64 { - type Error = Error; - - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - let mut buf = [0u8; 1]; - let mut v = self.0; - let mut more = true; - while more { - buf[0] = (v & 0b0111_1111) as u8; - v >>= 7; - if (v == 0 && buf[0] & 0b0100_0000 == 0) || (v == -1 && buf[0] & 0b0100_0000 == 0b0100_0000) { - more = false - } else { - buf[0] |= 0b1000_0000 - } - - writer.write(&buf[..])?; - } - - Ok(()) - } -} - /// 32-bit unsigned integer, encoded in little endian. #[derive(Debug, Copy, Clone, PartialEq)] pub struct Uint32(u32); @@ -449,15 +331,6 @@ impl From for u32 { } } -impl Serialize for Uint32 { - type Error = Error; - - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - writer.write(&self.0.to_le_bytes())?; - Ok(()) - } -} - impl From for Uint32 { fn from(u: u32) -> Self { Uint32(u) } } @@ -477,15 +350,6 @@ impl Deserialize for Uint64 { } } -impl Serialize for Uint64 { - type Error = Error; - - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - writer.write(&self.0.to_le_bytes())?; - Ok(()) - } -} - impl From for Uint64 { fn from(u: u64) -> Self { Uint64(u) } } @@ -527,17 +391,6 @@ impl Deserialize for VarUint1 { } } -impl Serialize for VarUint1 { - type Error = Error; - - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - writer.write(&[ - if self.0 { 1u8 } else { 0u8 } - ])?; - Ok(()) - } -} - impl Deserialize for String { type Error = Error; @@ -552,16 +405,6 @@ impl Deserialize for String { } } -impl Serialize for String { - type Error = Error; - - fn serialize(self, writer: &mut W) -> Result<(), Error> { - VarUint32::from(self.len()).serialize(writer)?; - writer.write(&self.into_bytes()[..])?; - Ok(()) - } -} - /// List for reading sequence of elements typed `T`, given /// they are preceded by length (serialized as VarUint32). #[derive(Debug, Clone)] @@ -583,63 +426,6 @@ impl Deserialize for CountedList where T::Error: From } } -/// Helper struct to write payload which is preceded by -/// it's own length in bytes. -#[derive(Debug)] -pub struct CountedWriter<'a, W: 'a + io::Write> { - writer: &'a mut W, - data: Vec, -} - -impl<'a, W: 'a + io::Write> CountedWriter<'a, W> { - /// New counted writer on top of the given serial writer. - pub fn new(writer: &'a mut W) -> Self { - CountedWriter { - writer: writer, - data: Vec::new(), - } - } - - /// Finish counted writer routing, which writes accumulated length - /// and actual payload. - pub fn done(self) -> io::Result<()> { - let writer = self.writer; - let data = self.data; - VarUint32::from(data.len()) - .serialize(writer) - .map_err(|_| io::Error::InvalidData)?; - writer.write(&data[..])?; - Ok(()) - } -} - -impl<'a, W: 'a + io::Write> io::Write for CountedWriter<'a, W> { - fn write(&mut self, buf: &[u8]) -> io::Result<()> { - self.data.extend_from_slice(buf); - Ok(()) - } -} - -/// Helper struct to write series of `T` preceded by the length of the sequence -/// serialized as VarUint32. -#[derive(Debug, Clone)] -pub struct CountedListWriter, T: IntoIterator>(pub usize, pub T); - -impl, T: IntoIterator> Serialize for CountedListWriter { - type Error = Error; - - fn serialize(self, writer: &mut W) -> Result<(), Self::Error> { - let len_us = self.0; - let data = self.1; - let len: VarUint32 = len_us.into(); - len.serialize(writer)?; - for data_element in data { data_element.serialize(writer)? } - - Ok(()) - } -} - - // #[cfg(test)] // mod tests { From e01dc6a211d4ca6f1b2bc4db6f995d2d097c2984 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 17:56:46 +1000 Subject: [PATCH 12/22] circleci: fix error with parity installation --- .circleci/config.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 730f916..a2613aa 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -96,7 +96,11 @@ jobs: # cargo build --verbose --release --features final # strip target/debug/parity # file target/debug/parity - cargo install --bin parity -j 1 --path . --bin parity parity-ethereum + if some_command; then + echo "Parity node installed" + else + cargo install --bin parity -j 1 --path . --bin parity parity-ethereum + fi - save_cache: key: deps6-{{ .Branch }}-cargo #-{{ checksum "kernel-ewasm/Cargo.lock" }} paths: From adec99071d500792b9eb4b67883cb9b7d1ed569a Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 17:58:46 +1000 Subject: [PATCH 13/22] circleci: fix error in previous commit --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a2613aa..8e32415 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -96,7 +96,7 @@ jobs: # cargo build --verbose --release --features final # strip target/debug/parity # file target/debug/parity - if some_command; then + if parity --version; then echo "Parity node installed" else cargo install --bin parity -j 1 --path . --bin parity parity-ethereum From e85ceb432d697a6e4414a17fc0bfdfb58461598b Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 18:02:59 +1000 Subject: [PATCH 14/22] wasm-parser: reinclude alloc --- kernel-ewasm/validator/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel-ewasm/validator/src/lib.rs b/kernel-ewasm/validator/src/lib.rs index d0ba682..8566081 100644 --- a/kernel-ewasm/validator/src/lib.rs +++ b/kernel-ewasm/validator/src/lib.rs @@ -1,6 +1,8 @@ #![cfg_attr(not(feature = "std"), no_std)] #[cfg(not(feature="std"))] +#[macro_use] +extern crate alloc; use pwasm_std; use pwasm_std::vec::Vec; From 51b26f90928fb013783f91eaa1ca4b1e7137f6f1 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 18:07:50 +1000 Subject: [PATCH 15/22] wasm-parser: merge Cursor and CodeCursor --- kernel-ewasm/validator/src/lib.rs | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/kernel-ewasm/validator/src/lib.rs b/kernel-ewasm/validator/src/lib.rs index 8566081..268c243 100644 --- a/kernel-ewasm/validator/src/lib.rs +++ b/kernel-ewasm/validator/src/lib.rs @@ -441,7 +441,7 @@ fn parse_varuint_32(cursor: &mut Cursor) -> u32 { } fn parse_import(cursor: &mut Cursor, index: u32) -> ImportEntry { - let mut reader = CodeCursor { + let mut reader = Cursor { current_offset: cursor.current_offset, body: cursor.body, }; @@ -604,7 +604,7 @@ struct Code<'a> { // `count` at zero, we'll see why in `next()`'s implementation below. impl<'a> Code<'a> { fn new(body: &'a [u8]) -> Code { - let mut reader = CodeCursor { + let mut reader = Cursor { current_offset: 0, body: body, }; @@ -617,37 +617,13 @@ impl<'a> Code<'a> { } } -struct CodeCursor<'a> { - current_offset: usize, - body: &'a [u8], -} - -// This is basically the rust definition of read for slice -impl<'a> io::Read for CodeCursor<'a> { - fn read(&mut self, buf: &mut [u8]) -> io::Result<()> { - let actual_self = &self.body[self.current_offset..]; - let amt = core::cmp::min(buf.len(), actual_self.len()); - let (a, _) = actual_self.split_at(amt); - - if amt == 1 { - buf[0] = a[0]; - } else { - buf[..amt].copy_from_slice(a); - } - - self.current_offset += amt; - Ok(()) - } -} - - impl<'a> Iterator for Code<'a> { type Item = crate::instructions::Instruction; fn next(&mut self) -> Option { if self.current_offset < self.body.len() { // We need to parse the code into something meaningful - let mut reader = CodeCursor { + let mut reader = Cursor { current_offset: self.current_offset, body: self.body, }; From 05d0cf7cd866f5bd5b9ed4fda1feeffcebf64692 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 18:08:09 +1000 Subject: [PATCH 16/22] circleci: add example contract 2 --- kernel-ewasm/example_contract_2/Cargo.toml | 22 ++++++++ kernel-ewasm/example_contract_2/build.bat | 15 +++++ kernel-ewasm/example_contract_2/build.sh | 16 ++++++ .../build/example_contract_2.wasm | Bin 0 -> 35717 bytes kernel-ewasm/example_contract_2/src/lib.rs | 52 ++++++++++++++++++ 5 files changed, 105 insertions(+) create mode 100644 kernel-ewasm/example_contract_2/Cargo.toml create mode 100644 kernel-ewasm/example_contract_2/build.bat create mode 100644 kernel-ewasm/example_contract_2/build.sh create mode 100644 kernel-ewasm/example_contract_2/build/example_contract_2.wasm create mode 100644 kernel-ewasm/example_contract_2/src/lib.rs diff --git a/kernel-ewasm/example_contract_2/Cargo.toml b/kernel-ewasm/example_contract_2/Cargo.toml new file mode 100644 index 0000000..961bd83 --- /dev/null +++ b/kernel-ewasm/example_contract_2/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "example_contract_2" +version = "0.1.0" + +[dependencies] +pwasm-std = "0.13" +pwasm-ethereum = { version = "0.8", features = ["kip6"] } +pwasm-abi = "0.2" +pwasm-abi-derive = "0.2" +tiny-keccak = "1.4.2" + +[dev-dependencies] +pwasm-test = { git = "https://github.com/paritytech/pwasm-test" } +cap9-build = { path = "../../cap9-build" } +pwasm-utils-cli = "0.7.0" + +[features] +default = [] +std = ["pwasm-std/std", "pwasm-ethereum/std"] + +[lib] +crate-type = ["cdylib"] diff --git a/kernel-ewasm/example_contract_2/build.bat b/kernel-ewasm/example_contract_2/build.bat new file mode 100644 index 0000000..c2760c5 --- /dev/null +++ b/kernel-ewasm/example_contract_2/build.bat @@ -0,0 +1,15 @@ +@echo OFF + +mkdir .\build + +rustup target add wasm32-unknown-unknown +REM cargo install pwasm-utils-cli --bin wasm-build --force + +set contract_name=example_contract_2 + +cargo build --release --target wasm32-unknown-unknown +REM We don't need to use cap9 build here as it contains no syscalls +wasm-build --target=wasm32-unknown-unknown .\target %contract_name% + +copy .\target\*.wasm .\build +copy .\target\json\* .\build diff --git a/kernel-ewasm/example_contract_2/build.sh b/kernel-ewasm/example_contract_2/build.sh new file mode 100644 index 0000000..492a95e --- /dev/null +++ b/kernel-ewasm/example_contract_2/build.sh @@ -0,0 +1,16 @@ +@echo OFF + +mkdir ./build + +rustup target add wasm32-unknown-unknown +REM cargo install pwasm-utils-cli --bin wasm-build --force +cargo install --path ../../cap9-build --bin cap9-build --force + +export contract_name=example_contract_2 + +cargo build --release --target wasm32-unknown-unknown +# We don't need to use cap9 build here as it contains no syscalls +wasm-build --target=wasm32-unknown-unknown ./target $contract_name + +cp ./target/*.wasm ./build +cp ./target/json/* ./build diff --git a/kernel-ewasm/example_contract_2/build/example_contract_2.wasm b/kernel-ewasm/example_contract_2/build/example_contract_2.wasm new file mode 100644 index 0000000000000000000000000000000000000000..f1803fb3ce4b3570d5b10677e0fd96c8baee07f2 GIT binary patch literal 35717 zcmeI5du$)qmEZ3?e$OGLv8}|ir9|`lMX{+^viK$?$2LcaWGj9s+uC{6j!9G0gOo_| zA=<%iEqa?YPcK{~-F2~Uu?12j1%hr`>>p_x6zXoaaM2`iu|-p$4+vOq*H{E-fCktE zO{;#s=g#~{N>pMyP8>TFP0pP=bMHOp-1EM7uHD4q*}yp$d}zyfc;SK@k1kxe5L{51 zzX27Ft8?Qq^~K}j#-0aH@e-wq9_#s2*05@~JP7ZOqp8{DuG6#U&M!T7W@`52(kW+E z$%(0@$y1Nn0~hI~>e;EYa|@pcgD}-?v@o^gTy*TgN*LDaVOWV8jVN+Xf1_qIbYZ|9 zkD{mw2CAtAH5a%_RO3Mq290Jjp}rY*h28aLvl@h9P>CzSxnReRY8|-qm6bTD)q{9) z;>;QM!A2IiJV3v-lfBPM76K-RF`!9>9k-z;Kx7|Dq{p~;Eb_=(Gzx@Z?R?_>p zN#ECUS!l>*F6r~=wKRH=9yKCRcwnmt6Qmy~D<0emMW{HKR9rgXl5yzhF-e`LU65b6 zzdJDMRodagp*rU!s?#Qji~RjA>2il&`e%Rqso(qk zfAX2@l5ThClfV04pZ@Qc{@~AFc1dXe-DdCs4cvmIOcbK&EI8=& zv<{bAT^>wB31ce}v#abjrCVd#yXP5W;h^ibyXtbjYd*iIimp6t1vE4;E?nbE^d zBOYB~o*ugyc`-@JUGnL`Sl%es4vTg(nI|VWsgE}7b5v;M!IC=VCpx;L4cpx-qVtxq zoza$e7@{Uo3A!M-_#VOOMt%zskemUbM1~oNfrwI)Jnr>LHq%C*fUbHIM}|xiz|uOM z-V?f!NN`Y9S5>`Jl?C>&&ck>*{|Ta_x6(UW@O+-3^0FY=Z?a`9h!n3OQ@D;yw17s? z#!KW5YsFwd^n+*OHdI6guXFrM-sQrveC2oI^gTu~6|(^S+XpMF?9$tkrYnlQ$qcXi zpQ2F+d#x5>W71|LmNOI{LsH6$vC%SJ(daM=t*VEoCOlnX! zMbpnm(S_hC)78B*?ZC{#UFmkzhD+~EZ*0+Cv_W&73rC3Mcr!>Y|Sx!L1?q@}TG%&12nOfY0a@ zR6KiRKK< z>9TqrE=}jph917d-Bo%;ccG1L;#sh)))aOf*|F4upIX&uOk)BA(6k%gN^+T@9LsZP zi047FL0=MwZPs%G0m83m+TO98$Mce3Bgj2F^k4@=hJYrNyU`GcUnQ&HA=DD&4TPVK z9_U6!$O##qU1dYKke`+lqtDZbi1;nagMMbIx+w!0l zcfC!sYgCetU&T=nVL=Hx&v&rOYT#91yulcHltg2lsbJEMfuEm})6!yel|Ne+d8ceD z8H-WdvQHvMuuN$h>FqQDToTQ)`%@+ZsUf)o8k1YXzSASPPqkc4In&$)K>f4nFR>LEI&1?$83CQ2Z$70|THGN@9K^r1XX;gtgxbyj$->4yq!Ql!9kew90x$?dnp4 z5Y~=M)}|Nu5db>W6DT6)lIC*;t}o{XcnU)V_-)u10v_%baTsv9-H@26J5)$dXw$~k zwb2+^!`ZkXW z*R88AH0xOdrlMi1fp_F1Rn(1SoksrBz-$;vh5;Dz8GaRo$KjZ;_$G{MrYoz$%)FU@ zlj%ZV$Ysed?-~v-3V$lT8X>O%m48%nq|3j?yLH}$C!mp-5|>CWlYBX0w5^z7?+@fF zAwHivmdMoej~Mqk?w>CP1wyQ*S2=W;_n12XudaaBH=-^Oh0(ecbD$*|GmF!G3O`_s z2c$kTQW4BHoP?;?73=xlp*;;H5L;!+fb_`%NCT!_m9~PUOgpV*k!CnS- zU`8?u7z=SGinSXh3@Zrv!ro8?Fk!maX4kX{xAd|`WN3ed$XJS{lnxXK_PZmal>7{a z%&>&IBNfo~T2f)7Zy*^kgqIA9UtbOPLPFzSag}0PDTZ7|h4@Gp!b-p?*jYT3Ri(kc zDUOHUjjYzH2rBqg?pM}00;MQnC&iCwHDv_2sIm(UZzfY0?qlPln6649Ntk)JkyU3< zAo5Pcz-@WO>e@sXcqztNgAOFs^NM%i3Nc@$ka?bUp^CWF+w~*ez^WKV-X20#hr#p`+K(ftZ0HCTB)Xdsa*{8?h?V%JOtN;-mydDBw zaS=^TQ_F0bI#d$1Fs1%w$>OzM1}F%w4wP(#oatWiH)GJZY$KMYFpts=Ffg7fVj}vB zUkk!_24C&3AUpoHj}RmhKg(#*jd)ZZ3LtP-k{!Cd3ay!ZSD~}`ot%b;BZL7YLTFrZ zjb>NVA`vnl0&%iLg5JxwSs=5mjCFUID{f(%G9z$y1uYwnNkz1(v{0Uax1}%I_F8Ox zfpIE_0-Vxz49`many==^LMIdO$)_|1HK=x$Zn9Sq1}t$^PE=1X0KcPfJR(1Y;Q$lJ z*##5jH9V?}C}VBNDX{^n+u_(k{rhLKxn{VE$L2yY@ysf3?iAXZ`#AacA>p(Ei9%g& zGn#@a1<*d23Mk!@MJLC2M3M0Gn35^eQ33s@Bwy>zs8rTB8{LS z((*?-F~c)}H3}|~`9=kM?(pKlLy(oV3oT4TqzAFok*)Qb3{*yvH-30 zm;G>>IvJ!kb0n5AIV9fFY+4%3+ieBj&=9>V!Si59OIRDb)RUJhLH&Ye9#q5p+n0Y6 zWd^&2McmBwsA7&F|E+?ds-WDem0Y~`3O6aDW+dril3ixL6lDgYBGCk91(f7~dShc2 zhCpf_YomVKO&YapIPp|)nZajhn!pnNcyTd{Lq9bHz7Q8VigGIn49HnUYM93hMQJ8~ zdZm7}yDsvpM`Z<$(i#b7$Y6dU4{ffnZ}J|(!qqOciTCHkwqd&8{5Hi;1&|7%HtZ(! zBNh6OIh4-`u+o%r7Zpu($@@~ETyzGJq+>#IrwD_(g^A7NBg|MgTvKVR`5k!u0>>v) zX%Q%uT6o1Jf{OHDLgh4Ss|Z3`vS(siLyJidHSyA~8=@g(SG~7x!U_X*?r9_}4GasQW5MkH=)24KWpeslY@u@Hk7+li^8tCd8&=Df*3Nef1 zBYH8TsEApfn<0WvA^V4dl{lF#U=cS03{JZKCCuzP#Xy0+fZ2BrWnRZ5J3XjU@16Wvo6eZ*;7wI&0FakY|syV zTQi7l%Wk6Yvym4ZW607kKm}k@N_Wik6>N~BKFuBTynz_iTdwpA!gQYj0$EL&gf02{ z(zC?^tfDB!(?v=-`R6rr2&5-@4c#hMlbp8$V)SqffY2VAQOUfRkpX#w2&fh4F)#QD zCh9?_i5b0TV{d9^1>rTA(S&4`837ZTDl4;|83mb_e??wqL<~!!v~@liAa(@X!?ya@ zvOHk6hC6YSp@JC!ic0$!cM7wDI|0UXr`b4Ok|$kor#xJFlmeHgo;x>y)Rc8c+h(rd zPDPNz#-=55ntKn9UyZ$z!{E9e;&;*h70H&9mdkhcmpA;I|`RIg_dB&vDroK5QV||C z$&R5$VFPM-?!4x_ZPY|mk)#5e*IC9U1h1EOwagu6@QX?i5=$_j`8UX|TricjX7;ZL za*)tBr}TyUzvCY5>Euhi>JvY zqe(o$naWip^NWQ^OOhYThi9-T9Lve_!#-MFNbh5jc_s@LPociA^qkr(^ma{aJyd>C zh`g7!hj+mVF*T1VlzU}ayBg8}QA4t*q{=O-#b`_ZB4g)CUdjLLhc zsCy*=3Lz$qY?-3YOENdU6;y$$ax3t1#300D~`COoiqZ8T*8JrXPp zl1^J(Dba-A*A0Yn0RdS~n83!PKY3hc8B0HlJW;xzxlyW#DT|VZku}}rDCL*@&I=%z z@heR%r$ww51D5~&vyqx>_^NRQBh>K4_Bz*Y+P)5p4dz=-tdU+&D!@`O`P^4j%FB#(dK<`=T& z0uZjOe9IjnFz`(dcN4(YvigjYAmr9rNkkK4!AP5!#Znl^#QCThYkFP4^kO*}1|efa zqlE9&8TDAAbaW|Sf|nFVvGqe!RGWt6`PjXhH6}*m!WqivN;goTo|wgG%uH!!;SI3i zWoD2#O%%AuisnjiL@{CH3DcAYY|03h(@VdN8GyF6_;!^r21v>-ReW{bGIThTRT&ax z>h`%_shd1HVhh3MRly+46g``h4zF%NHf(33RoCe9dK$n^{0_Y-Et7c4FF-485&~g| zh_g~Bsw+e;*q2coqNJtioA7y7;|~IJU8qfEANo$TqFVQfpzHPMU`Ce97fAJd*5PM&K7&2pEF>Dhd@cLSl~ zAO^`xtzT<^t_R&H5BBmv2_`~HS$osIhgbz!SwSyK<)Y9ss7b`((-n5nt`w|HufOz^ z3?Xik0x{mC#6+1N#p1PgicujOmo>1$P3aSsL8#LoRB}NrEz@>c-isYKEf^NqTha}^ z)2%M3?Fk2)qb2t_r(Jh2KdO?R1a5xLOzylXs(Eq4C%J;2q38+W5OwRIoH3N$ni<29fdOsCuwT#Q~cEH?{;gpb+S3r-(u6QK_t=qI3qRNJ0!1X)jQb zh=4`F+3oqaKI;<(Yo-vqOC2A|SqMEN zG7>v)d{YrmS>^5dpKR3L>^gy`Uiedcp-75*a@pQmaiKO2%ZCQu+}(49PXE);He1>* zW$!-cw-y-(cj(#gx`%*;3V0#P*&u=2E(XqAW=~hzRlW4o-~LLwmcQg?wSizM|39CO zr}sN|ha;hvKgB{DEcTK+qkQ|?XR+9aSvYk0-+piZhme9Q>{lsR1A`!{RKLP_f9}}i zSd3491W{H`=WJe{w{a_e0J~o|3Z2kRC2xFSwF}$~x~QP=p^TSop;mOwK83YlB2dr{ z4>vDCn9gq{Zb|O}b{P#AFiwv9ecq+>Tqt_{AtnbVkZ#bzj4ZPlErJ78rI><0WtBw_ zvWl>cy})K*y=j|)UGm*(Q1#0k+UStqW+EQ3&A{wi@O=A9Pg8nYB!&ZzX%b&l5D6lA@VjGmhA8zXL@gUm-=R>EH;0g zYis!pb4z)t@P9XW$pjQxJLr08-|KZk*-Y+I2^Z50LGUuJ0U9%ApaCVcYstvMH1Y>^ zF$WQCeE|xt^$eLCd4`31bh*n@*kcF8gph~nXcP8-#5IOC*=3ecnUK=M1XMg-|Af!|XLEUpzX zKMrd1(sX{Ak0v6%(;&v~T|lROk9)pdI=VxCER*j|d`w20NFyAhYK1w9@~8FrgeENi z@uyil@SX7}ru^Wot|!XvR{ zOA1*TM4xa?wzxFP{}Vg+zxDTn6u;z;z7oXHg^$|)XXEJX^2C|b$FqsYPiLoRm*-}t z78fQTIdl5)+ZPtgXJ@CDPR$+97Ehm?ome`*F!k{4#N%hCvZc9fVsdio+)_pt=cj0% z&Cbp4J2&wOdptQeySTJ)esXDUA=8I*6ALHLpPiar%8pM>&K*BJdonvQar(^E@q-y7 z?q|fwxrM3y3sZ~d&nz+cv87W}3k3upoH(uq56@0Ld2VWQY3lglxf8{shldBt(m;Pv zIy5(T=Hc1nQwt}~%sr9Koyg9eUpzH+JUchBFaa)83yazQ*82`V^6( z`y}wqJ+d%$@-$F?;t^5dJ$9v99omk55yfa%kee%@Op7Causpeod zKEAiDeVP9J;;NFx2hq-l=D{t0^{^y(b&Z?z+=semj`=O!jkFMT4LTlTDW8lHPH zn>)WGo_l=m{Os|?gBfhBNy<(yX4&IB(!GC?n%4<3lbp4)ZslT_#ifabrNwMw$&Wt; zRJ!SXvbVRlueZNt)0LV zXO{{oaQVxhjg!yB&IRsz-o2h{lj|+~R`}h?{q_y&2dN+4p#Hb1*FRlDuAk)kHm-jW z`TqV3_q(|NYp#0pN5%EWTtCkJAiwBs_u(M0>nFK(asMn=x^Q3Qs&`)CD!9I0bFRU4 zC=A>~T!pa4y~Oi}xqcDM^t{S%onLMpO{~1OPVWeB{S#aXzuo-mef@6XcPqaszxFvD zSG^~iy~NnJaorkuTtCVK;d}$XdSC6g@vFMG^DBH*cO$=d&_@03=BoR@0(jB=CVur# zW8BQ|{XEaOp5dx7pW>=9|0!4XTaNjkxz`xq=PLOB4Oh`=5d_umi?M%xF97tcxqpaz z!z<^r!Q_%iz4`C0OaZw)32u-3MIT^rUqy!zRLtJ^a|&M3VFtzN1y>wv@Yu(zm70z- z;M@Y(IjnM60lZoZIn|)H=5Paaz-v0);M#{9R0xDz&fx}KwfjGE-L7_PXZDWX{kPw? z@7=p^9X)W%yFPT}!RF_m4nF=5L!S_M(SK0tql^%LG`Fp`AwoxDWBU?8dR^-}KdG^< zLwPx0`F{}$zWMg$g@ydjzWBetQPXb1IDH#lJRh#QbVo)?k79bWC3HwMlK{*w+PBhV zH6oHKX}7)MtJ52@c%RFZk=BxIkZ#Qh5L4}#pug>M$1T;U#Jp9JrmznS`4%-Qsz_7l zQwV*Ysw#bjN-4|y-v+XH@f6W-|iw*^$WeWN>3=}S8v0E?nWr^UIK2RV=KQ( z_fq0AnAv*oPVT<`InseF>QcOsB?;CkC@Fob1qUT{Y#A7^@{7R#fvXOm`1tDK6a6G} z*B(AGaK+&hgT#{rhJPITFFuP5k$nRT)C#N8X+A53t|1TGFgrb*N4iZ(b#K>DBh=b9_;|*0dRd8gCBI-CyQf3pTi)xV zT>m5^TH{N{oXb0Pxx?+`O=ZA-{sTN7RrW~fJb!@4qe5A?{s50hm4(o)KfvQrE%NHt zAK>w*ayq*82Y5WnP5N-l&!2cWxlxR4j7a60^fJeEK*N(hG!1h5>``BB`)O6;jhGaw zv+3GO5Itw9hJ?u4Zs>cPxC6>-J@k+k&{BT~DaG!b+OfqY|1o6$E*S#?@a8xu|vQ#^8(A`b8upC^>_)BF zt*VD?*Kg`$J=>y0PE(0VW}spCR@we%MG$6&k+rU3pN4(zZE_2}ZOekTHoykT-tW!A zLu^CPddrKFVyHxMFA}Syiu$pS&hwWM-1ijx+aUJ|L?kQ&BqK<#hqn4Ig$o~UpkwUo zj&MxN)})|~_xXgN_>6h|$t-_MuRy-^vEpQwN6LzE%R1_0n!gCVp1S0^c@xO zv(o@5v@}mI;FnJDIeUJ|t54JI(nEkkZ5O5YbA5rtPPv~X&U@^}P>)%=%vmRu7D%ny zWRn(uhvy&3Vr@3LpNG%ttdx5x@G_quih?><;76jMohzU*qzE- z<0<1j_jyx_mm?m>Q zj#3*!69!v*w@yEf^S)jICT2FznAK2r5Us)ryMNX|GwyMPcGa^~Q2A%qvD0GRvm3S5 zJW!Q0rrP5sMxwDS+~>x%o|b3R7z^0FR=%PdI%Jo%*+UwshT%z|mNimrW3rW@8pH6N z#C{5y2p);Fek2sUW1>NBMV9EnHk3l#_3U~BZkmjhdnoAx&kzvw1J-# zY4x&HPE9d;flh1U)hxY9f2F<0?bH@ANg5PiYOWqsg!)5Gpi)CM^PJX zE!ouwJlnCyFVZ|$$}&?`Ey{LL8?VPnuWIv60Nb!U%4Vj0KKZyo*0IAP@_srTWWZJm zE-;6vTHHiNMLev}ek#sy$-jySzSAX3Y}*R;H4Ga~0#N0`iggP#^aB{Ad~JVi&M7}g z1)U)roSMR(frlWtKFy$^?L>t1MSeJoKT_;Nv26KeHl*a=;CvcV^yxh=xs&c`DI><} z9nw{|kv&O-K~c(ruff8!{X;+=Dnb4!=Skh>8I1!YHt_C{ko*PCn1Umede*)}m)uGV z27kTIo??5g`ASmMXfNYE-~FmVH(uQ6>?!ORxV@&cry9vCI(v%Ou0DGTZ+pYaaZgO| z2r$DLT;GGGke$~b)~r|>N`He#Y>@~tE8;X>fDa^qp+9~`>e7y%(F4;;tfO=Gic4PO z;Z}Pg=&#k`Rv@eZ=9-6FP5j~yw`xkgb`H0auZe#tw-cT<51+}EJ=PkWIg`mR=y0nC zOxegDu>Q9GaH}68!wxJltyYaI4M3 zt;i)2^2VEoTVd?ql80N}g`wX(+-mc1s|^pgx?Ab>&BLv5LdwIf?h409q--8;wRyM| zD-$}X4)MSlwXb0*O<#Ft9Et8<&%>?m)>53P^Hx9H>MkuZTDIs{;c%;h?5u~`XY$c2 zIuda6a4VKmHxIYc>Z#5kW*fog;Z}B%BA;Kx9OL)qINU1#wO)0mPz9M8XRtQm-#zd>Hd{G-0E)I=)$fG za|=S9o?{zzSO(VOkxsQ@HAxpOB)-`Xw_4ASY~b8H-0DqnxYf1hO}u*LIc8e(exnb! zy4ySc7bE*L%?{IgQyy-`dZ;$TycrI+%B5%7uA`_+%R^dx?JRZuQVzG0#b!5zH`>Jp zroPVMR&4EH1!|_Vk;CtbLARoNZJC}la(NKc>u|Ug`<#C%hg&huFY$0IMtgk@x8jhE z&BLuW54U1#JbP)_@XvB{N)EUB*lRo7>SO$`6yHRLTYYTvaI3W^b-gtYx4Q2Q zJKXA{riQLK+=`Fi-k`&+t_99(Jlrbz%j+V(Y1ll>YV$BF&i?tSXLfBKX0>^k)#hPV dR~>%!+b(eWr|afnR&Mh!E8~XEKfh`e`2T(qz+?ab literal 0 HcmV?d00001 diff --git a/kernel-ewasm/example_contract_2/src/lib.rs b/kernel-ewasm/example_contract_2/src/lib.rs new file mode 100644 index 0000000..704b0d4 --- /dev/null +++ b/kernel-ewasm/example_contract_2/src/lib.rs @@ -0,0 +1,52 @@ +#![cfg_attr(not(feature="std"), no_std)] + +#![allow(non_snake_case)] + +extern crate tiny_keccak; +extern crate pwasm_std; +extern crate pwasm_ethereum; +extern crate pwasm_abi; +extern crate pwasm_abi_derive; + +use tiny_keccak::Keccak; +use pwasm_ethereum as eth; +use pwasm_abi::types::*; +use pwasm_abi_derive::eth_abi; +use pwasm_ethereum::Error; + +/// The call function is the main function of the *deployed* contract +#[no_mangle] +pub fn call() { + let mut endpoint = contract::ExampleContract2Endpoint::new(contract::ExampleContract2{}); + pwasm_ethereum::ret(&endpoint.dispatch(&pwasm_ethereum::input())); +} + +// Declares the dispatch and dispatch_ctor methods +use pwasm_abi::eth::EndpointInterface; + +#[no_mangle] +pub fn deploy() { + let mut endpoint = contract::ExampleContract2Endpoint::new(contract::ExampleContract2{}); + endpoint.dispatch_ctor(&pwasm_ethereum::input()); +} + + +pub mod contract { + use super::*; + use pwasm_abi_derive::eth_abi; + + #[eth_abi(ExampleContract2Endpoint, ExampleContract2Client)] + pub trait ExampleContract2Interface { + /// Check if Procedure Contract is Valid + fn check_contract(&mut self, _to: Address) -> bool; + } + + pub struct ExampleContract2; + + impl ExampleContract2Interface for ExampleContract2 { + fn check_contract(&mut self, _target: Address) -> bool { + // unimplemented!() + false + } + } +} From 39b4d5f5dd9ae46a8cc2fbccd37987c1070c2519 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 18:09:12 +1000 Subject: [PATCH 17/22] circleci: set-up environment for test --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8e32415..9e59db2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -139,6 +139,7 @@ jobs: - run: name: Test Rust Component command: | + . ~/.profile cd cap9 cd kernel-ewasm && npm install npm run test From 3093006eda6cb503b8a06985010f6cbeeaf95545 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 18:29:52 +1000 Subject: [PATCH 18/22] circleci: fix example_contract_2 build --- kernel-ewasm/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel-ewasm/test.sh b/kernel-ewasm/test.sh index 44f4f42..527c297 100644 --- a/kernel-ewasm/test.sh +++ b/kernel-ewasm/test.sh @@ -1,4 +1,4 @@ pushd example_contract_2 -./build.sh +sh ./build.sh popd mocha tests/**/**.js From 6cf47ae403effca6a263bb6cd0d9453c9c0ef055 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 18:30:16 +1000 Subject: [PATCH 19/22] wasm-parser: properly validate instructions in syscall --- kernel-ewasm/validator/src/lib.rs | 171 +++++++++++++----------------- 1 file changed, 73 insertions(+), 98 deletions(-) diff --git a/kernel-ewasm/validator/src/lib.rs b/kernel-ewasm/validator/src/lib.rs index 268c243..14d9bdc 100644 --- a/kernel-ewasm/validator/src/lib.rs +++ b/kernel-ewasm/validator/src/lib.rs @@ -235,6 +235,8 @@ impl Validity for &[u8] { // There is only one greylisted item (dcall) so we will just reserve a // place for that rather than maintain a list. let mut dcall_index: Option = None; + let mut gasleft_index: Option = None; + let mut sender_index: Option = None; if let Some(imports_offset) = import_section_offset { // Make a new cursor for imports let mut imports_cursor = Cursor {current_offset:imports_offset,body:&self}; @@ -249,6 +251,16 @@ impl Validity for &[u8] { // index. let import = parse_import(&mut imports_cursor, i); + if import.mod_name == "env" && import.field_name == "sender" { + if sender_index.is_some() {panic!("sender imported multiple times");} + sender_index = Some(import.index as usize); + } + + if import.mod_name == "env" && import.field_name == "gasleft" { + if gasleft_index.is_some() {panic!("gasleft imported multiple times");} + gasleft_index = Some(import.index as usize); + } + // println!("mod_name: {}, field_name: {}, f_index: {}, listing: {:?}", // import.mod_name, import.field_name, import.index, import.listing()); match import.listing() { @@ -288,14 +300,21 @@ impl Validity for &[u8] { assert_eq!(n_functions,n_bodies); + let dcall_index: Option = None; + let gasleft_index: Option = None; + let sender_index: Option = None; + // Next we iterate through the function bodies and check if they // violate any of our rules. for _i in 0..n_bodies { let body_size = parse_varuint_32(&mut code_cursor); - // First we check if it is a system call - if is_syscall(&self[(code_cursor.current_offset)..(code_cursor.current_offset+body_size as usize)]) { - // If the function is a system call we can continue past it - continue; + // First we check if it is a system call, this is only possible + // if we have the three required imports. + if let (Some(dcall_i),Some(gasleft_i),Some(sender_i)) = (dcall_index,gasleft_index,sender_index) { + if is_syscall(dcall_i as u32, gasleft_i as u32, sender_i as u32, &self[(code_cursor.current_offset)..(code_cursor.current_offset+body_size as usize)]) { + // If the function is a system call we can continue past it + continue; + } } // let body = parse_varuint_32(&mut code_cursor, &self); // println!("function[{}] is {} bytes", i, body_size); @@ -453,41 +472,6 @@ fn parse_import(cursor: &mut Cursor, index: u32) -> ImportEntry { } } -// fn get_imports(module: &Module) -> Vec { -// if let Some(import_section) = module.import_section() { -// import_section.entries().to_vec() -// } else { -// Vec::new() -// } -// } - -// fn check_grey(module: &Module, grey_index: usize) -> Vec<(u32, u32)> { -// let mut uses = Vec::new(); -// let code_section = module.code_section().unwrap(); -// let codes = Vec::from(code_section.bodies()); -// // If the instruction Call(grey_index) exists in the body of the function, that is a dangerous function. -// let this_call = parity_wasm::elements::Instruction::Call(grey_index as u32); -// for (func_index, func_body) in codes.iter().enumerate() { -// for (instruction_index, instruction) in func_body.code().elements().iter().enumerate() { -// if instruction == &this_call && !is_syscall(module, func_index as u32) { -// uses.push((func_index as u32, instruction_index as u32)); -// } -// } -// } -// uses -// } - -// // Find the function index of an import -// pub fn find_import(module: &Module, mod_name: &str, field_name: &str) -> Option { -// let imports = module.import_section().unwrap().entries(); -// for (i,import) in imports.iter().enumerate() { -// if import.module() == mod_name && import.field() == field_name { -// return Some(i as u32); -// } -// } -// return None; -// } - // pub fn is_syscall(module: &Module, function_index: u32) -> bool { // let function_section = module.function_section().unwrap(); @@ -638,10 +622,10 @@ impl<'a> Iterator for Code<'a> { // TODO: we need to provide the indices of the various necessary functions for // the system call. -pub fn is_syscall(body: &[u8]) -> bool { +pub fn is_syscall(dcall_i: u32, gasleft_i: u32, sender_i: u32, body: &[u8]) -> bool { // println!("body: {:?}", body); - let code_iter = Code::new(body); - let mut indexed_iter = code_iter.enumerate(); + let mut code_iter = Code::new(body); + // let mut indexed_iter = code_iter.enumerate(); // First we need to check that the instructions are correct, that is: // 0. call $a @@ -655,64 +639,55 @@ pub fn is_syscall(body: &[u8]) -> bool { // 0. call gasleft - if let Some((_instr_index, instructions::Instruction::Call(_f_ind))) = indexed_iter.next() { - // Check that f_ind is the function index of "gasleft" - // println!("call_index: {}", f_ind); + if let Some(instructions::Instruction::Call(f_ind)) = code_iter.next() { + if f_ind != gasleft_i { + return false; + } + } else { + return false; + } + // 1. call sender + if let Some(instructions::Instruction::Call(f_ind)) = code_iter.next() { + if f_ind != sender_i { + return false; + } + } else { + return false; + } + // 2. get_local 0 + if let Some(instructions::Instruction::GetLocal(0)) = code_iter.next() { + } else { + return false; + } + // 3. get_local 1 + if let Some(instructions::Instruction::GetLocal(1)) = code_iter.next() { + } else { + return false; + } + // 4. get_local 2 + if let Some(instructions::Instruction::GetLocal(2)) = code_iter.next() { + } else { + return false; + } + // 5. get_local 3 + if let Some(instructions::Instruction::GetLocal(3)) = code_iter.next() { + } else { + return false; } - // if let Instruction::Call(f_ind) = instructions[0] { - // let gasleft_index = find_import(module, "env", "gasleft"); - // if Some(f_ind) != gasleft_index { - // return false; - // } - // } else { - // return false; - // } - // // 1. call sender - // if let Instruction::Call(f_ind) = instructions[1] { - // // Check that f_ind is the function index of "sender" - // let sender_index = find_import(module, "env", "sender"); - // if Some(f_ind) != sender_index { - // return false; - // } - // } else { - // return false; - // } - // // 2. get_local 0 - // if let Instruction::GetLocal(0) = instructions[2] { - // } else { - // return false; - // } - // // 3. get_local 1 - // if let Instruction::GetLocal(1) = instructions[3] { - // } else { - // return false; - // } - // // 4. get_local 2 - // if let Instruction::GetLocal(2) = instructions[4] { - // } else { - // return false; - // } - // // 5. get_local 3 - // if let Instruction::GetLocal(3) = instructions[5] { - // } else { - // return false; - // } - // // 6. call dcall - // if let Instruction::Call(f_ind) = instructions[6] { - // // Check that f_ind is the function index of "dcall" - // let dcall_index = find_import(module, "env", "dcall"); - // if Some(f_ind) != dcall_index { - // return false; - // } - // } else { - // return false; - // } - // // 7. END - // if let Instruction::End = instructions[7] { - // } else { - // return false; - // } + // 6. call dcall + if let Some(instructions::Instruction::Call(f_ind)) = code_iter.next() { + if f_ind != dcall_i { + return false; + } + } else { + return false; + } + // 7. END + if let Some(instructions::Instruction::End) = code_iter.next() { + } else { + return false; + } // // Check that no locals are used // if code.locals().len() > 0 { From 61c670cc2f7d0317ceac0c6b25a079ae1fc5f949 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 18:46:20 +1000 Subject: [PATCH 20/22] wasm-parser: fix import cursor progression --- kernel-ewasm/validator/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel-ewasm/validator/src/lib.rs b/kernel-ewasm/validator/src/lib.rs index 14d9bdc..f832aa2 100644 --- a/kernel-ewasm/validator/src/lib.rs +++ b/kernel-ewasm/validator/src/lib.rs @@ -465,11 +465,13 @@ fn parse_import(cursor: &mut Cursor, index: u32) -> ImportEntry { body: cursor.body, }; let import: import_entry::ImportEntry = import_entry::ImportEntry::deserialize(&mut reader).expect("counted list"); - ImportEntry { + let val = ImportEntry { index, mod_name: String::from(import.module()), field_name: String::from(import.field()), - } + }; + cursor.current_offset = reader.current_offset; + val } // pub fn is_syscall(module: &Module, function_index: u32) -> bool { From 768453131e457b878a8f2f6f991861224f5d7210 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 18:49:43 +1000 Subject: [PATCH 21/22] circleci: remove config step from parity --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9e59db2..a0fc421 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -122,7 +122,7 @@ jobs: cd kernel-ewasm # we need to run parity once to set up the accounts and keys # this only needs to be active for a few seconds (hence timeout) - timeout 5 parity --config dev || true + # timeout 5 parity --config dev || true # We then run parity properly, now unlocking the previously setup # account parity --config dev --chain ./wasm-dev-chain.json --jsonrpc-apis=all --ws-apis=all --reseal-min-period 0 --gasprice 0 From ab4d448f1ea6033eae853734358080a964d73df7 Mon Sep 17 00:00:00 2001 From: Jake O'Shannessy Date: Thu, 6 Jun 2019 18:57:29 +1000 Subject: [PATCH 22/22] circleci: clear cache --- .circleci/config.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a0fc421..7a5073a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -43,10 +43,10 @@ jobs: steps: - restore_cache: keys: - - deps6-{{ .Branch }}-{{ .Revision }} - # - deps6-{{ .Branch }}-cargo-{{ checksum "kernel-ewasm/Cargo.lock" }} - - deps6-{{ .Branch }}- - - deps6- + - deps7-{{ .Branch }}-{{ .Revision }} + # - deps7-{{ .Branch }}-cargo-{{ checksum "kernel-ewasm/Cargo.lock" }} + - deps7-{{ .Branch }}- + - deps7- - run: name: Install native build prequisites command: | @@ -102,7 +102,7 @@ jobs: cargo install --bin parity -j 1 --path . --bin parity parity-ethereum fi - save_cache: - key: deps6-{{ .Branch }}-cargo #-{{ checksum "kernel-ewasm/Cargo.lock" }} + key: deps7-{{ .Branch }}-cargo #-{{ checksum "kernel-ewasm/Cargo.lock" }} paths: - "~/.cargo" - "~/.rustup"