Avoid allocations on memory operations (#112)
This commit is contained in:
parent
a605175abe
commit
9ed95e49c1
|
@ -7,6 +7,7 @@ use std::cell::RefCell;
|
||||||
use parity_wasm::elements::ResizableLimits;
|
use parity_wasm::elements::ResizableLimits;
|
||||||
use Error;
|
use Error;
|
||||||
use memory_units::{RoundUpTo, Pages, Bytes};
|
use memory_units::{RoundUpTo, Pages, Bytes};
|
||||||
|
use value::LittleEndianConvert;
|
||||||
|
|
||||||
/// Size of a page of [linear memory][`MemoryInstance`] - 64KiB.
|
/// Size of a page of [linear memory][`MemoryInstance`] - 64KiB.
|
||||||
///
|
///
|
||||||
|
@ -171,6 +172,13 @@ impl MemoryInstance {
|
||||||
Bytes(self.buffer.borrow().len()).round_up_to()
|
Bytes(self.buffer.borrow().len()).round_up_to()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get value from memory at given offset.
|
||||||
|
pub fn get_value<T: LittleEndianConvert>(&self, offset: u32) -> Result<T, Error> {
|
||||||
|
let buffer = self.buffer.borrow();
|
||||||
|
let region = self.checked_region(&buffer, offset as usize, ::std::mem::size_of::<T>())?;
|
||||||
|
Ok(T::from_little_endian(region.slice()).expect("Slice size is checked"))
|
||||||
|
}
|
||||||
|
|
||||||
/// Copy data from memory at given offset.
|
/// Copy data from memory at given offset.
|
||||||
///
|
///
|
||||||
/// This will allocate vector for you.
|
/// This will allocate vector for you.
|
||||||
|
@ -208,6 +216,14 @@ impl MemoryInstance {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Copy value in the memory at given offset.
|
||||||
|
pub fn set_value<T: LittleEndianConvert>(&self, offset: u32, value: T) -> Result<(), Error> {
|
||||||
|
let mut buffer = self.buffer.borrow_mut();
|
||||||
|
let range = self.checked_region(&buffer, offset as usize, ::std::mem::size_of::<T>())?.range();
|
||||||
|
value.into_little_endian(&mut buffer[range]);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Increases the size of the linear memory by given number of pages.
|
/// Increases the size of the linear memory by given number of pages.
|
||||||
/// Returns previous memory size if succeeds.
|
/// Returns previous memory size if succeeds.
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use std::mem;
|
|
||||||
use std::ops;
|
use std::ops;
|
||||||
use std::{u32, usize};
|
use std::{u32, usize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -615,10 +614,8 @@ impl Interpreter {
|
||||||
let m = context
|
let m = context
|
||||||
.memory()
|
.memory()
|
||||||
.expect("Due to validation memory should exists");
|
.expect("Due to validation memory should exists");
|
||||||
let b = m.get(address, mem::size_of::<T>())
|
let n: T = m.get_value(address)
|
||||||
.map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
|
.map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
|
||||||
let n = T::from_little_endian(&b)
|
|
||||||
.expect("Can't fail since buffer length should be size_of::<T>");
|
|
||||||
self.value_stack.push(n.into())?;
|
self.value_stack.push(n.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
@ -636,10 +633,8 @@ impl Interpreter {
|
||||||
let m = context
|
let m = context
|
||||||
.memory()
|
.memory()
|
||||||
.expect("Due to validation memory should exists");
|
.expect("Due to validation memory should exists");
|
||||||
let b = m.get(address, mem::size_of::<T>())
|
let v: T = m.get_value(address)
|
||||||
.map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
|
.map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
|
||||||
let v = T::from_little_endian(&b)
|
|
||||||
.expect("Can't fail since buffer length should be size_of::<T>");
|
|
||||||
let stack_value: U = v.extend_into();
|
let stack_value: U = v.extend_into();
|
||||||
self
|
self
|
||||||
.value_stack
|
.value_stack
|
||||||
|
@ -652,8 +647,7 @@ impl Interpreter {
|
||||||
where T: FromRuntimeValue, T: LittleEndianConvert {
|
where T: FromRuntimeValue, T: LittleEndianConvert {
|
||||||
let stack_value = self
|
let stack_value = self
|
||||||
.value_stack
|
.value_stack
|
||||||
.pop_as::<T>()
|
.pop_as::<T>();
|
||||||
.into_little_endian();
|
|
||||||
let raw_address = self
|
let raw_address = self
|
||||||
.value_stack
|
.value_stack
|
||||||
.pop_as::<u32>();
|
.pop_as::<u32>();
|
||||||
|
@ -666,7 +660,7 @@ impl Interpreter {
|
||||||
let m = context
|
let m = context
|
||||||
.memory()
|
.memory()
|
||||||
.expect("Due to validation memory should exists");
|
.expect("Due to validation memory should exists");
|
||||||
m.set(address, &stack_value)
|
m.set_value(address, stack_value)
|
||||||
.map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
|
.map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
@ -686,7 +680,7 @@ impl Interpreter {
|
||||||
.pop()
|
.pop()
|
||||||
.try_into()
|
.try_into()
|
||||||
.expect("Due to validation value should be of proper type");
|
.expect("Due to validation value should be of proper type");
|
||||||
let stack_value = stack_value.wrap_into().into_little_endian();
|
let stack_value = stack_value.wrap_into();
|
||||||
let raw_address = self
|
let raw_address = self
|
||||||
.value_stack
|
.value_stack
|
||||||
.pop_as::<u32>();
|
.pop_as::<u32>();
|
||||||
|
@ -698,7 +692,7 @@ impl Interpreter {
|
||||||
let m = context
|
let m = context
|
||||||
.memory()
|
.memory()
|
||||||
.expect("Due to validation memory should exists");
|
.expect("Due to validation memory should exists");
|
||||||
m.set(address, &stack_value)
|
m.set_value(address, stack_value)
|
||||||
.map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
|
.map_err(|_| TrapKind::MemoryAccessOutOfBounds)?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
60
src/value.rs
60
src/value.rs
|
@ -75,7 +75,7 @@ pub trait TransmuteInto<T> {
|
||||||
/// Convert from and to little endian.
|
/// Convert from and to little endian.
|
||||||
pub trait LittleEndianConvert where Self: Sized {
|
pub trait LittleEndianConvert where Self: Sized {
|
||||||
/// Convert to little endian buffer.
|
/// Convert to little endian buffer.
|
||||||
fn into_little_endian(self) -> Vec<u8>;
|
fn into_little_endian(self, buffer: &mut[u8]);
|
||||||
/// Convert from little endian buffer.
|
/// Convert from little endian buffer.
|
||||||
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error>;
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error>;
|
||||||
}
|
}
|
||||||
|
@ -555,8 +555,8 @@ impl TransmuteInto<i64> for u64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LittleEndianConvert for i8 {
|
impl LittleEndianConvert for i8 {
|
||||||
fn into_little_endian(self) -> Vec<u8> {
|
fn into_little_endian(self, buffer: &mut[u8]) {
|
||||||
vec![self as u8]
|
buffer[0] = self as u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
||||||
|
@ -567,8 +567,8 @@ impl LittleEndianConvert for i8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LittleEndianConvert for u8 {
|
impl LittleEndianConvert for u8 {
|
||||||
fn into_little_endian(self) -> Vec<u8> {
|
fn into_little_endian(self, buffer: &mut[u8]) {
|
||||||
vec![self]
|
buffer[0] = self;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
||||||
|
@ -579,11 +579,9 @@ impl LittleEndianConvert for u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LittleEndianConvert for i16 {
|
impl LittleEndianConvert for i16 {
|
||||||
fn into_little_endian(self) -> Vec<u8> {
|
fn into_little_endian(self, mut buffer: &mut[u8]) {
|
||||||
let mut vec = Vec::with_capacity(2);
|
buffer.write_i16::<LittleEndian>(self)
|
||||||
vec.write_i16::<LittleEndian>(self)
|
|
||||||
.expect("i16 is written without any errors");
|
.expect("i16 is written without any errors");
|
||||||
vec
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
||||||
|
@ -593,11 +591,9 @@ impl LittleEndianConvert for i16 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LittleEndianConvert for u16 {
|
impl LittleEndianConvert for u16 {
|
||||||
fn into_little_endian(self) -> Vec<u8> {
|
fn into_little_endian(self, mut buffer: &mut[u8]) {
|
||||||
let mut vec = Vec::with_capacity(2);
|
buffer.write_u16::<LittleEndian>(self)
|
||||||
vec.write_u16::<LittleEndian>(self)
|
|
||||||
.expect("u16 is written without any errors");
|
.expect("u16 is written without any errors");
|
||||||
vec
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
||||||
|
@ -607,11 +603,9 @@ impl LittleEndianConvert for u16 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LittleEndianConvert for i32 {
|
impl LittleEndianConvert for i32 {
|
||||||
fn into_little_endian(self) -> Vec<u8> {
|
fn into_little_endian(self, mut buffer: &mut[u8]) {
|
||||||
let mut vec = Vec::with_capacity(4);
|
buffer.write_i32::<LittleEndian>(self)
|
||||||
vec.write_i32::<LittleEndian>(self)
|
|
||||||
.expect("i32 is written without any errors");
|
.expect("i32 is written without any errors");
|
||||||
vec
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
||||||
|
@ -621,11 +615,9 @@ impl LittleEndianConvert for i32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LittleEndianConvert for u32 {
|
impl LittleEndianConvert for u32 {
|
||||||
fn into_little_endian(self) -> Vec<u8> {
|
fn into_little_endian(self, mut buffer: &mut[u8]) {
|
||||||
let mut vec = Vec::with_capacity(4);
|
buffer.write_u32::<LittleEndian>(self)
|
||||||
vec.write_u32::<LittleEndian>(self)
|
|
||||||
.expect("u32 is written without any errors");
|
.expect("u32 is written without any errors");
|
||||||
vec
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
||||||
|
@ -635,11 +627,9 @@ impl LittleEndianConvert for u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LittleEndianConvert for i64 {
|
impl LittleEndianConvert for i64 {
|
||||||
fn into_little_endian(self) -> Vec<u8> {
|
fn into_little_endian(self, mut buffer: &mut[u8]) {
|
||||||
let mut vec = Vec::with_capacity(8);
|
buffer.write_i64::<LittleEndian>(self)
|
||||||
vec.write_i64::<LittleEndian>(self)
|
|
||||||
.expect("i64 is written without any errors");
|
.expect("i64 is written without any errors");
|
||||||
vec
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
||||||
|
@ -649,11 +639,9 @@ impl LittleEndianConvert for i64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LittleEndianConvert for f32 {
|
impl LittleEndianConvert for f32 {
|
||||||
fn into_little_endian(self) -> Vec<u8> {
|
fn into_little_endian(self, mut buffer: &mut[u8]) {
|
||||||
let mut vec = Vec::with_capacity(4);
|
buffer.write_f32::<LittleEndian>(self)
|
||||||
vec.write_f32::<LittleEndian>(self)
|
|
||||||
.expect("f32 is written without any errors");
|
.expect("f32 is written without any errors");
|
||||||
vec
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
||||||
|
@ -664,11 +652,9 @@ impl LittleEndianConvert for f32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LittleEndianConvert for f64 {
|
impl LittleEndianConvert for f64 {
|
||||||
fn into_little_endian(self) -> Vec<u8> {
|
fn into_little_endian(self, mut buffer: &mut[u8]) {
|
||||||
let mut vec = Vec::with_capacity(8);
|
buffer.write_f64::<LittleEndian>(self)
|
||||||
vec.write_f64::<LittleEndian>(self)
|
|
||||||
.expect("i64 is written without any errors");
|
.expect("i64 is written without any errors");
|
||||||
vec
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
||||||
|
@ -679,8 +665,8 @@ impl LittleEndianConvert for f64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LittleEndianConvert for F32 {
|
impl LittleEndianConvert for F32 {
|
||||||
fn into_little_endian(self) -> Vec<u8> {
|
fn into_little_endian(self, buffer: &mut[u8]) {
|
||||||
(self.to_bits() as i32).into_little_endian()
|
(self.to_bits() as i32).into_little_endian(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
||||||
|
@ -689,8 +675,8 @@ impl LittleEndianConvert for F32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LittleEndianConvert for F64 {
|
impl LittleEndianConvert for F64 {
|
||||||
fn into_little_endian(self) -> Vec<u8> {
|
fn into_little_endian(self, buffer: &mut[u8]) {
|
||||||
(self.to_bits() as i64).into_little_endian()
|
(self.to_bits() as i64).into_little_endian(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
||||||
|
|
Loading…
Reference in New Issue