use crate::sys::exports::{ExportError, Exportable};
use crate::sys::externals::Extern;
use crate::sys::store::Store;
use crate::sys::{MemoryType, MemoryView};
use loupe::MemoryUsage;
use std::convert::TryInto;
use std::slice;
use std::sync::Arc;
use wasmer_engine::Export;
use wasmer_types::{Pages, ValueType};
use wasmer_vm::{MemoryError, VMMemory};
#[derive(Debug, MemoryUsage)]
pub struct Memory {
store: Store,
vm_memory: VMMemory,
}
impl Memory {
pub fn new(store: &Store, ty: MemoryType) -> Result<Self, MemoryError> {
let tunables = store.tunables();
let style = tunables.memory_style(&ty);
let memory = tunables.create_host_memory(&ty, &style)?;
Ok(Self {
store: store.clone(),
vm_memory: VMMemory {
from: memory,
instance_ref: None,
},
})
}
pub fn ty(&self) -> MemoryType {
self.vm_memory.from.ty()
}
pub fn store(&self) -> &Store {
&self.store
}
pub unsafe fn data_unchecked(&self) -> &[u8] {
self.data_unchecked_mut()
}
#[allow(clippy::mut_from_ref)]
pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] {
let definition = self.vm_memory.from.vmmemory();
let def = definition.as_ref();
slice::from_raw_parts_mut(def.base, def.current_length.try_into().unwrap())
}
pub fn data_ptr(&self) -> *mut u8 {
let definition = self.vm_memory.from.vmmemory();
let def = unsafe { definition.as_ref() };
def.base
}
pub fn data_size(&self) -> u64 {
let definition = self.vm_memory.from.vmmemory();
let def = unsafe { definition.as_ref() };
def.current_length.try_into().unwrap()
}
pub fn size(&self) -> Pages {
self.vm_memory.from.size()
}
pub fn grow<IntoPages>(&self, delta: IntoPages) -> Result<Pages, MemoryError>
where
IntoPages: Into<Pages>,
{
self.vm_memory.from.grow(delta.into())
}
pub fn view<T: ValueType>(&self) -> MemoryView<T> {
let base = self.data_ptr();
let length = self.size().bytes().0 / std::mem::size_of::<T>();
unsafe { MemoryView::new(base as _, length as u32) }
}
#[doc(hidden)]
pub fn uint8view(&self) -> MemoryView<u8> {
self.view()
}
pub(crate) fn from_vm_export(store: &Store, vm_memory: VMMemory) -> Self {
Self {
store: store.clone(),
vm_memory,
}
}
pub fn same(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.vm_memory.from, &other.vm_memory.from)
}
#[doc(hidden)]
pub unsafe fn get_vm_memory(&self) -> &VMMemory {
&self.vm_memory
}
}
impl Clone for Memory {
fn clone(&self) -> Self {
let mut vm_memory = self.vm_memory.clone();
vm_memory.upgrade_instance_ref().unwrap();
Self {
store: self.store.clone(),
vm_memory,
}
}
}
impl<'a> Exportable<'a> for Memory {
fn to_export(&self) -> Export {
self.vm_memory.clone().into()
}
fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> {
match _extern {
Extern::Memory(memory) => Ok(memory),
_ => Err(ExportError::IncompatibleType),
}
}
fn into_weak_instance_ref(&mut self) {
self.vm_memory
.instance_ref
.as_mut()
.map(|v| *v = v.downgrade());
}
}