mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-26 07:01:33 +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},
|
||||
fmt, mem,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
pub use self::dynamic::DynamicMemory;
|
||||
pub use self::static_::{SharedStaticMemory, StaticMemory};
|
||||
pub use self::static_::StaticMemory;
|
||||
pub use self::view::{Atomically, MemoryView};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
mod dynamic;
|
||||
pub mod ptr;
|
||||
mod static_;
|
||||
@ -151,20 +154,10 @@ impl Memory {
|
||||
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 {
|
||||
match &self.variant {
|
||||
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"),
|
||||
};
|
||||
|
||||
Ok(UnsharedMemory {
|
||||
Ok(Self {
|
||||
internal: Rc::new(UnsharedMemoryInternal {
|
||||
storage: RefCell::new(storage),
|
||||
local: Cell::new(local),
|
||||
@ -289,27 +282,56 @@ impl Clone for UnsharedMemory {
|
||||
}
|
||||
|
||||
pub struct SharedMemory {
|
||||
#[allow(dead_code)]
|
||||
desc: MemoryDescriptor,
|
||||
internal: Arc<SharedMemoryInternal>,
|
||||
}
|
||||
|
||||
pub struct SharedMemoryInternal {
|
||||
memory: RefCell<Box<StaticMemory>>,
|
||||
local: Cell<vm::LocalMemory>,
|
||||
lock: Mutex<()>,
|
||||
}
|
||||
|
||||
impl SharedMemory {
|
||||
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> {
|
||||
unimplemented!()
|
||||
pub fn grow(&self, delta: Pages) -> Result<Pages, GrowError> {
|
||||
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 {
|
||||
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 {
|
||||
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)]
|
||||
pub const SAFE_STATIC_GUARD_SIZE: usize = 1 << 31; // 2 GiB
|
||||
|
||||
mod shared;
|
||||
mod unshared;
|
||||
|
||||
pub use self::shared::SharedStaticMemory;
|
||||
pub use self::unshared::StaticMemory;
|
||||
|
@ -1,11 +1,110 @@
|
||||
use crate::sys;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
/*use crate::error::GrowError;
|
||||
use crate::{
|
||||
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.
|
||||
#[allow(dead_code)]
|
||||
use parking_lot::{Mutex, MutexGuard};
|
||||
|
||||
/// 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 {
|
||||
memory: sys::Memory,
|
||||
current: AtomicUsize,
|
||||
lock: Mutex<()>,
|
||||
current: Pages,
|
||||
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