From 68925b62a1bae0be50bffdf24a9bd7e89a146445 Mon Sep 17 00:00:00 2001 From: Sergey Pepyakin Date: Tue, 2 Jul 2019 20:33:26 +0200 Subject: [PATCH] Refactor. --- src/{memory.rs => memory/mod.rs} | 102 ++---------------------------- src/memory/rust_alloc.rs | 104 +++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 97 deletions(-) rename src/{memory.rs => memory/mod.rs} (90%) create mode 100644 src/memory/rust_alloc.rs diff --git a/src/memory.rs b/src/memory/mod.rs similarity index 90% rename from src/memory.rs rename to src/memory/mod.rs index 2a3a36b..6274084 100644 --- a/src/memory.rs +++ b/src/memory/mod.rs @@ -12,9 +12,6 @@ use parity_wasm::elements::ResizableLimits; use value::LittleEndianConvert; use Error; -use std::alloc::{System, Layout, GlobalAlloc}; -use std::{slice, ptr}; - /// Size of a page of [linear memory][`MemoryInstance`] - 64KiB. /// /// The size of a memory is always a integer multiple of a page size. @@ -72,100 +69,8 @@ impl fmt::Debug for MemoryInstance { } } -struct ByteBuf { - ptr: *mut u8, - len: usize, -} - -impl ByteBuf { - fn layout(len: usize) -> Layout { - Layout::from_size_align(len, 1).expect("") - } - - pub fn new(len: usize) -> Self { - let ptr = if len == 0 { - ptr::null_mut() - } else { - // Alignment of byte is 1. - // TODO: proof - - let ptr = unsafe { - // TODO: proof - System.alloc_zeroed(Self::layout(len)) - }; - - // TODO: proof - assert!(!ptr.is_null()); - - ptr - }; - - Self { - ptr, - len, - } - } - - pub fn realloc(&mut self, new_len: usize) { - let new_ptr = if self.len == 0 { - // special case, when the memory wasn't allocated before. - // Alignment of byte is 1. - // TODO: proof - let ptr = unsafe { - // TODO: proof - System.alloc_zeroed(Self::layout(new_len)) - }; - - // TODO: proof - assert!(!ptr.is_null()); - - ptr - } else { - // TODO: proof - let cur_layout = Self::layout(self.len); - let new_ptr = unsafe { - System.realloc(self.ptr, cur_layout, new_len) - }; - assert!(!new_ptr.is_null()); - - unsafe { - let new_area = new_ptr.offset(self.len as isize); - ptr::write_bytes(new_area, 0, new_len - self.len); - } - - new_ptr - }; - - self.ptr = new_ptr; - self.len = new_len; - } - - pub fn len(&self) -> usize { - self.len - } - - pub fn as_slice(&self) -> &[u8] { - unsafe { - slice::from_raw_parts(self.ptr, self.len) - } - } - - pub fn as_slice_mut(&mut self) -> &mut [u8] { - unsafe { - slice::from_raw_parts_mut(self.ptr, self.len) - } - } -} - -impl Drop for ByteBuf { - fn drop(&mut self) { - if self.len != 0 { - unsafe { - System.dealloc(self.ptr, Self::layout(self.len)) - } - } - } -} +mod rust_alloc; +use self::rust_alloc::ByteBuf; struct CheckedRegion { offset: usize, @@ -579,6 +484,9 @@ impl MemoryInstance { self.clear(offset, 0, len) } + /// Set every byte in the entire linear memory to 0. + /// + /// Might be useful for some optimization shenanigans. pub fn erase(&self) { let cur_size = self.buffer.borrow().len(); *self.buffer.borrow_mut() = ByteBuf::new(cur_size); diff --git a/src/memory/rust_alloc.rs b/src/memory/rust_alloc.rs new file mode 100644 index 0000000..bde6df8 --- /dev/null +++ b/src/memory/rust_alloc.rs @@ -0,0 +1,104 @@ +//! An implementation of a `ByteBuf` based on Rust's `GlobalAlloc`. +//! +//! The performance of this is really depends on the underlying allocator implementation, +//! specifically on `alloc_zeroed`. On macOS, for example, it calls to `bzero` which +//! can ruin the performance for some workloads. + +use std::alloc::{System, Layout, GlobalAlloc}; +use std::{slice, ptr}; + +pub struct ByteBuf { + // If the `len` is 0, this would store a dangling pointer but not `null`. + ptr: *mut u8, + len: usize, +} + +impl ByteBuf { + pub fn new(len: usize) -> Self { + let ptr = if len == 0 { + // Craft a pointer which is not null, but + ptr::NonNull::dangling().as_ptr() + } else { + let ptr = unsafe { + // TODO: proof + System.alloc_zeroed(Self::layout(len)) + }; + + // TODO: proof + assert!(!ptr.is_null()); + + ptr + }; + + Self { + ptr, + len, + } + } + + pub fn realloc(&mut self, new_len: usize) { + let new_ptr = if self.len == 0 { + // special case, when the memory wasn't allocated before. + // Alignment of byte is 1. + // TODO: proof + let ptr = unsafe { + // TODO: proof + System.alloc_zeroed(Self::layout(new_len)) + }; + + // TODO: proof + assert!(!ptr.is_null()); + + ptr + } else { + // TODO: proof + let cur_layout = Self::layout(self.len); + let new_ptr = unsafe { + System.realloc(self.ptr, cur_layout, new_len) + }; + assert!(!new_ptr.is_null()); + + unsafe { + let new_area = new_ptr.offset(self.len as isize); + ptr::write_bytes(new_area, 0, new_len - self.len); + } + + new_ptr + }; + + self.ptr = new_ptr; + self.len = new_len; + } + + pub fn len(&self) -> usize { + self.len + } + + pub fn as_slice(&self) -> &[u8] { + unsafe { + // + slice::from_raw_parts(self.ptr, self.len) + } + } + + pub fn as_slice_mut(&mut self) -> &mut [u8] { + unsafe { + // TODO: zero sized. + slice::from_raw_parts_mut(self.ptr, self.len) + } + } + + fn layout(len: usize) -> Layout { + Layout::from_size_align(len, 1).expect("") + } +} + +impl Drop for ByteBuf { + fn drop(&mut self) { + if self.len != 0 { + unsafe { + System.dealloc(self.ptr, Self::layout(self.len)) + } + } + } +}