From b7b93ac3485faf3b7ed9424645d9cefb65ffdc3d Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 27 Apr 2017 15:41:16 +0300 Subject: [PATCH] LittleEndianConvert trait for memory access --- src/interpreter/mod.rs | 1 - src/interpreter/runner.rs | 19 +++--- src/interpreter/utils.rs | 7 -- src/interpreter/value.rs | 136 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 18 deletions(-) delete mode 100644 src/interpreter/utils.rs diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 8c1a1ad..e09ced8 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -44,7 +44,6 @@ mod program; mod runner; mod stack; mod table; -mod utils; mod value; mod variable; diff --git a/src/interpreter/runner.rs b/src/interpreter/runner.rs index 66cdff1..126284d 100644 --- a/src/interpreter/runner.rs +++ b/src/interpreter/runner.rs @@ -6,9 +6,8 @@ use elements::{Opcode, BlockType, FunctionType}; use interpreter::Error; use interpreter::module::{ModuleInstance, ItemIndex}; use interpreter::stack::StackWithLimit; -use interpreter::utils::{to_little_endian_bytes, from_little_endian_bytes}; use interpreter::value::{RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto, TransmuteInto, - ArithmeticOps, Integer, Float}; + ArithmeticOps, Integer, Float, LittleEndianConvert}; use interpreter::variable::VariableInstance; const DEFAULT_MEMORY_INDEX: u32 = 0; @@ -397,21 +396,21 @@ impl Interpreter { } fn run_load(context: &mut FunctionContext, offset: u32, align: u32) -> Result - where RuntimeValue: From { + where RuntimeValue: From, T: LittleEndianConvert { context.module() .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) .and_then(|m| m.get(effective_address(offset, align)?, 4)) - .map(|b| from_little_endian_bytes::(&b)) + .and_then(|b| T::from_little_endian(b)) .and_then(|n| context.value_stack_mut().push(n.into())) .map(|_| InstructionOutcome::RunNextInstruction) } fn run_load_extend(context: &mut FunctionContext, offset: u32, align: u32) -> Result - where T: ExtendInto, RuntimeValue: From { + where T: ExtendInto, RuntimeValue: From, T: LittleEndianConvert { let stack_value: U = context.module() .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) .and_then(|m| m.get(effective_address(offset, align)?, mem::size_of::())) - .map(|b| from_little_endian_bytes::(&b)) + .and_then(|b| T::from_little_endian(b)) .map(|v| v.extend_into())?; context .value_stack_mut() @@ -420,11 +419,11 @@ impl Interpreter { } fn run_store(context: &mut FunctionContext, offset: u32, align: u32) -> Result - where RuntimeValue: TryInto { + where RuntimeValue: TryInto, T: LittleEndianConvert { let stack_value = context .value_stack_mut() .pop_as::() - .map(|n| to_little_endian_bytes::(n))?; + .map(|n| n.into_little_endian())?; context.module() .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) .and_then(|m| m.set(effective_address(offset, align)?, &stack_value)) @@ -432,9 +431,9 @@ impl Interpreter { } fn run_store_wrap(context: &mut FunctionContext, offset: u32, align: u32) -> Result - where RuntimeValue: TryInto, T: WrapInto { + where RuntimeValue: TryInto, T: WrapInto, U: LittleEndianConvert { let stack_value: T = context.value_stack_mut().pop().and_then(|v| v.try_into())?; - let stack_value = to_little_endian_bytes::(stack_value.wrap_into()); + let stack_value = stack_value.wrap_into().into_little_endian(); context.module() .memory(ItemIndex::IndexSpace(DEFAULT_MEMORY_INDEX)) .and_then(|m| m.set(effective_address(offset, align)?, &stack_value)) diff --git a/src/interpreter/utils.rs b/src/interpreter/utils.rs deleted file mode 100644 index e283cae..0000000 --- a/src/interpreter/utils.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub fn to_little_endian_bytes(_number: T) -> Vec { - unimplemented!() -} - -pub fn from_little_endian_bytes(_buffer: &[u8]) -> T { - unimplemented!() -} diff --git a/src/interpreter/value.rs b/src/interpreter/value.rs index 1c9091d..da067c1 100644 --- a/src/interpreter/value.rs +++ b/src/interpreter/value.rs @@ -1,5 +1,7 @@ use std::{i32, i64, u32, u64, f32}; +use std::io; use std::mem; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use interpreter::Error; use interpreter::variable::VariableType; @@ -50,6 +52,14 @@ pub trait TransmuteInto { fn transmute_into(self) -> T; } +/// Convert from and to little endian. +pub trait LittleEndianConvert where Self: Sized { + /// Convert to little endian bufer. + fn into_little_endian(self) -> Vec; + /// Convert from little endian bufer. + fn from_little_endian(buffer: Vec) -> Result; +} + /// Arithmetic operations. pub trait ArithmeticOps { /// Add two values. @@ -331,6 +341,8 @@ macro_rules! impl_transmute_into { } } +impl_transmute_into!(i8, u8); +impl_transmute_into!(u8, i8); impl_transmute_into!(i32, u32); impl_transmute_into!(u32, i32); impl_transmute_into!(i32, f32); @@ -340,6 +352,130 @@ impl_transmute_into!(u64, i64); impl_transmute_into!(i64, f64); impl_transmute_into!(f64, i64); +impl LittleEndianConvert for i8 { + fn into_little_endian(self) -> Vec { + vec![self.transmute_into()] + } + + fn from_little_endian(buffer: Vec) -> Result { + buffer.get(0) + .map(|v| v.transmute_into()) + .ok_or(Error::Value("invalid little endian buffer".into())) + } +} + +impl LittleEndianConvert for u8 { + fn into_little_endian(self) -> Vec { + vec![self] + } + + fn from_little_endian(buffer: Vec) -> Result { + buffer.get(0) + .cloned() + .ok_or(Error::Value("invalid little endian buffer".into())) + } +} + +impl LittleEndianConvert for i16 { + fn into_little_endian(self) -> Vec { + let mut vec = Vec::with_capacity(2); + vec.write_i16::(self) + .expect("i16 is written without any errors"); + vec + } + + fn from_little_endian(buffer: Vec) -> Result { + io::Cursor::new(buffer).read_i16::() + .map_err(|e| Error::Value(e.to_string())) + } +} + +impl LittleEndianConvert for u16 { + fn into_little_endian(self) -> Vec { + let mut vec = Vec::with_capacity(2); + vec.write_u16::(self) + .expect("u16 is written without any errors"); + vec + } + + fn from_little_endian(buffer: Vec) -> Result { + io::Cursor::new(buffer).read_u16::() + .map_err(|e| Error::Value(e.to_string())) + } +} + +impl LittleEndianConvert for i32 { + fn into_little_endian(self) -> Vec { + let mut vec = Vec::with_capacity(4); + vec.write_i32::(self) + .expect("i32 is written without any errors"); + vec + } + + fn from_little_endian(buffer: Vec) -> Result { + io::Cursor::new(buffer).read_i32::() + .map_err(|e| Error::Value(e.to_string())) + } +} + +impl LittleEndianConvert for u32 { + fn into_little_endian(self) -> Vec { + let mut vec = Vec::with_capacity(4); + vec.write_u32::(self) + .expect("u32 is written without any errors"); + vec + } + + fn from_little_endian(buffer: Vec) -> Result { + io::Cursor::new(buffer).read_u32::() + .map_err(|e| Error::Value(e.to_string())) + } +} + +impl LittleEndianConvert for i64 { + fn into_little_endian(self) -> Vec { + let mut vec = Vec::with_capacity(8); + vec.write_i64::(self) + .expect("i64 is written without any errors"); + vec + } + + fn from_little_endian(buffer: Vec) -> Result { + io::Cursor::new(buffer).read_i64::() + .map_err(|e| Error::Value(e.to_string())) + } +} + +impl LittleEndianConvert for f32 { + fn into_little_endian(self) -> Vec { + let mut vec = Vec::with_capacity(4); + vec.write_i32::(self.transmute_into()) + .expect("i32 is written without any errors"); + vec + } + + fn from_little_endian(buffer: Vec) -> Result { + io::Cursor::new(buffer).read_i32::() + .map(TransmuteInto::transmute_into) + .map_err(|e| Error::Value(e.to_string())) + } +} + +impl LittleEndianConvert for f64 { + fn into_little_endian(self) -> Vec { + let mut vec = Vec::with_capacity(8); + vec.write_i64::(self.transmute_into()) + .expect("i64 is written without any errors"); + vec + } + + fn from_little_endian(buffer: Vec) -> Result { + io::Cursor::new(buffer).read_i64::() + .map(TransmuteInto::transmute_into) + .map_err(|e| Error::Value(e.to_string())) + } +} + macro_rules! impl_integer_arithmetic_ops { ($type: ident) => { impl ArithmeticOps<$type> for $type {