LittleEndianConvert trait for memory access

This commit is contained in:
Svyatoslav Nikolsky 2017-04-27 15:41:16 +03:00
parent c2aef456a5
commit b7b93ac348
4 changed files with 145 additions and 18 deletions

View File

@ -44,7 +44,6 @@ mod program;
mod runner;
mod stack;
mod table;
mod utils;
mod value;
mod variable;

View File

@ -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<T>(context: &mut FunctionContext, offset: u32, align: u32) -> Result<InstructionOutcome, Error>
where RuntimeValue: From<T> {
where RuntimeValue: From<T>, 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::<T>(&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<T, U>(context: &mut FunctionContext, offset: u32, align: u32) -> Result<InstructionOutcome, Error>
where T: ExtendInto<U>, RuntimeValue: From<U> {
where T: ExtendInto<U>, RuntimeValue: From<U>, 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::<T>()))
.map(|b| from_little_endian_bytes::<T>(&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<T>(context: &mut FunctionContext, offset: u32, align: u32) -> Result<InstructionOutcome, Error>
where RuntimeValue: TryInto<T, Error> {
where RuntimeValue: TryInto<T, Error>, T: LittleEndianConvert {
let stack_value = context
.value_stack_mut()
.pop_as::<T>()
.map(|n| to_little_endian_bytes::<T>(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<T, U>(context: &mut FunctionContext, offset: u32, align: u32) -> Result<InstructionOutcome, Error>
where RuntimeValue: TryInto<T, Error>, T: WrapInto<U> {
where RuntimeValue: TryInto<T, Error>, T: WrapInto<U>, U: LittleEndianConvert {
let stack_value: T = context.value_stack_mut().pop().and_then(|v| v.try_into())?;
let stack_value = to_little_endian_bytes::<U>(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))

View File

@ -1,7 +0,0 @@
pub fn to_little_endian_bytes<T>(_number: T) -> Vec<u8> {
unimplemented!()
}
pub fn from_little_endian_bytes<T>(_buffer: &[u8]) -> T {
unimplemented!()
}

View File

@ -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<T> {
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<u8>;
/// Convert from little endian bufer.
fn from_little_endian(buffer: Vec<u8>) -> Result<Self, Error>;
}
/// Arithmetic operations.
pub trait ArithmeticOps<T> {
/// 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<u8> {
vec![self.transmute_into()]
}
fn from_little_endian(buffer: Vec<u8>) -> Result<Self, Error> {
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<u8> {
vec![self]
}
fn from_little_endian(buffer: Vec<u8>) -> Result<Self, Error> {
buffer.get(0)
.cloned()
.ok_or(Error::Value("invalid little endian buffer".into()))
}
}
impl LittleEndianConvert for i16 {
fn into_little_endian(self) -> Vec<u8> {
let mut vec = Vec::with_capacity(2);
vec.write_i16::<LittleEndian>(self)
.expect("i16 is written without any errors");
vec
}
fn from_little_endian(buffer: Vec<u8>) -> Result<Self, Error> {
io::Cursor::new(buffer).read_i16::<LittleEndian>()
.map_err(|e| Error::Value(e.to_string()))
}
}
impl LittleEndianConvert for u16 {
fn into_little_endian(self) -> Vec<u8> {
let mut vec = Vec::with_capacity(2);
vec.write_u16::<LittleEndian>(self)
.expect("u16 is written without any errors");
vec
}
fn from_little_endian(buffer: Vec<u8>) -> Result<Self, Error> {
io::Cursor::new(buffer).read_u16::<LittleEndian>()
.map_err(|e| Error::Value(e.to_string()))
}
}
impl LittleEndianConvert for i32 {
fn into_little_endian(self) -> Vec<u8> {
let mut vec = Vec::with_capacity(4);
vec.write_i32::<LittleEndian>(self)
.expect("i32 is written without any errors");
vec
}
fn from_little_endian(buffer: Vec<u8>) -> Result<Self, Error> {
io::Cursor::new(buffer).read_i32::<LittleEndian>()
.map_err(|e| Error::Value(e.to_string()))
}
}
impl LittleEndianConvert for u32 {
fn into_little_endian(self) -> Vec<u8> {
let mut vec = Vec::with_capacity(4);
vec.write_u32::<LittleEndian>(self)
.expect("u32 is written without any errors");
vec
}
fn from_little_endian(buffer: Vec<u8>) -> Result<Self, Error> {
io::Cursor::new(buffer).read_u32::<LittleEndian>()
.map_err(|e| Error::Value(e.to_string()))
}
}
impl LittleEndianConvert for i64 {
fn into_little_endian(self) -> Vec<u8> {
let mut vec = Vec::with_capacity(8);
vec.write_i64::<LittleEndian>(self)
.expect("i64 is written without any errors");
vec
}
fn from_little_endian(buffer: Vec<u8>) -> Result<Self, Error> {
io::Cursor::new(buffer).read_i64::<LittleEndian>()
.map_err(|e| Error::Value(e.to_string()))
}
}
impl LittleEndianConvert for f32 {
fn into_little_endian(self) -> Vec<u8> {
let mut vec = Vec::with_capacity(4);
vec.write_i32::<LittleEndian>(self.transmute_into())
.expect("i32 is written without any errors");
vec
}
fn from_little_endian(buffer: Vec<u8>) -> Result<Self, Error> {
io::Cursor::new(buffer).read_i32::<LittleEndian>()
.map(TransmuteInto::transmute_into)
.map_err(|e| Error::Value(e.to_string()))
}
}
impl LittleEndianConvert for f64 {
fn into_little_endian(self) -> Vec<u8> {
let mut vec = Vec::with_capacity(8);
vec.write_i64::<LittleEndian>(self.transmute_into())
.expect("i64 is written without any errors");
vec
}
fn from_little_endian(buffer: Vec<u8>) -> Result<Self, Error> {
io::Cursor::new(buffer).read_i64::<LittleEndian>()
.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 {