Files
wasmer/src/webassembly/memory.rs

154 lines
4.8 KiB
Rust
Raw Normal View History

2018-10-24 11:47:12 +02:00
//! The webassembly::Memory() constructor creates a new Memory object which is
//! a structure that holds the raw bytes of memory accessed by a
//! webassembly::Instance.
//! A memory created by Rust or in WebAssembly code will be accessible and
//! mutable from both Rust and WebAssembly.
2018-10-15 02:48:59 +02:00
use memmap::MmapMut;
2018-10-14 13:59:11 +02:00
use std::fmt;
use std::ops::{Deref, DerefMut};
2018-10-14 13:59:11 +02:00
const PAGE_SIZE: u32 = 65536;
const MAX_PAGES: u32 = 65536;
/// A linear memory instance.
///
/// This linear memory has a stable base address and at the same time allows
/// for dynamical growing.
pub struct LinearMemory {
pub mmap: MmapMut,
// The initial size of the WebAssembly Memory, in units of
// WebAssembly pages.
2018-10-14 13:59:11 +02:00
current: u32,
// The maximum size the WebAssembly Memory is allowed to grow
// to, in units of WebAssembly pages. When present, the maximum
// parameter acts as a hint to the engine to reserve memory up
// front. However, the engine may ignore or clamp this reservation
// request. In general, most WebAssembly modules shouldn't need
// to set a maximum.
2018-10-14 13:59:11 +02:00
maximum: Option<u32>,
2018-10-13 19:22:57 +02:00
}
/// It holds the raw bytes of memory accessed by a WebAssembly Instance
2018-10-14 13:59:11 +02:00
impl LinearMemory {
2018-10-26 14:53:33 +02:00
pub const WASM_PAGE_SIZE: usize = 1 << 16; // 64 KiB
pub const DEFAULT_HEAP_SIZE: usize = 1 << 32; // 4 GiB
pub const DEFAULT_GUARD_SIZE: usize = 1 << 31; // 2 GiB
pub const DEFAULT_SIZE: usize = Self::DEFAULT_HEAP_SIZE + Self::DEFAULT_GUARD_SIZE; // 8GiB
2018-10-14 13:59:11 +02:00
/// Create a new linear memory instance with specified initial and maximum number of pages.
///
/// `maximum` cannot be set to more than `65536` pages.
pub fn new(initial: u32, maximum: Option<u32>) -> Self {
assert!(initial <= MAX_PAGES);
assert!(maximum.is_none() || maximum.unwrap() <= MAX_PAGES);
2018-10-15 03:03:00 +02:00
debug!(
"Instantiate LinearMemory(initial={:?}, maximum={:?})",
initial, maximum
);
2018-10-24 11:43:18 +02:00
let len: u64 = PAGE_SIZE as u64 * match maximum {
Some(val) => val as u64,
None => initial as u64,
};
2018-10-19 01:28:16 +02:00
let len = if len == 0 { PAGE_SIZE as u64 } else { len };
2018-10-15 02:48:59 +02:00
let mmap = MmapMut::map_anon(len as usize).unwrap();
debug!("LinearMemory instantiated");
Self {
2018-10-14 13:59:11 +02:00
mmap,
current: initial,
maximum,
}
}
2018-10-14 13:59:11 +02:00
/// Returns an base address of this linear memory.
pub fn base_addr(&mut self) -> *mut u8 {
self.mmap.as_mut_ptr()
}
2018-10-14 13:59:11 +02:00
/// Returns a number of allocated wasm pages.
pub fn current_size(&self) -> u32 {
self.current
}
2018-10-13 19:22:57 +02:00
2018-10-14 13:59:11 +02:00
/// Grow memory by the specified amount of pages.
///
/// Returns `None` if memory can't be grown by the specified amount
/// of pages.
pub fn grow(&mut self, add_pages: u32) -> Option<i32> {
2018-10-14 13:59:11 +02:00
let new_pages = match self.current.checked_add(add_pages) {
Some(new_pages) => new_pages,
None => return None,
};
2018-10-14 13:59:11 +02:00
if let Some(val) = self.maximum {
if new_pages > val {
return None;
}
} else {
2018-10-14 13:59:11 +02:00
// Wasm linear memories are never allowed to grow beyond what is
// indexable. If the memory has no maximum, enforce the greatest
// limit here.
if new_pages >= 65536 {
return None;
}
}
2018-10-14 13:59:11 +02:00
let prev_pages = self.current;
let new_bytes = (new_pages * PAGE_SIZE) as usize;
2018-10-14 13:59:11 +02:00
if self.mmap.len() < new_bytes {
// If we have no maximum, this is a "dynamic" heap, and it's allowed
// to move.
assert!(self.maximum.is_none());
2018-10-15 02:48:59 +02:00
let mut new_mmap = MmapMut::map_anon(new_bytes).unwrap();
2018-10-14 13:59:11 +02:00
new_mmap.copy_from_slice(&self.mmap);
self.mmap = new_mmap;
}
2018-10-14 13:59:11 +02:00
self.current = new_pages;
2018-10-14 13:59:11 +02:00
// Ensure that newly allocated area is zeroed.
let new_start_offset = (prev_pages * PAGE_SIZE) as usize;
let new_end_offset = (new_pages * PAGE_SIZE) as usize;
for i in new_start_offset..new_end_offset {
assert!(self.mmap[i] == 0);
}
Some(prev_pages as i32)
}
2018-10-14 13:59:11 +02:00
}
2018-10-14 13:59:11 +02:00
impl fmt::Debug for LinearMemory {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("LinearMemory")
.field("current", &self.current)
.field("maximum", &self.maximum)
.finish()
}
2018-10-14 13:59:11 +02:00
}
2018-10-14 13:59:11 +02:00
impl AsRef<[u8]> for LinearMemory {
fn as_ref(&self) -> &[u8] {
&self.mmap
}
}
2018-10-14 13:59:11 +02:00
impl AsMut<[u8]> for LinearMemory {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.mmap
}
}
impl Deref for LinearMemory {
type Target = [u8];
fn deref(&self) -> &[u8] {
&*self.mmap
}
}
impl DerefMut for LinearMemory {
fn deref_mut(&mut self) -> &mut [u8] {
&mut *self.mmap
}
}