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;
|
2018-10-18 19:01:09 +02:00
|
|
|
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.
|
|
|
|
///
|
|
|
|
pub struct LinearMemory {
|
2018-10-28 22:00:04 +01:00
|
|
|
pub mmap: MmapMut,
|
2018-10-14 22:10:53 +02:00
|
|
|
// The initial size of the WebAssembly Memory, in units of
|
|
|
|
// WebAssembly pages.
|
2018-11-07 11:18:55 +01:00
|
|
|
pub current: u32,
|
2018-10-14 22:10:53 +02:00
|
|
|
// 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-11-16 16:55:49 +01:00
|
|
|
pub maximum: Option<u32>,
|
2018-10-13 19:22:57 +02:00
|
|
|
}
|
|
|
|
|
2018-10-14 22:10:53 +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
|
2018-11-16 16:55:49 +01:00
|
|
|
pub const DEFAULT_SIZE: usize = Self::DEFAULT_HEAP_SIZE + Self::DEFAULT_GUARD_SIZE; // 6 GiB
|
2018-10-26 14:53:33 +02:00
|
|
|
|
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-18 00:09:04 +02:00
|
|
|
|
2018-11-16 16:55:49 +01:00
|
|
|
// TODO: Investigate if memory is zeroed out
|
|
|
|
let mmap = MmapMut::map_anon(LinearMemory::DEFAULT_HEAP_SIZE).unwrap();
|
2018-10-18 00:09:04 +02:00
|
|
|
|
2018-10-15 02:48:59 +02:00
|
|
|
debug!("LinearMemory instantiated");
|
2018-10-11 21:29:36 +02:00
|
|
|
Self {
|
2018-10-14 13:59:11 +02:00
|
|
|
mmap,
|
|
|
|
current: initial,
|
|
|
|
maximum,
|
2018-10-11 21:29:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-11 21:29:36 +02:00
|
|
|
}
|
|
|
|
|
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.
|
2018-10-18 19:01:09 +02:00
|
|
|
pub fn grow(&mut self, add_pages: u32) -> Option<i32> {
|
2018-11-06 13:18:16 +01:00
|
|
|
debug!("grow_memory called!");
|
2018-11-06 18:19:20 +01:00
|
|
|
debug!("old memory = {:?}", self.mmap);
|
2018-11-06 13:18:16 +01:00
|
|
|
let prev_pages = self.current;
|
|
|
|
|
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-11 21:29:36 +02:00
|
|
|
};
|
2018-11-06 13:18:16 +01:00
|
|
|
|
2018-10-14 13:59:11 +02:00
|
|
|
if let Some(val) = self.maximum {
|
|
|
|
if new_pages > val {
|
|
|
|
return None;
|
|
|
|
}
|
2018-11-06 13:18:16 +01:00
|
|
|
// Wasm linear memories are never allowed to grow beyond what is
|
|
|
|
// indexable. If the memory has no maximum, enforce the greatest
|
|
|
|
// limit here.
|
|
|
|
} else if new_pages >= 65536 {
|
|
|
|
return None;
|
2018-10-11 21:29:36 +02:00
|
|
|
}
|
|
|
|
|
2018-11-06 13:18:16 +01:00
|
|
|
let prev_bytes = self.mmap.len();
|
2018-10-14 13:59:11 +02:00
|
|
|
let new_bytes = (new_pages * PAGE_SIZE) as usize;
|
2018-10-11 21:29:36 +02:00
|
|
|
|
2018-11-06 13:18:16 +01:00
|
|
|
// Updating self.mmap if new_bytes > prev_bytes
|
|
|
|
if new_bytes > prev_bytes {
|
2018-11-06 18:19:20 +01:00
|
|
|
debug!("new memory = {:?}", self.mmap);
|
2018-10-11 21:29:36 +02:00
|
|
|
}
|
|
|
|
|
2018-11-16 16:55:49 +01:00
|
|
|
self.current = new_pages;
|
|
|
|
|
2018-10-18 19:01:09 +02:00
|
|
|
Some(prev_pages as i32)
|
2018-10-11 21:29:36 +02:00
|
|
|
}
|
2018-10-29 12:29:44 +01:00
|
|
|
|
|
|
|
pub fn carve_slice(&self, offset: u32, size: u32) -> Option<&[u8]> {
|
|
|
|
let start = offset as usize;
|
|
|
|
let end = start + size as usize;
|
|
|
|
let slice: &[u8] = &*self;
|
|
|
|
|
|
|
|
// if end <= self.mapped_size() {
|
|
|
|
Some(&slice[start..end])
|
|
|
|
// } else {
|
|
|
|
// None
|
|
|
|
// }
|
|
|
|
}
|
2018-10-14 13:59:11 +02:00
|
|
|
}
|
2018-10-11 21:29:36 +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")
|
2018-11-06 13:18:16 +01:00
|
|
|
.field("mmap", &self.mmap)
|
2018-10-14 13:59:11 +02:00
|
|
|
.field("current", &self.current)
|
|
|
|
.field("maximum", &self.maximum)
|
|
|
|
.finish()
|
2018-10-11 21:29:36 +02:00
|
|
|
}
|
2018-10-14 13:59:11 +02:00
|
|
|
}
|
2018-10-11 21:29:36 +02:00
|
|
|
|
2018-11-16 16:55:49 +01:00
|
|
|
// Not comparing based on memory content. That would be inefficient.
|
|
|
|
impl PartialEq for LinearMemory {
|
|
|
|
fn eq(&self, other: &LinearMemory) -> bool {
|
|
|
|
self.current == other.current &&
|
|
|
|
self.maximum == other.maximum
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-14 13:59:11 +02:00
|
|
|
impl AsRef<[u8]> for LinearMemory {
|
|
|
|
fn as_ref(&self) -> &[u8] {
|
|
|
|
&self.mmap
|
2018-10-11 21:29:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-14 13:59:11 +02:00
|
|
|
impl AsMut<[u8]> for LinearMemory {
|
|
|
|
fn as_mut(&mut self) -> &mut [u8] {
|
|
|
|
&mut self.mmap
|
2018-10-11 21:29:36 +02:00
|
|
|
}
|
|
|
|
}
|
2018-10-18 19:01:09 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
2018-10-29 12:29:44 +01:00
|
|
|
|
|
|
|
// impl Clone for LinearMemory {
|
|
|
|
// fn clone(&self) -> LinearMemory {
|
|
|
|
// let mut mmap = MmapMut::map_anon(self.maximum.unwrap_or(self.current) as usize).unwrap();
|
|
|
|
// let mut base_mmap = &self.mmap;
|
|
|
|
// let to_init = &mut mmap[0..self.current as usize];
|
|
|
|
// to_init.copy_from_slice(&self.mmap);
|
|
|
|
|
|
|
|
// return LinearMemory {
|
|
|
|
// mmap: mmap,
|
|
|
|
// current: self.current,
|
|
|
|
// maximum: self.maximum,
|
|
|
|
// };
|
|
|
|
// }
|
|
|
|
// }
|