#[cfg(feature = "wasm-c-api")]
use crate::c_api::externals::memory as memory_impl;
#[cfg(feature = "js")]
use crate::js::externals::memory as memory_impl;
#[cfg(feature = "jsc")]
use crate::jsc::externals::memory as memory_impl;
#[cfg(feature = "sys")]
use crate::sys::externals::memory as memory_impl;
use super::memory_view::MemoryView;
use crate::exports::{ExportError, Exportable};
use crate::store::{AsStoreMut, AsStoreRef};
use crate::vm::{VMExtern, VMExternMemory, VMMemory};
use crate::MemoryAccessError;
use crate::MemoryType;
use crate::{AtomicsError, Extern};
use std::mem::MaybeUninit;
use wasmer_types::{MemoryError, Pages};
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
pub struct Memory(pub(crate) memory_impl::Memory);
impl Memory {
pub fn new(store: &mut impl AsStoreMut, ty: MemoryType) -> Result<Self, MemoryError> {
Ok(Self(memory_impl::Memory::new(store, ty)?))
}
pub fn new_from_existing(new_store: &mut impl AsStoreMut, memory: VMMemory) -> Self {
Self(memory_impl::Memory::new_from_existing(new_store, memory))
}
pub fn ty(&self, store: &impl AsStoreRef) -> MemoryType {
self.0.ty(store)
}
pub fn view<'a>(&self, store: &'a (impl AsStoreRef + ?Sized)) -> MemoryView<'a> {
MemoryView::new(self, store)
}
pub fn grow<IntoPages>(
&self,
store: &mut impl AsStoreMut,
delta: IntoPages,
) -> Result<Pages, MemoryError>
where
IntoPages: Into<Pages>,
{
self.0.grow(store, delta)
}
pub fn grow_at_least(
&self,
store: &mut impl AsStoreMut,
min_size: u64,
) -> Result<(), MemoryError> {
self.0.grow_at_least(store, min_size)
}
pub fn reset(&self, store: &mut impl AsStoreMut) -> Result<(), MemoryError> {
self.0.reset(store)?;
Ok(())
}
pub fn copy_to_store(
&self,
store: &impl AsStoreRef,
new_store: &mut impl AsStoreMut,
) -> Result<Self, MemoryError> {
if !self.ty(store).shared {
return Err(MemoryError::InvalidMemory {
reason: "memory is not a shared memory type".to_string(),
});
}
self.0
.try_copy(&store)
.map(|new_memory| Self::new_from_existing(new_store, new_memory.into()))
}
pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternMemory) -> Self {
Self(memory_impl::Memory::from_vm_extern(store, vm_extern))
}
pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
self.0.is_from_store(store)
}
pub fn try_clone(&self, store: &impl AsStoreRef) -> Result<VMMemory, MemoryError> {
self.0.try_clone(store)
}
pub fn share_in_store(
&self,
store: &impl AsStoreRef,
new_store: &mut impl AsStoreMut,
) -> Result<Self, MemoryError> {
if !self.ty(store).shared {
return Err(MemoryError::InvalidMemory {
reason: "memory is not a shared memory type".to_string(),
});
}
self.0
.try_clone(&store)
.map(|new_memory| Self::new_from_existing(new_store, new_memory))
}
pub fn as_shared(&self, store: &impl AsStoreRef) -> Option<SharedMemory> {
if !self.ty(store).shared {
return None;
}
self.0.as_shared(store)
}
pub(crate) fn to_vm_extern(&self) -> VMExtern {
self.0.to_vm_extern()
}
}
impl std::cmp::Eq for Memory {}
impl<'a> Exportable<'a> for Memory {
fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> {
match _extern {
Extern::Memory(memory) => Ok(memory),
_ => Err(ExportError::IncompatibleType),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MemoryLocation {
pub(crate) address: u32,
}
impl MemoryLocation {
pub fn new_32(address: u32) -> Self {
Self { address }
}
}
impl From<u32> for MemoryLocation {
fn from(value: u32) -> Self {
Self::new_32(value)
}
}
pub(crate) trait SharedMemoryOps {
fn disable_atomics(&self) -> Result<(), MemoryError> {
Err(MemoryError::AtomicsNotSupported)
}
fn wake_all_atomic_waiters(&self) -> Result<(), MemoryError> {
Err(MemoryError::AtomicsNotSupported)
}
fn notify(&self, _dst: MemoryLocation, _count: u32) -> Result<u32, AtomicsError> {
Err(AtomicsError::Unimplemented)
}
fn wait(
&self,
_dst: MemoryLocation,
_timeout: Option<std::time::Duration>,
) -> Result<u32, AtomicsError> {
Err(AtomicsError::Unimplemented)
}
}
#[derive(Clone)]
pub struct SharedMemory {
memory: Memory,
ops: std::sync::Arc<dyn SharedMemoryOps + Send + Sync>,
}
impl std::fmt::Debug for SharedMemory {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SharedMemory").finish()
}
}
impl SharedMemory {
pub fn memory(&self) -> &Memory {
&self.memory
}
#[allow(unused)]
pub(crate) fn new(memory: Memory, ops: impl SharedMemoryOps + Send + Sync + 'static) -> Self {
Self {
memory,
ops: std::sync::Arc::new(ops),
}
}
pub fn notify(&self, location: MemoryLocation, count: u32) -> Result<u32, AtomicsError> {
self.ops.notify(location, count)
}
pub fn wait(
&self,
location: MemoryLocation,
timeout: Option<std::time::Duration>,
) -> Result<u32, AtomicsError> {
self.ops.wait(location, timeout)
}
pub fn disable_atomics(&self) -> Result<(), MemoryError> {
self.ops.disable_atomics()
}
pub fn wake_all_atomic_waiters(&self) -> Result<(), MemoryError> {
self.ops.wake_all_atomic_waiters()
}
}
#[derive(Debug, Copy, Clone)]
pub(crate) struct MemoryBuffer<'a>(pub(crate) memory_impl::MemoryBuffer<'a>);
impl<'a> MemoryBuffer<'a> {
#[allow(unused)]
pub(crate) fn read(&self, offset: u64, buf: &mut [u8]) -> Result<(), MemoryAccessError> {
self.0.read(offset, buf)
}
#[allow(unused)]
pub(crate) fn read_uninit<'b>(
&self,
offset: u64,
buf: &'b mut [MaybeUninit<u8>],
) -> Result<&'b mut [u8], MemoryAccessError> {
self.0.read_uninit(offset, buf)
}
#[allow(unused)]
pub(crate) fn write(&self, offset: u64, data: &[u8]) -> Result<(), MemoryAccessError> {
self.0.write(offset, data)
}
}