mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-26 15:11:37 +00:00
Implement shared static memory similarly to unshared static memory.
This commit is contained in:
@ -12,12 +12,15 @@ use std::{
|
|||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
fmt, mem,
|
fmt, mem,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use self::dynamic::DynamicMemory;
|
pub use self::dynamic::DynamicMemory;
|
||||||
pub use self::static_::{SharedStaticMemory, StaticMemory};
|
pub use self::static_::StaticMemory;
|
||||||
pub use self::view::{Atomically, MemoryView};
|
pub use self::view::{Atomically, MemoryView};
|
||||||
|
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
mod dynamic;
|
mod dynamic;
|
||||||
pub mod ptr;
|
pub mod ptr;
|
||||||
mod static_;
|
mod static_;
|
||||||
@ -151,20 +154,10 @@ impl Memory {
|
|||||||
unsafe { MemoryView::new(base as _, length as u32) }
|
unsafe { MemoryView::new(base as _, length as u32) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert this memory to a shared memory if the shared flag
|
|
||||||
/// is present in the description used to create it.
|
|
||||||
pub fn shared(self) -> Option<SharedMemory> {
|
|
||||||
if self.desc.shared {
|
|
||||||
Some(SharedMemory { desc: self.desc })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn vm_local_memory(&self) -> *mut vm::LocalMemory {
|
pub(crate) fn vm_local_memory(&self) -> *mut vm::LocalMemory {
|
||||||
match &self.variant {
|
match &self.variant {
|
||||||
MemoryVariant::Unshared(unshared_mem) => unshared_mem.vm_local_memory(),
|
MemoryVariant::Unshared(unshared_mem) => unshared_mem.vm_local_memory(),
|
||||||
MemoryVariant::Shared(_) => unimplemented!(),
|
MemoryVariant::Shared(shared_mem) => shared_mem.vm_local_memory(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,7 +234,7 @@ impl UnsharedMemory {
|
|||||||
MemoryType::SharedStatic => panic!("attempting to create shared unshared memory"),
|
MemoryType::SharedStatic => panic!("attempting to create shared unshared memory"),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(UnsharedMemory {
|
Ok(Self {
|
||||||
internal: Rc::new(UnsharedMemoryInternal {
|
internal: Rc::new(UnsharedMemoryInternal {
|
||||||
storage: RefCell::new(storage),
|
storage: RefCell::new(storage),
|
||||||
local: Cell::new(local),
|
local: Cell::new(local),
|
||||||
@ -289,27 +282,56 @@ impl Clone for UnsharedMemory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct SharedMemory {
|
pub struct SharedMemory {
|
||||||
#[allow(dead_code)]
|
internal: Arc<SharedMemoryInternal>,
|
||||||
desc: MemoryDescriptor,
|
}
|
||||||
|
|
||||||
|
pub struct SharedMemoryInternal {
|
||||||
|
memory: RefCell<Box<StaticMemory>>,
|
||||||
|
local: Cell<vm::LocalMemory>,
|
||||||
|
lock: Mutex<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SharedMemory {
|
impl SharedMemory {
|
||||||
fn new(desc: MemoryDescriptor) -> Result<Self, CreationError> {
|
fn new(desc: MemoryDescriptor) -> Result<Self, CreationError> {
|
||||||
Ok(Self { desc })
|
let mut local = vm::LocalMemory {
|
||||||
|
base: std::ptr::null_mut(),
|
||||||
|
bound: 0,
|
||||||
|
memory: std::ptr::null_mut(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let memory = StaticMemory::new(desc, &mut local)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
internal: Arc::new(SharedMemoryInternal {
|
||||||
|
memory: RefCell::new(memory),
|
||||||
|
local: Cell::new(local),
|
||||||
|
lock: Mutex::new(()),
|
||||||
|
}),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn grow(&self, _delta: Pages) -> Result<Pages, GrowError> {
|
pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
|
||||||
unimplemented!()
|
let _guard = self.internal.lock.lock();
|
||||||
|
let mut local = self.internal.local.get();
|
||||||
|
let pages = self.internal.memory.borrow_mut().grow(delta, &mut local);
|
||||||
|
pages
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size(&self) -> Pages {
|
pub fn size(&self) -> Pages {
|
||||||
unimplemented!()
|
let _guard = self.internal.lock.lock();
|
||||||
|
self.internal.memory.borrow_mut().size()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn vm_local_memory(&self) -> *mut vm::LocalMemory {
|
||||||
|
self.internal.local.as_ptr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for SharedMemory {
|
impl Clone for SharedMemory {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
unimplemented!()
|
SharedMemory {
|
||||||
|
internal: Arc::clone(&self.internal),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,8 +3,6 @@ pub const SAFE_STATIC_HEAP_SIZE: usize = 1 << 32; // 4 GiB
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub const SAFE_STATIC_GUARD_SIZE: usize = 1 << 31; // 2 GiB
|
pub const SAFE_STATIC_GUARD_SIZE: usize = 1 << 31; // 2 GiB
|
||||||
|
|
||||||
mod shared;
|
|
||||||
mod unshared;
|
mod unshared;
|
||||||
|
|
||||||
pub use self::shared::SharedStaticMemory;
|
|
||||||
pub use self::unshared::StaticMemory;
|
pub use self::unshared::StaticMemory;
|
||||||
|
@ -1,11 +1,110 @@
|
|||||||
use crate::sys;
|
/*use crate::error::GrowError;
|
||||||
use parking_lot::Mutex;
|
use crate::{
|
||||||
use std::sync::atomic::AtomicUsize;
|
error::CreationError,
|
||||||
|
memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE},
|
||||||
|
sys,
|
||||||
|
types::MemoryDescriptor,
|
||||||
|
units::Pages,
|
||||||
|
vm,
|
||||||
|
};
|
||||||
|
|
||||||
// Remove this attribute once this is used.
|
use parking_lot::{Mutex, MutexGuard};
|
||||||
#[allow(dead_code)]
|
|
||||||
|
/// This is an internal-only api.
|
||||||
|
///
|
||||||
|
/// A static memory allocates 6GB of *virtual* memory when created
|
||||||
|
/// in order to allow the WebAssembly module to contain no bounds-checks.
|
||||||
|
///
|
||||||
|
/// Additionally, static memories stay at a single virtual address, so there is no need
|
||||||
|
/// to reload its address on each use.
|
||||||
|
///
|
||||||
|
/// Static memories take a relatively long time to create, so if memories are short-lived,
|
||||||
|
/// it's recommended that a dynamic memory is used. There is currently no user-facing api that
|
||||||
|
/// allows them to select the type of memory used however.
|
||||||
pub struct SharedStaticMemory {
|
pub struct SharedStaticMemory {
|
||||||
memory: sys::Memory,
|
memory: sys::Memory,
|
||||||
current: AtomicUsize,
|
current: Pages,
|
||||||
lock: Mutex<()>,
|
max: Option<Pages>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SharedStaticMemory {
|
||||||
|
pub(in crate::memory) fn new(
|
||||||
|
desc: MemoryDescriptor,
|
||||||
|
local: &mut vm::LocalMemory,
|
||||||
|
) -> Result<Box<Self>, CreationError> {
|
||||||
|
let memory = {
|
||||||
|
let mut memory = sys::Memory::with_size(SAFE_STATIC_HEAP_SIZE + SAFE_STATIC_GUARD_SIZE)
|
||||||
|
.map_err(|_| CreationError::UnableToCreateMemory)?;
|
||||||
|
if desc.minimum != Pages(0) {
|
||||||
|
unsafe {
|
||||||
|
memory
|
||||||
|
.protect(0..desc.minimum.bytes().0, sys::Protect::ReadWrite)
|
||||||
|
.map_err(|_| CreationError::UnableToCreateMemory)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memory
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut storage = Box::new(SharedStaticMemory {
|
||||||
|
memory,
|
||||||
|
current: desc.minimum,
|
||||||
|
max: desc.maximum,
|
||||||
|
lock: Mutex::new(()),
|
||||||
|
});
|
||||||
|
let storage_ptr: *mut SharedStaticMemory = &mut *storage;
|
||||||
|
|
||||||
|
local.base = storage.memory.as_ptr();
|
||||||
|
local.bound = desc.minimum.bytes().0;
|
||||||
|
local.memory = storage_ptr as *mut ();
|
||||||
|
|
||||||
|
Ok(storage)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lock(&mut self) -> MutexGuard<()> {
|
||||||
|
self.lock.lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self, _: &MutexGuard<()>) -> Pages {
|
||||||
|
self.current
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory, _: &MutexGuard<()>) -> Result<Pages, GrowError> {
|
||||||
|
let new_pages = self.current.checked_add(delta).map_err(|e| e.into())?;
|
||||||
|
|
||||||
|
if let Some(max) = self.max {
|
||||||
|
if new_pages > max {
|
||||||
|
return Err(GrowError::ExceededMaxPagesForMemory(
|
||||||
|
new_pages.0 as usize,
|
||||||
|
max.0 as usize,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = unsafe {
|
||||||
|
self.memory
|
||||||
|
.protect(
|
||||||
|
self.current.bytes().0..new_pages.bytes().0,
|
||||||
|
sys::Protect::ReadWrite,
|
||||||
|
)
|
||||||
|
.map_err(|e| e.into())
|
||||||
|
}?;
|
||||||
|
|
||||||
|
local.bound = new_pages.bytes().0;
|
||||||
|
|
||||||
|
let old_pages = self.current;
|
||||||
|
|
||||||
|
self.current = new_pages;
|
||||||
|
|
||||||
|
Ok(old_pages)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
|
unsafe { &self.memory.as_slice()[0..self.current.bytes().0] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_slice_mut(&mut self) -> &mut [u8] {
|
||||||
|
unsafe { &mut self.memory.as_slice_mut()[0..self.current.bytes().0] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
Reference in New Issue
Block a user