From a6c67d2f9336f9dfcaf910bab3602d272e9e22be Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 9 Jun 2017 15:17:12 +0300 Subject: [PATCH 01/18] data segment builder --- spec/src/fixtures.rs | 1 + src/builder/global.rs | 1 - src/builder/mod.rs | 1 + src/builder/module.rs | 23 ++++++++++++++++++++++- 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/spec/src/fixtures.rs b/spec/src/fixtures.rs index c7539c3..ad663f1 100644 --- a/spec/src/fixtures.rs +++ b/spec/src/fixtures.rs @@ -16,6 +16,7 @@ macro_rules! run_test { run_test!("address", wasm_address); run_test!("address-offset-range.fail", wasm_address_offset_range_fail, fail); run_test!("binary", wasm_binary); +run_test!("call", wasm_call); run_test!("endianness", wasm_endianness); run_test!("f32", wasm_f32); run_test!("f32_bitwise", wasm_f32_bitwise); diff --git a/src/builder/global.rs b/src/builder/global.rs index 2cae4ba..9c666f3 100644 --- a/src/builder/global.rs +++ b/src/builder/global.rs @@ -56,7 +56,6 @@ impl GlobalBuilder where F: Invoke { } } - impl Invoke for GlobalBuilder { type Result = Self; fn invoke(self, the_type: elements::ValueType) -> Self { diff --git a/src/builder/mod.rs b/src/builder/mod.rs index 7d7437e..d590a75 100644 --- a/src/builder/mod.rs +++ b/src/builder/mod.rs @@ -9,6 +9,7 @@ mod memory; mod table; mod export; mod global; +mod data; pub use self::module::{module, from_module, ModuleBuilder}; pub use self::code::{signatures, signature, function}; diff --git a/src/builder/module.rs b/src/builder/module.rs index 8086a96..372acfa 100644 --- a/src/builder/module.rs +++ b/src/builder/module.rs @@ -2,7 +2,7 @@ use super::invoke::{Invoke, Identity}; use super::code::{self, SignaturesBuilder, FunctionBuilder}; use super::memory::{self, MemoryBuilder}; use super::table::{self, TableBuilder}; -use super::{import, export, global}; +use super::{import, export, global, data}; use elements; /// Module builder @@ -321,6 +321,17 @@ impl ModuleBuilder where F: Invoke { global::GlobalBuilder::with_callback(self) } + /// Add data segment to the builder + pub fn with_data_segment(mut self, segment: elements::DataSegment) -> Self { + self.module.data.entries_mut().push(segment); + self + } + + /// Data entry builder + pub fn data(self) -> data::DataSegmentBuilder { + data::DataSegmentBuilder::with_callback(self) + } + /// Build module (final step) pub fn build(self) -> F::Result { self.callback.invoke(self.module.into()) @@ -414,6 +425,16 @@ impl Invoke for ModuleBuilder } } +impl Invoke for ModuleBuilder + where F: Invoke +{ + type Result = Self; + + fn invoke(self, segment: elements::DataSegment) -> Self { + self.with_data_segment(segment) + } +} + /// Start new module builder pub fn module() -> ModuleBuilder { ModuleBuilder::new() From 6446c62c829d794695e791380d8af11d1806db8e Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 9 Jun 2017 15:19:21 +0300 Subject: [PATCH 02/18] test --- src/builder/data.rs | 49 +++++++++++++++++++++++++++++++++++++++++++ src/builder/module.rs | 12 +++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/builder/data.rs diff --git a/src/builder/data.rs b/src/builder/data.rs new file mode 100644 index 0000000..46398e5 --- /dev/null +++ b/src/builder/data.rs @@ -0,0 +1,49 @@ +use super::invoke::{Identity, Invoke}; +use elements; + +pub struct DataSegmentBuilder { + callback: F, + // todo: add mapper once multiple memory refs possible + mem_index: u32, + offset: elements::InitExpr, + value: Vec, +} + +impl DataSegmentBuilder { + pub fn new() -> Self { + DataSegmentBuilder::with_callback(Identity) + } +} + +impl DataSegmentBuilder { + pub fn with_callback(callback: F) -> Self { + DataSegmentBuilder { + callback: callback, + mem_index: 0, + offset: elements::InitExpr::empty(), + value: Vec::new(), + } + } + + pub fn offset(mut self, opcode: elements::Opcode) -> Self { + self.offset = elements::InitExpr::new(vec![opcode, elements::Opcode::End]); + self + } + + pub fn value(mut self, value: Vec) -> Self { + self.value = value; + self + } +} + +impl DataSegmentBuilder where F: Invoke { + pub fn build(self) -> F::Result { + self.callback.invoke( + elements::DataSegment::new( + self.mem_index, + self.offset, + self.value, + ) + ) + } +} \ No newline at end of file diff --git a/src/builder/module.rs b/src/builder/module.rs index 372acfa..584b2d9 100644 --- a/src/builder/module.rs +++ b/src/builder/module.rs @@ -487,4 +487,16 @@ mod tests { assert_eq!(module.global_section().expect("global section to exist").entries().len(), 1); } + + #[test] + fn data() { + let module = module() + .data() + .offset(::elements::Opcode::I32Const(16)) + .value(vec![0u8, 15, 10, 5, 25]) + .build() + .build(); + + assert_eq!(module.data_section().expect("data section to exist").entries().len(), 1); + } } From 4a4ef698fc2ec4df97d6a6eb43174b212a69a289 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 9 Jun 2017 15:20:21 +0300 Subject: [PATCH 03/18] remove artifact --- spec/src/fixtures.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/src/fixtures.rs b/spec/src/fixtures.rs index ad663f1..c7539c3 100644 --- a/spec/src/fixtures.rs +++ b/spec/src/fixtures.rs @@ -16,7 +16,6 @@ macro_rules! run_test { run_test!("address", wasm_address); run_test!("address-offset-range.fail", wasm_address_offset_range_fail, fail); run_test!("binary", wasm_binary); -run_test!("call", wasm_call); run_test!("endianness", wasm_endianness); run_test!("f32", wasm_f32); run_test!("f32_bitwise", wasm_f32_bitwise); From ed68a0316de664c1945f37d8d16c3c377d19d564 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 9 Jun 2017 15:41:11 +0300 Subject: [PATCH 04/18] bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b6c0a41..e9205e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parity-wasm" -version = "0.8.5" +version = "0.8.6" authors = ["Nikolay Volf ", "Svyatoslav Nikolsky "] license = "MIT/Apache-2.0" readme = "README.md" From 23471d63da23cffb1939e6929b339e79a54330a5 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 9 Jun 2017 16:38:34 +0300 Subject: [PATCH 05/18] make opcode struct clear on store immediates --- src/elements/ops.rs | 141 ++++++++++++++++++++++---------------------- 1 file changed, 72 insertions(+), 69 deletions(-) diff --git a/src/elements/ops.rs b/src/elements/ops.rs index 4346f6d..b80b29e 100644 --- a/src/elements/ops.rs +++ b/src/elements/ops.rs @@ -122,6 +122,8 @@ pub enum Opcode { GetGlobal(u32), SetGlobal(u32), + // All store/load opcodes operate with 'memory immediates' + // which represented here as (flag, offset) tuple I32Load(u32, u32), I64Load(u32, u32), F32Load(u32, u32), @@ -145,6 +147,7 @@ pub enum Opcode { I64Store8(u32, u32), I64Store16(u32, u32), I64Store32(u32, u32), + CurrentMemory(bool), GrowMemory(bool), @@ -649,97 +652,97 @@ impl Serialize for Opcode { SetGlobal(index) => op!(writer, 0x24, { VarUint32::from(index).serialize(writer)?; }), - I32Load(from, to) => op!(writer, 0x28, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I32Load(flags, offset) => op!(writer, 0x28, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I64Load(from, to) => op!(writer, 0x29, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I64Load(flags, offset) => op!(writer, 0x29, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - F32Load(from, to) => op!(writer, 0x2a, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + F32Load(flags, offset) => op!(writer, 0x2a, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - F64Load(from, to) => op!(writer, 0x2b, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + F64Load(flags, offset) => op!(writer, 0x2b, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I32Load8S(from, to) => op!(writer, 0x2c, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I32Load8S(flags, offset) => op!(writer, 0x2c, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I32Load8U(from, to) => op!(writer, 0x2d, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I32Load8U(flags, offset) => op!(writer, 0x2d, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I32Load16S(from, to) => op!(writer, 0x2e, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I32Load16S(flags, offset) => op!(writer, 0x2e, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I32Load16U(from, to) => op!(writer, 0x2f, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I32Load16U(flags, offset) => op!(writer, 0x2f, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I64Load8S(from, to) => op!(writer, 0x30, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I64Load8S(flags, offset) => op!(writer, 0x30, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I64Load8U(from, to) => op!(writer, 0x31, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I64Load8U(flags, offset) => op!(writer, 0x31, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I64Load16S(from, to) => op!(writer, 0x32, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I64Load16S(flags, offset) => op!(writer, 0x32, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I64Load16U(from, to) => op!(writer, 0x33, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I64Load16U(flags, offset) => op!(writer, 0x33, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I64Load32S(from, to) => op!(writer, 0x34, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I64Load32S(flags, offset) => op!(writer, 0x34, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I64Load32U(from, to) => op!(writer, 0x35, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I64Load32U(flags, offset) => op!(writer, 0x35, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I32Store(from, to) => op!(writer, 0x36, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I32Store(flags, offset) => op!(writer, 0x36, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I64Store(from, to) => op!(writer, 0x37, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I64Store(flags, offset) => op!(writer, 0x37, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - F32Store(from, to) => op!(writer, 0x38, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + F32Store(flags, offset) => op!(writer, 0x38, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - F64Store(from, to) => op!(writer, 0x39, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + F64Store(flags, offset) => op!(writer, 0x39, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I32Store8(from, to) => op!(writer, 0x3a, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I32Store8(flags, offset) => op!(writer, 0x3a, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I32Store16(from, to) => op!(writer, 0x3b, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I32Store16(flags, offset) => op!(writer, 0x3b, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I64Store8(from, to) => op!(writer, 0x3c, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I64Store8(flags, offset) => op!(writer, 0x3c, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I64Store16(from, to) => op!(writer, 0x3d, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I64Store16(flags, offset) => op!(writer, 0x3d, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), - I64Store32(from, to) => op!(writer, 0x3e, { - VarUint32::from(from).serialize(writer)?; - VarUint32::from(to).serialize(writer)?; + I64Store32(flags, offset) => op!(writer, 0x3e, { + VarUint32::from(flags).serialize(writer)?; + VarUint32::from(offset).serialize(writer)?; }), CurrentMemory(flag) => op!(writer, 0x3f, { VarUint1::from(flag).serialize(writer)?; From 7bc0f8a0688b58ad41e63e057474e5bb29d31f44 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 13 Jun 2017 13:36:37 +0300 Subject: [PATCH 06/18] comments --- Cargo.toml | 1 + src/elements/primitives.rs | 1 - src/interpreter/module.rs | 2 +- src/interpreter/runner.rs | 2 +- src/interpreter/validator.rs | 2 +- src/lib.rs | 2 ++ 6 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b6c0a41..92744ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,5 +12,6 @@ keywords = ["wasm", "webassembly", "bytecode", "serde", "interpreter"] exclude = [ "res/*", "spec/*" ] [dependencies] +log = "0.3" byteorder = "1.0" parking_lot = "0.4" \ No newline at end of file diff --git a/src/elements/primitives.rs b/src/elements/primitives.rs index ee98a76..305f597 100644 --- a/src/elements/primitives.rs +++ b/src/elements/primitives.rs @@ -427,7 +427,6 @@ impl Deserialize for VarUint1 { fn deserialize(reader: &mut R) -> Result { let mut u8buf = [0u8; 1]; reader.read_exact(&mut u8buf)?; - // todo check range match u8buf[0] { 0 => Ok(VarUint1(false)), 1 => Ok(VarUint1(true)), diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index 6523282..91c06af 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -40,7 +40,7 @@ pub enum ExportEntryType { /// Module instance API. pub trait ModuleInstanceInterface { - /// Run instantiation-time procedures (validation and start function call). Module is not completely validated until this call. + /// Run instantiation-time procedures (validation and start function [if any] call). Module is not completely validated until this call. fn instantiate<'a>(&self, is_user_module: bool, externals: Option<&'a HashMap>>) -> Result<(), Error>; /// Execute function with the given index. fn execute_index(&self, index: u32, params: ExecutionParams) -> Result, Error>; diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index f2a5833..da73e78 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -858,7 +858,7 @@ impl Interpreter { loop { let instruction = &body[context.position]; - // println!("=== RUNNING {:?}", instruction); // TODO: trace + debug!(target: "interpreter", "running {:?}", instruction); match Interpreter::run_instruction(context, instruction)? { InstructionOutcome::RunInstruction => (), InstructionOutcome::RunNextInstruction => context.position += 1, diff --git a/src/interpreter/validator.rs b/src/interpreter/validator.rs index 891e4f2..7d995a0 100644 --- a/src/interpreter/validator.rs +++ b/src/interpreter/validator.rs @@ -77,7 +77,7 @@ impl Validator { } pub fn validate_instruction(context: &mut FunctionValidationContext, opcode: &Opcode) -> Result { - // println!("=== VALIDATING {:?}: {:?}", opcode, context.value_stack); + debug!(target: "validator", "validating {:?}", opcode); match opcode { &Opcode::Unreachable => Ok(InstructionOutcome::Unreachable), &Opcode::Nop => Ok(InstructionOutcome::RunNextInstruction), diff --git a/src/lib.rs b/src/lib.rs index d0443f7..680de78 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,8 @@ #![warn(missing_docs)] +#[macro_use] +extern crate log; extern crate byteorder; extern crate parking_lot; From 5a07f6075b801104e55f20da154daf7350343abc Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 13 Jun 2017 13:46:27 +0300 Subject: [PATCH 07/18] new version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8d22e52..11d1deb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parity-wasm" -version = "0.8.6" +version = "0.9.0" authors = ["Nikolay Volf ", "Svyatoslav Nikolsky "] license = "MIT/Apache-2.0" readme = "README.md" From 352b218dbc7f15169ce50a84359fbcba2028690d Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 14 Jun 2017 12:26:19 +0300 Subject: [PATCH 08/18] func index in mapped error --- src/interpreter/module.rs | 18 ++++++++++++++++-- src/interpreter/validator.rs | 9 ++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/interpreter/module.rs b/src/interpreter/module.rs index 91c06af..f8f2357 100644 --- a/src/interpreter/module.rs +++ b/src/interpreter/module.rs @@ -312,9 +312,23 @@ impl ModuleInstanceInterface for ModuleInstance { let function_body = code_section.bodies().get(index as usize).ok_or(Error::Validation(format!("Missing body for function {}", index)))?; let mut locals = function_type.params().to_vec(); locals.extend(function_body.locals().iter().flat_map(|l| repeat(l.value_type()).take(l.count() as usize))); - let mut context = FunctionValidationContext::new(&self.module, &self.imports, &locals, DEFAULT_VALUE_STACK_LIMIT, DEFAULT_FRAME_STACK_LIMIT, &function_type); + let mut context = FunctionValidationContext::new( + &self.module, + &self.imports, + &locals, + DEFAULT_VALUE_STACK_LIMIT, + DEFAULT_FRAME_STACK_LIMIT, + &function_type); + let block_type = function_type.return_type().map(BlockType::Value).unwrap_or(BlockType::NoResult); - Validator::validate_block(&mut context, false, block_type, function_body.code().elements(), Opcode::End)?; + Validator::validate_block(&mut context, false, block_type, function_body.code().elements(), Opcode::End) + .map_err(|e| { + if let Error::Validation(msg) = e { + Error::Validation(format!("Function #{} validation error: {}", index, msg)) + } else { + e + } + })?; } } diff --git a/src/interpreter/validator.rs b/src/interpreter/validator.rs index 7d995a0..9d4c07b 100644 --- a/src/interpreter/validator.rs +++ b/src/interpreter/validator.rs @@ -495,7 +495,14 @@ impl Validator { } impl<'a> FunctionValidationContext<'a> { - pub fn new(module: &'a Module, imports: &'a ModuleImports, locals: &'a [ValueType], value_stack_limit: usize, frame_stack_limit: usize, function: &FunctionType) -> Self { + pub fn new( + module: &'a Module, + imports: &'a ModuleImports, + locals: &'a [ValueType], + value_stack_limit: usize, + frame_stack_limit: usize, + function: &FunctionType, + ) -> Self { FunctionValidationContext { module: module, imports: imports, From 2ce12d5a70e9788289640a90369d94018c1079c7 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Wed, 14 Jun 2017 14:09:00 +0300 Subject: [PATCH 09/18] if_else_with_return_type_validation --- src/interpreter/tests/basics.rs | 29 +++++++++++++++++++++++++++-- src/interpreter/validator.rs | 4 ++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/interpreter/tests/basics.rs b/src/interpreter/tests/basics.rs index e8e9f35..b13cb00 100644 --- a/src/interpreter/tests/basics.rs +++ b/src/interpreter/tests/basics.rs @@ -1,14 +1,16 @@ ///! Basic tests for instructions/constructions, missing in wabt tests -use std::sync::Arc; +use std::sync::{Arc, Weak}; use builder::module; use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, GlobalType, - InitExpr, ValueType, Opcodes, Opcode}; + InitExpr, ValueType, BlockType, Opcodes, Opcode, FunctionType}; use interpreter::Error; use interpreter::env_native::{env_native_module, UserFunction, UserFunctions, UserFunctionExecutor}; +use interpreter::imports::ModuleImports; use interpreter::memory::MemoryInstance; use interpreter::module::{ModuleInstanceInterface, CallerContext, ItemIndex, ExecutionParams}; use interpreter::program::ProgramInstance; +use interpreter::validator::{FunctionValidationContext, Validator}; use interpreter::value::RuntimeValue; #[test] @@ -215,3 +217,26 @@ fn single_program_different_modules() { assert_eq!(executor.memory.get(0, 1).unwrap()[0], 42); assert_eq!(executor.values, vec![7, 57, 42]); } + +#[test] +fn if_else_with_return_type_validation() { + let module = module().build(); + let imports = ModuleImports::new(Weak::default(), None); + let mut context = FunctionValidationContext::new(&module, &imports, &[], 1024, 1024, &FunctionType::default()); + + Validator::validate_block(&mut context, false, BlockType::NoResult, &[ + Opcode::I32Const(1), + Opcode::If(BlockType::NoResult, Opcodes::new(vec![ + Opcode::I32Const(1), + Opcode::If(BlockType::Value(ValueType::I32), Opcodes::new(vec![ + Opcode::I32Const(1), + Opcode::Else, + Opcode::I32Const(2), + Opcode::End, + ])), + Opcode::Drop, + Opcode::End, + ])), + Opcode::End, + ], Opcode::End).unwrap(); +} diff --git a/src/interpreter/validator.rs b/src/interpreter/validator.rs index 7d995a0..708887d 100644 --- a/src/interpreter/validator.rs +++ b/src/interpreter/validator.rs @@ -399,6 +399,10 @@ impl Validator { .unwrap_or(body_len - 1); if separator_index != body_len - 1 { Validator::validate_block(context, false, block_type, &body[..separator_index + 1], Opcode::Else)?; + if let BlockType::Value(value_type) = block_type { + context.pop_value(value_type.into())?; + } + Validator::validate_block(context, false, block_type, &body[separator_index+1..], Opcode::End) } else { if block_type != BlockType::NoResult { From 9c2061c63c975107f46fb168b701f99ef3dde672 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 14 Jun 2017 14:24:21 +0300 Subject: [PATCH 10/18] bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 11d1deb..9871bcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parity-wasm" -version = "0.9.0" +version = "0.9.1" authors = ["Nikolay Volf ", "Svyatoslav Nikolsky "] license = "MIT/Apache-2.0" readme = "README.md" From f2ee624cea67e0523e79b4ab45f146e88f9654fd Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 14 Jun 2017 17:07:22 +0300 Subject: [PATCH 11/18] static variants of passed functions --- src/interpreter/env_native.rs | 63 +++++++++++++++++++++++++++------ src/interpreter/tests/basics.rs | 31 ++++++++++------ 2 files changed, 74 insertions(+), 20 deletions(-) diff --git a/src/interpreter/env_native.rs b/src/interpreter/env_native.rs index 19216af..ec86577 100644 --- a/src/interpreter/env_native.rs +++ b/src/interpreter/env_native.rs @@ -1,5 +1,6 @@ use std::sync::Arc; use std::collections::HashMap; +use std::borrow::Cow; use parking_lot::RwLock; use elements::{FunctionType, Internal, ValueType}; use interpreter::Error; @@ -22,20 +23,62 @@ pub trait UserFunctionExecutor { fn execute(&mut self, name: &str, context: CallerContext) -> Result, Error>; } +#[derive(Clone)] +pub enum UserFunctionDescriptor { + Static(&'static str, &'static [ValueType]), + Heap(String, Vec), +} + /// User function type. +#[derive(Clone)] pub struct UserFunction { - /// User function name. - pub name: String, - /// User function parameters (for signature matching). - pub params: Vec, - /// User function return type (for signature matching). + pub desc: UserFunctionDescriptor, pub result: Option, } +impl UserFunction { + /// New function with statically known params + pub fn statik(name: &'static str, params: &'static [ValueType], result: Option) -> Self { + UserFunction { + desc: UserFunctionDescriptor::Static(name, params), + result: result, + } + } + + /// New function with statically unknown params + pub fn heap(name: String, params: Vec, result: Option) -> Self { + UserFunction { + desc: UserFunctionDescriptor::Heap(name, params), + result: result, + } + } + + /// Name of the function + pub fn name(&self) -> &str { + match self.desc { + UserFunctionDescriptor::Static(name, _) => name, + UserFunctionDescriptor::Heap(ref name, _) => name, + } + } + + /// Arguments of the function + pub fn params(&self) -> &[ValueType] { + match self.desc { + UserFunctionDescriptor::Static(_, params) => params, + UserFunctionDescriptor::Heap(_, ref params) => params, + } + } + + /// Return type of the function + pub fn result(&self) -> Option { + self.result + } +} + /// Set of user-defined functions pub struct UserFunctions<'a> { /// Functions list. - pub functions: Vec, + pub functions: Cow<'static, [UserFunction]>, /// Functions executor. pub executor: &'a mut UserFunctionExecutor, } @@ -49,7 +92,7 @@ pub struct NativeModuleInstance<'a> { /// By-name functions index. by_name: HashMap, /// User functions list. - functions: Vec, + functions: Cow<'static, [UserFunction]>, } impl<'a> NativeModuleInstance<'a> { @@ -58,7 +101,7 @@ impl<'a> NativeModuleInstance<'a> { Ok(NativeModuleInstance { env: env, executor: RwLock::new(functions.executor), - by_name: functions.functions.iter().enumerate().map(|(i, f)| (f.name.clone(), i as u32)).collect(), + by_name: functions.functions.iter().enumerate().map(|(i, f)| (f.name().to_owned(), i as u32)).collect(), functions: functions.functions, }) } @@ -98,7 +141,7 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { self.functions .get((index - NATIVE_INDEX_FUNC_MIN) as usize) .ok_or(Error::Native(format!("missing native env function with index {}", index))) - .map(|f| FunctionType::new(f.params.clone(), f.result.clone())) + .map(|f| FunctionType::new(f.params().to_vec(), f.result().clone())) } fn table(&self, index: ItemIndex) -> Result, Error> { @@ -130,7 +173,7 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { self.functions .get((index - NATIVE_INDEX_FUNC_MIN) as usize) .ok_or(Error::Native(format!("trying to call native function with index {}", index))) - .and_then(|f| self.executor.write().execute(&f.name, outer)) + .and_then(|f| self.executor.write().execute(&f.name(), outer)) } } diff --git a/src/interpreter/tests/basics.rs b/src/interpreter/tests/basics.rs index b13cb00..2931529 100644 --- a/src/interpreter/tests/basics.rs +++ b/src/interpreter/tests/basics.rs @@ -5,7 +5,7 @@ use builder::module; use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, GlobalType, InitExpr, ValueType, BlockType, Opcodes, Opcode, FunctionType}; use interpreter::Error; -use interpreter::env_native::{env_native_module, UserFunction, UserFunctions, UserFunctionExecutor}; +use interpreter::env_native::{env_native_module, UserFunction, UserFunctions, UserFunctionExecutor, UserFunctionDescriptor}; use interpreter::imports::ModuleImports; use interpreter::memory::MemoryInstance; use interpreter::module::{ModuleInstanceInterface, CallerContext, ItemIndex, ExecutionParams}; @@ -123,6 +123,25 @@ fn global_get_set() { assert_eq!(module.execute_index(2, vec![].into()).unwrap_err(), Error::Variable("trying to update variable of type I32 with value of type Some(I64)".into())); } +const SIGNATURE_I32: &'static [ValueType] = &[ValueType::I32]; + +const SIGNATURES: &'static [UserFunction] = &[ + UserFunction { + desc: UserFunctionDescriptor::Static( + "add", + SIGNATURE_I32, + ), + result: Some(ValueType::I32), + }, + UserFunction { + desc: UserFunctionDescriptor::Static( + "sub", + SIGNATURE_I32, + ), + result: Some(ValueType::I32), + }, +]; + #[test] fn single_program_different_modules() { // user function executor @@ -170,15 +189,7 @@ fn single_program_different_modules() { { let functions: UserFunctions = UserFunctions { executor: &mut executor, - functions: vec![UserFunction { - name: "add".into(), - params: vec![ValueType::I32], - result: Some(ValueType::I32), - }, UserFunction { - name: "sub".into(), - params: vec![ValueType::I32], - result: Some(ValueType::I32), - }], + functions: ::std::borrow::Cow::from(SIGNATURES), }; let native_env_instance = Arc::new(env_native_module(env_instance, functions).unwrap()); let params = ExecutionParams::with_external("env".into(), native_env_instance); From e9ad59d9da18793c7107f1e6cffed4214ae5ac6c Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 14 Jun 2017 17:56:45 +0300 Subject: [PATCH 12/18] memory upgrade --- src/interpreter/memory.rs | 70 +++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/src/interpreter/memory.rs b/src/interpreter/memory.rs index 7aadcae..2b8995b 100644 --- a/src/interpreter/memory.rs +++ b/src/interpreter/memory.rs @@ -18,6 +18,18 @@ pub struct MemoryInstance { maximum_size: u32, } +struct CheckedRegion<'a, B: 'a> where B: ::std::ops::Deref> { + _buffer: &'a B, + offset: usize, + size: usize, +} + +impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref> { + fn range(&self) -> ::std::ops::Range { + self.offset..self.offset+self.size + } +} + impl MemoryInstance { /// Create new linear memory instance. pub fn new(memory_type: &MemoryType) -> Result, Error> { @@ -48,36 +60,18 @@ impl MemoryInstance { /// Get data at given offset. pub fn get(&self, offset: u32, size: usize) -> Result, Error> { - let begin = offset as usize; - let end = match begin.checked_add(size) { - Some(end) => end, - None => return Err(Error::Memory(format!("trying to read memory block of size {} from offset {}", size, offset))), - }; - let buffer = self.buffer.read(); - if buffer.len() < end { - return Err(Error::Memory(format!("trying to read region [{}..{}] in memory [0..{}]", begin, end, buffer.len()))); - } + let region = self.checked_region(&buffer, offset as usize, size)?; - Ok(buffer[begin..end].to_vec()) + Ok(buffer[region.range()].to_vec()) } /// Set data at given offset. pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> { - let size = value.len(); - let begin = offset as usize; - let end = match begin.checked_add(size) { - Some(end) => end, - None => return Err(Error::Memory(format!("trying to update memory block of size {} from offset {}", size, offset))), - }; - let mut buffer = self.buffer.write(); - if buffer.len() < end { - return Err(Error::Memory(format!("trying to update region [{}..{}] in memory [0..{}]", begin, end, buffer.len()))); - } + let range = self.checked_region(&buffer, offset as usize, value.len())?.range(); - let mut mut_buffer = buffer.as_mut_slice(); - mut_buffer[begin..end].copy_from_slice(value); + buffer[range].copy_from_slice(value); Ok(()) } @@ -96,4 +90,36 @@ impl MemoryInstance { }, } } + + fn checked_region<'a, B>(&self, buffer: &'a B, offset: usize, size: usize) -> Result, Error> + where B: ::std::ops::Deref> + { + let end = offset.checked_add(size) + .ok_or(Error::Memory(format!("trying to access memory block of size {} from offset {}", size, offset)))?; + + if end > buffer.len() { + return Err(Error::Memory(format!("trying to access region [{}..{}] in memory [0..{}]", offset, end, buffer.len()))); + } + + Ok(CheckedRegion { + _buffer: buffer, + offset: offset, + size: size, + }) + } + + pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error> { + let buffer = self.buffer.write(); + + let read_region = self.checked_region(&buffer, src_offset, len)?; + let write_region = self.checked_region(&buffer, dst_offset, len)?; + + unsafe { ::std::ptr::copy( + buffer[read_region.range()].as_ptr(), + buffer[write_region.range()].as_ptr() as *mut _, + len, + )} + + Ok(()) + } } From 40a07cfb75037d07f9f3b2f9a3087d5cfc463989 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 14 Jun 2017 18:00:59 +0300 Subject: [PATCH 13/18] fix warnings --- src/interpreter/memory.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/interpreter/memory.rs b/src/interpreter/memory.rs index 2b8995b..0bca676 100644 --- a/src/interpreter/memory.rs +++ b/src/interpreter/memory.rs @@ -19,7 +19,7 @@ pub struct MemoryInstance { } struct CheckedRegion<'a, B: 'a> where B: ::std::ops::Deref> { - _buffer: &'a B, + buffer: &'a B, offset: usize, size: usize, } @@ -28,6 +28,10 @@ impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref> fn range(&self) -> ::std::ops::Range { self.offset..self.offset+self.size } + + fn slice(&self) -> &[u8] { + &*self.buffer + } } impl MemoryInstance { @@ -63,7 +67,7 @@ impl MemoryInstance { let buffer = self.buffer.read(); let region = self.checked_region(&buffer, offset as usize, size)?; - Ok(buffer[region.range()].to_vec()) + Ok(region.slice().to_vec()) } /// Set data at given offset. @@ -102,12 +106,13 @@ impl MemoryInstance { } Ok(CheckedRegion { - _buffer: buffer, + buffer: buffer, offset: offset, size: size, }) } + /// Copy memory region pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error> { let buffer = self.buffer.write(); From 0bcf7da546ef9dd147544471e1da83b814a1a802 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 14 Jun 2017 18:02:31 +0300 Subject: [PATCH 14/18] fix warnings --- src/interpreter/env_native.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/interpreter/env_native.rs b/src/interpreter/env_native.rs index ec86577..953a40e 100644 --- a/src/interpreter/env_native.rs +++ b/src/interpreter/env_native.rs @@ -23,6 +23,7 @@ pub trait UserFunctionExecutor { fn execute(&mut self, name: &str, context: CallerContext) -> Result, Error>; } +/// User function descriptor #[derive(Clone)] pub enum UserFunctionDescriptor { Static(&'static str, &'static [ValueType]), @@ -32,7 +33,9 @@ pub enum UserFunctionDescriptor { /// User function type. #[derive(Clone)] pub struct UserFunction { + /// Descriptor with variable-length definitions pub desc: UserFunctionDescriptor, + /// Return type of the signature pub result: Option, } From 4a171aef7e4006874c7817a0cbd81f0d026098b7 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 14 Jun 2017 18:09:33 +0300 Subject: [PATCH 15/18] fix range --- src/interpreter/memory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interpreter/memory.rs b/src/interpreter/memory.rs index 0bca676..1c208a7 100644 --- a/src/interpreter/memory.rs +++ b/src/interpreter/memory.rs @@ -30,7 +30,7 @@ impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref> } fn slice(&self) -> &[u8] { - &*self.buffer + &self.buffer[self.range()] } } From 5aa38bc90543f8abcede0e499917812d55735963 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 14 Jun 2017 18:52:47 +0300 Subject: [PATCH 16/18] missing api exposure and docs --- src/interpreter/env_native.rs | 2 ++ src/interpreter/mod.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/interpreter/env_native.rs b/src/interpreter/env_native.rs index 953a40e..053fa31 100644 --- a/src/interpreter/env_native.rs +++ b/src/interpreter/env_native.rs @@ -26,7 +26,9 @@ pub trait UserFunctionExecutor { /// User function descriptor #[derive(Clone)] pub enum UserFunctionDescriptor { + /// Static function definition Static(&'static str, &'static [ValueType]), + /// Dynamic heap function definition Heap(String, Vec), } diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 7d3331a..33155bd 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -79,5 +79,5 @@ pub use self::table::TableInstance; pub use self::program::ProgramInstance; pub use self::value::RuntimeValue; pub use self::variable::VariableInstance; -pub use self::env_native::{env_native_module, UserFunctions, UserFunction, UserFunctionExecutor}; +pub use self::env_native::{env_native_module, UserFunctions, UserFunction, UserFunctionExecutor, UserFunctionDescriptor}; pub use self::env::EnvParams; \ No newline at end of file From 7f7d7dc8bb94712e00921b4202f8098063b24e44 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 14 Jun 2017 19:12:11 +0300 Subject: [PATCH 17/18] new version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9871bcb..00f9c6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parity-wasm" -version = "0.9.1" +version = "0.10.0" authors = ["Nikolay Volf ", "Svyatoslav Nikolsky "] license = "MIT/Apache-2.0" readme = "README.md" From 2f416260b0c5130d754bf080ccb954dbdfbcd415 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 14 Jun 2017 19:26:38 +0300 Subject: [PATCH 18/18] also mem zero --- src/interpreter/memory.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/interpreter/memory.rs b/src/interpreter/memory.rs index 1c208a7..43a921f 100644 --- a/src/interpreter/memory.rs +++ b/src/interpreter/memory.rs @@ -127,4 +127,13 @@ impl MemoryInstance { Ok(()) } + + /// Zero memory region + pub fn zero(&self, offset: usize, len: usize) -> Result<(), Error> { + let mut buffer = self.buffer.write(); + + let range = self.checked_region(&buffer, offset, len)?.range(); + for val in &mut buffer[range] { *val = 0 } + Ok(()) + } }