Change memory api

This commit is contained in:
Lachlan Sneff
2019-02-04 15:07:32 -08:00
parent dcc75b98ba
commit 7fce447276
8 changed files with 316 additions and 234 deletions

View File

@ -3,7 +3,7 @@ use crate::{
export::{Context, Export}, export::{Context, Export},
global::Global, global::Global,
import::ImportObject, import::ImportObject,
memory::Memory, memory::{Memory, MemoryVariant},
module::{ImportName, ModuleInner}, module::{ImportName, ModuleInner},
structures::{BoxedMap, Map, SliceMap, TypedIndex}, structures::{BoxedMap, Map, SliceMap, TypedIndex},
table::Table, table::Table,
@ -17,7 +17,7 @@ use std::slice;
#[derive(Debug)] #[derive(Debug)]
pub struct LocalBacking { pub struct LocalBacking {
pub(crate) memories: BoxedMap<LocalMemoryIndex, Memory>, pub(crate) memories: BoxedMap<LocalMemoryIndex, MemoryVariant>,
pub(crate) tables: BoxedMap<LocalTableIndex, Table>, pub(crate) tables: BoxedMap<LocalTableIndex, Table>,
pub(crate) globals: BoxedMap<LocalGlobalIndex, Global>, pub(crate) globals: BoxedMap<LocalGlobalIndex, Global>,
@ -57,7 +57,7 @@ impl LocalBacking {
} }
} }
fn generate_memories(module: &ModuleInner) -> BoxedMap<LocalMemoryIndex, Memory> { fn generate_memories(module: &ModuleInner) -> BoxedMap<LocalMemoryIndex, MemoryVariant> {
let mut memories = Map::with_capacity(module.memories.len()); let mut memories = Map::with_capacity(module.memories.len());
for (_, &desc) in &module.memories { for (_, &desc) in &module.memories {
@ -70,8 +70,13 @@ impl LocalBacking {
// } else { // } else {
// Memory::new(memory.minimum, memory.maximum.map(|m| m as u32)) // Memory::new(memory.minimum, memory.maximum.map(|m| m as u32))
// }; // };
let memory = Memory::new(desc).expect("unable to create memory"); let memory_variant = if desc.shared {
memories.push(memory); MemoryVariant::Shared(Memory::new(desc).expect("unable to create memory"))
} else {
MemoryVariant::Unshared(Memory::new(desc).expect("unable to create memory"))
};
memories.push(memory_variant);
} }
memories.into_boxed_map() memories.into_boxed_map()
@ -80,7 +85,7 @@ impl LocalBacking {
fn finalize_memories( fn finalize_memories(
module: &ModuleInner, module: &ModuleInner,
imports: &ImportBacking, imports: &ImportBacking,
memories: &mut SliceMap<LocalMemoryIndex, Memory>, memories: &mut SliceMap<LocalMemoryIndex, MemoryVariant>,
) -> BoxedMap<LocalMemoryIndex, *mut vm::LocalMemory> { ) -> BoxedMap<LocalMemoryIndex, *mut vm::LocalMemory> {
// For each init that has some data... // For each init that has some data...
for init in module for init in module
@ -107,7 +112,14 @@ impl LocalBacking {
assert!(memory_desc.minimum.bytes().0 >= data_top); assert!(memory_desc.minimum.bytes().0 >= data_top);
let mem = &memories[local_memory_index]; let mem = &memories[local_memory_index];
mem.write_many(init_base as u32, &init.data).unwrap(); match mem {
MemoryVariant::Unshared(unshared_mem) => unshared_mem.access_mut()
[init_base..init_base + init.data.len()]
.copy_from_slice(&init.data),
MemoryVariant::Shared(shared_mem) => shared_mem.access_mut()
[init_base..init_base + init.data.len()]
.copy_from_slice(&init.data),
}
} }
LocalOrImport::Import(imported_memory_index) => { LocalOrImport::Import(imported_memory_index) => {
// Write the initialization data to the memory that // Write the initialization data to the memory that
@ -127,7 +139,10 @@ impl LocalBacking {
memories memories
.iter_mut() .iter_mut()
.map(|(_, mem)| mem.vm_local_memory()) .map(|(_, mem)| match mem {
MemoryVariant::Unshared(unshared_mem) => unshared_mem.vm_local_memory(),
MemoryVariant::Shared(shared_mem) => shared_mem.vm_local_memory(),
})
.collect::<Map<_, _>>() .collect::<Map<_, _>>()
.into_boxed_map() .into_boxed_map()
} }
@ -283,7 +298,7 @@ impl LocalBacking {
#[derive(Debug)] #[derive(Debug)]
pub struct ImportBacking { pub struct ImportBacking {
pub(crate) memories: BoxedMap<ImportedMemoryIndex, Memory>, pub(crate) memories: BoxedMap<ImportedMemoryIndex, MemoryVariant>,
pub(crate) tables: BoxedMap<ImportedTableIndex, Table>, pub(crate) tables: BoxedMap<ImportedTableIndex, Table>,
pub(crate) globals: BoxedMap<ImportedGlobalIndex, Global>, pub(crate) globals: BoxedMap<ImportedGlobalIndex, Global>,
@ -418,7 +433,7 @@ fn import_memories(
module: &ModuleInner, module: &ModuleInner,
imports: &ImportObject, imports: &ImportObject,
) -> LinkResult<( ) -> LinkResult<(
BoxedMap<ImportedMemoryIndex, Memory>, BoxedMap<ImportedMemoryIndex, MemoryVariant>,
BoxedMap<ImportedMemoryIndex, *mut vm::LocalMemory>, BoxedMap<ImportedMemoryIndex, *mut vm::LocalMemory>,
)> { )> {
let mut link_errors = vec![]; let mut link_errors = vec![];
@ -432,15 +447,22 @@ fn import_memories(
.and_then(|namespace| namespace.get_export(&name)); .and_then(|namespace| namespace.get_export(&name));
match memory_import { match memory_import {
Some(Export::Memory(mut memory)) => { Some(Export::Memory(mut memory)) => {
if expected_memory_desc.fits_in_imported(memory.descriptor()) { let (descriptor, vm_local_memory) = match &mut memory {
MemoryVariant::Unshared(unshared_mem) => {
(unshared_mem.descriptor(), unshared_mem.vm_local_memory())
}
MemoryVariant::Shared(_) => unimplemented!(),
};
if expected_memory_desc.fits_in_imported(descriptor) {
memories.push(memory.clone()); memories.push(memory.clone());
vm_memories.push(memory.vm_local_memory()); vm_memories.push(vm_local_memory);
} else { } else {
link_errors.push(LinkError::IncorrectMemoryDescriptor { link_errors.push(LinkError::IncorrectMemoryDescriptor {
namespace: namespace.clone(), namespace: namespace.clone(),
name: name.clone(), name: name.clone(),
expected: *expected_memory_desc, expected: *expected_memory_desc,
found: memory.descriptor(), found: descriptor,
}); });
} }
} }

View File

@ -193,7 +193,6 @@ impl From<ResolveError> for Error {
} }
} }
impl From<CallError> for Error { impl From<CallError> for Error {
fn from(call_err: CallError) -> Self { fn from(call_err: CallError) -> Self {
Error::CallError(call_err) Error::CallError(call_err)

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
global::Global, instance::InstanceInner, memory::Memory, module::ExportIndex, global::Global, instance::InstanceInner, memory::MemoryVariant, module::ExportIndex,
module::ModuleInner, table::Table, types::FuncSig, vm, module::ModuleInner, table::Table, types::FuncSig, vm,
}; };
use hashbrown::hash_map; use hashbrown::hash_map;
@ -18,7 +18,7 @@ pub enum Export {
ctx: Context, ctx: Context,
signature: Arc<FuncSig>, signature: Arc<FuncSig>,
}, },
Memory(Memory), Memory(MemoryVariant),
Table(Table), Table(Table),
Global(Global), Global(Global),
} }

View File

@ -5,7 +5,7 @@ use crate::{
export::{Context, Export, ExportIter, FuncPointer}, export::{Context, Export, ExportIter, FuncPointer},
global::Global, global::Global,
import::{ImportObject, LikeNamespace}, import::{ImportObject, LikeNamespace},
memory::Memory, memory::MemoryVariant,
module::{ExportIndex, Module, ModuleInner}, module::{ExportIndex, Module, ModuleInner},
table::Table, table::Table,
typed_func::{Func, Safe, WasmTypeList}, typed_func::{Func, Safe, WasmTypeList},
@ -372,7 +372,7 @@ impl InstanceInner {
(unsafe { FuncPointer::new(func_ptr) }, ctx, signature) (unsafe { FuncPointer::new(func_ptr) }, ctx, signature)
} }
fn get_memory_from_index(&self, module: &ModuleInner, mem_index: MemoryIndex) -> Memory { fn get_memory_from_index(&self, module: &ModuleInner, mem_index: MemoryIndex) -> MemoryVariant {
match mem_index.local_or_import(module) { match mem_index.local_or_import(module) {
LocalOrImport::Local(local_mem_index) => self.backing.memories[local_mem_index].clone(), LocalOrImport::Local(local_mem_index) => self.backing.memories[local_mem_index].clone(),
LocalOrImport::Import(imported_mem_index) => { LocalOrImport::Import(imported_mem_index) => {

View File

@ -4,11 +4,18 @@ use crate::{
import::IsExport, import::IsExport,
memory::dynamic::DYNAMIC_GUARD_SIZE, memory::dynamic::DYNAMIC_GUARD_SIZE,
memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE}, memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE},
types::{MemoryDescriptor, ValueType}, types::MemoryDescriptor,
units::Pages, units::Pages,
vm, vm,
}; };
use std::{cell::RefCell, fmt, mem, ptr, rc::Rc, slice}; use std::{
cell::{Cell, Ref, RefCell, RefMut},
fmt,
marker::PhantomData,
ops::{Deref, DerefMut},
ptr,
rc::Rc,
};
pub use self::dynamic::DynamicMemory; pub use self::dynamic::DynamicMemory;
pub use self::static_::{SharedStaticMemory, StaticMemory}; pub use self::static_::{SharedStaticMemory, StaticMemory};
@ -16,12 +23,68 @@ pub use self::static_::{SharedStaticMemory, StaticMemory};
mod dynamic; mod dynamic;
mod static_; mod static_;
pub struct Memory { pub trait MemoryImpl<'a>: Clone {
desc: MemoryDescriptor, type Access: Deref<Target = [u8]>;
storage: Rc<RefCell<(MemoryStorage, Box<vm::LocalMemory>)>>, type AccessMut: DerefMut<Target = [u8]>;
fn new(desc: MemoryDescriptor) -> Result<Self, CreationError>;
fn grow(&'a self, delta: Pages) -> Option<Pages>;
fn size(&'a self) -> Pages;
fn vm_local_memory(&'a self) -> *mut vm::LocalMemory;
fn access(&'a self) -> Self::Access;
fn access_mut(&'a self) -> Self::AccessMut;
} }
impl Memory { pub trait SharedPolicy
where
Self: Sized,
for<'a> Self::Memory: MemoryImpl<'a>,
{
const SHARED: bool;
type Memory;
fn transform_variant(variants: &MemoryVariant) -> &Memory<Self>;
}
pub struct Shared;
impl SharedPolicy for Shared {
const SHARED: bool = true;
type Memory = SharedMemory;
fn transform_variant(variants: &MemoryVariant) -> &Memory<Self> {
match variants {
MemoryVariant::Shared(shared_mem) => shared_mem,
MemoryVariant::Unshared(_) => {
panic!("cannot transform unshared memory to shared memory")
}
}
}
}
pub struct Unshared;
impl SharedPolicy for Unshared {
const SHARED: bool = false;
type Memory = UnsharedMemory;
fn transform_variant(variants: &MemoryVariant) -> &Memory<Self> {
match variants {
MemoryVariant::Unshared(unshared_mem) => unshared_mem,
MemoryVariant::Shared(_) => panic!("cannot transform shared memory to unshared memory"),
}
}
}
unsafe impl Send for Memory<Shared> {}
unsafe impl Sync for Memory<Shared> {}
pub struct Memory<S = Unshared>
where
S: SharedPolicy,
{
desc: MemoryDescriptor,
memory: S::Memory,
_phantom: PhantomData<S>,
}
impl<S> Memory<S>
where
S: SharedPolicy,
{
/// Create a new `Memory` from a [`MemoryDescriptor`] /// Create a new `Memory` from a [`MemoryDescriptor`]
/// ///
/// [`MemoryDescriptor`]: struct.MemoryDescriptor.html /// [`MemoryDescriptor`]: struct.MemoryDescriptor.html
@ -40,30 +103,21 @@ impl Memory {
/// shared: false, /// shared: false,
/// }; /// };
/// ///
/// let memory = Memory::new(descriptor)?; /// let memory: Memory = Memory::new(descriptor)?;
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
pub fn new(desc: MemoryDescriptor) -> Result<Self, CreationError> { pub fn new(desc: MemoryDescriptor) -> Result<Memory<S>, CreationError> {
let mut vm_local_memory = Box::new(vm::LocalMemory { assert_eq!(
base: ptr::null_mut(), desc.shared,
bound: 0, S::SHARED,
memory: ptr::null_mut(), "type parameter must match description"
}); );
let memory_storage = match desc.memory_type() {
MemoryType::Dynamic => {
MemoryStorage::Dynamic(DynamicMemory::new(desc, &mut vm_local_memory)?)
}
MemoryType::Static => {
MemoryStorage::Static(StaticMemory::new(desc, &mut vm_local_memory)?)
}
MemoryType::SharedStatic => unimplemented!("shared memories are not yet implemented"),
};
Ok(Memory { Ok(Memory {
desc, desc,
storage: Rc::new(RefCell::new((memory_storage, vm_local_memory))), memory: S::Memory::new(desc)?,
_phantom: PhantomData,
}) })
} }
@ -76,192 +130,48 @@ impl Memory {
} }
/// Grow this memory by the specfied number of pages. /// Grow this memory by the specfied number of pages.
pub fn grow(&mut self, delta: Pages) -> Option<Pages> { pub fn grow(&self, delta: Pages) -> Option<Pages> {
match &mut *self.storage.borrow_mut() { self.memory.grow(delta)
(MemoryStorage::Dynamic(ref mut dynamic_memory), ref mut local) => {
dynamic_memory.grow(delta, local)
}
(MemoryStorage::Static(ref mut static_memory), ref mut local) => {
static_memory.grow(delta, local)
}
(MemoryStorage::SharedStatic(_), _) => unimplemented!(),
}
} }
/// The size, in wasm pages, of this memory. /// The size, in wasm pages, of this memory.
pub fn size(&self) -> Pages { pub fn size(&self) -> Pages {
match &*self.storage.borrow() { self.memory.size()
(MemoryStorage::Dynamic(ref dynamic_memory), _) => dynamic_memory.size(),
(MemoryStorage::Static(ref static_memory), _) => static_memory.size(),
(MemoryStorage::SharedStatic(_), _) => unimplemented!(),
}
} }
pub fn read<T: ValueType>(&self, offset: u32) -> Result<T, ()> { pub fn access(&self) -> <S::Memory as MemoryImpl>::Access {
let offset = offset as usize; self.memory.access()
let borrow_ref = self.storage.borrow();
let memory_storage = &borrow_ref.0;
let mem_slice = match memory_storage {
MemoryStorage::Dynamic(ref dynamic_memory) => dynamic_memory.as_slice(),
MemoryStorage::Static(ref static_memory) => static_memory.as_slice(),
MemoryStorage::SharedStatic(_) => panic!("cannot slice a shared memory"),
};
if offset + mem::size_of::<T>() <= mem_slice.len() {
T::from_le(&mem_slice[offset..]).map_err(|_| ())
} else {
Err(())
}
} }
pub fn write<T: ValueType>(&self, offset: u32, value: T) -> Result<(), ()> { pub fn access_mut(&self) -> <S::Memory as MemoryImpl>::AccessMut {
let offset = offset as usize; self.memory.access_mut()
let mut borrow_ref = self.storage.borrow_mut();
let memory_storage = &mut borrow_ref.0;
let mem_slice = match memory_storage {
MemoryStorage::Dynamic(ref mut dynamic_memory) => dynamic_memory.as_slice_mut(),
MemoryStorage::Static(ref mut static_memory) => static_memory.as_slice_mut(),
MemoryStorage::SharedStatic(_) => panic!("cannot slice a shared memory"),
};
if offset + mem::size_of::<T>() <= mem_slice.len() {
value.into_le(&mut mem_slice[offset..]);
Ok(())
} else {
Err(())
}
} }
pub fn read_many<T: ValueType>(&self, offset: u32, count: usize) -> Result<Vec<T>, ()> { pub(crate) fn vm_local_memory(&self) -> *mut vm::LocalMemory {
let offset = offset as usize; self.memory.vm_local_memory()
let borrow_ref = self.storage.borrow();
let memory_storage = &borrow_ref.0;
let mem_slice = match memory_storage {
MemoryStorage::Dynamic(ref dynamic_memory) => dynamic_memory.as_slice(),
MemoryStorage::Static(ref static_memory) => static_memory.as_slice(),
MemoryStorage::SharedStatic(_) => panic!("cannot slice a shared memory"),
};
let bytes_size = count * mem::size_of::<T>();
if offset + bytes_size <= mem_slice.len() {
let buffer = &mem_slice[offset..offset + bytes_size];
let value_type_buffer = unsafe {
slice::from_raw_parts(
buffer.as_ptr() as *const T,
buffer.len() / mem::size_of::<T>(),
)
};
Ok(value_type_buffer.to_vec())
} else {
Err(())
}
}
pub fn write_many<T: ValueType>(&self, offset: u32, values: &[T]) -> Result<(), ()> {
let offset = offset as usize;
let mut borrow_ref = self.storage.borrow_mut();
let memory_storage = &mut borrow_ref.0;
let mem_slice = match memory_storage {
MemoryStorage::Dynamic(ref mut dynamic_memory) => dynamic_memory.as_slice_mut(),
MemoryStorage::Static(ref mut static_memory) => static_memory.as_slice_mut(),
MemoryStorage::SharedStatic(_) => panic!("cannot slice a shared memory"),
};
let bytes_size = values.len() * mem::size_of::<T>();
if offset + bytes_size <= mem_slice.len() {
let u8_buffer =
unsafe { slice::from_raw_parts(values.as_ptr() as *const u8, bytes_size) };
mem_slice[offset..offset + bytes_size].copy_from_slice(u8_buffer);
Ok(())
} else {
Err(())
}
}
pub fn direct_access<T: ValueType, F, R>(&self, f: F) -> R
where
F: FnOnce(&[T]) -> R,
{
let borrow_ref = self.storage.borrow();
let memory_storage = &borrow_ref.0;
let mem_slice = match memory_storage {
MemoryStorage::Dynamic(ref dynamic_memory) => dynamic_memory.as_slice(),
MemoryStorage::Static(ref static_memory) => static_memory.as_slice(),
MemoryStorage::SharedStatic(_) => panic!("cannot slice a shared memory"),
};
let t_buffer = unsafe {
slice::from_raw_parts(
mem_slice.as_ptr() as *const T,
mem_slice.len() / mem::size_of::<T>(),
)
};
f(t_buffer)
}
pub fn direct_access_mut<T: ValueType, F, R>(&self, f: F) -> R
where
F: FnOnce(&mut [T]) -> R,
{
let mut borrow_ref = self.storage.borrow_mut();
let memory_storage = &mut borrow_ref.0;
let mem_slice = match memory_storage {
MemoryStorage::Dynamic(ref mut dynamic_memory) => dynamic_memory.as_slice_mut(),
MemoryStorage::Static(ref mut static_memory) => static_memory.as_slice_mut(),
MemoryStorage::SharedStatic(_) => panic!("cannot slice a shared memory"),
};
let t_buffer = unsafe {
slice::from_raw_parts_mut(
mem_slice.as_mut_ptr() as *mut T,
mem_slice.len() / mem::size_of::<T>(),
)
};
f(t_buffer)
}
pub fn vm_local_memory(&mut self) -> *mut vm::LocalMemory {
&mut *self.storage.borrow_mut().1
} }
} }
impl IsExport for Memory { impl IsExport for Memory<Unshared> {
fn to_export(&self) -> Export { fn to_export(&self) -> Export {
Export::Memory(self.clone()) Export::Memory(MemoryVariant::Unshared(self.clone()))
}
}
impl IsExport for Memory<Shared> {
fn to_export(&self) -> Export {
Export::Memory(MemoryVariant::Shared(self.clone()))
} }
} }
impl Clone for Memory { impl<S> Clone for Memory<S>
where
S: SharedPolicy,
{
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
desc: self.desc, desc: self.desc,
storage: Rc::clone(&self.storage), memory: self.memory.clone(),
} _phantom: PhantomData,
}
}
pub enum MemoryStorage {
Dynamic(Box<DynamicMemory>),
Static(Box<StaticMemory>),
SharedStatic(Box<SharedStaticMemory>),
}
impl MemoryStorage {
pub fn to_type(&self) -> MemoryType {
match self {
MemoryStorage::Dynamic(_) => MemoryType::Dynamic,
MemoryStorage::Static(_) => MemoryType::Static,
MemoryStorage::SharedStatic(_) => MemoryType::SharedStatic,
} }
} }
} }
@ -278,8 +188,7 @@ impl MemoryType {
pub fn guard_size(self) -> u64 { pub fn guard_size(self) -> u64 {
match self { match self {
MemoryType::Dynamic => DYNAMIC_GUARD_SIZE as u64, MemoryType::Dynamic => DYNAMIC_GUARD_SIZE as u64,
MemoryType::Static => SAFE_STATIC_GUARD_SIZE as u64, MemoryType::Static | MemoryType::SharedStatic => SAFE_STATIC_GUARD_SIZE as u64,
MemoryType::SharedStatic => SAFE_STATIC_GUARD_SIZE as u64,
} }
} }
@ -287,13 +196,15 @@ impl MemoryType {
pub fn bounds(self) -> Option<u64> { pub fn bounds(self) -> Option<u64> {
match self { match self {
MemoryType::Dynamic => None, MemoryType::Dynamic => None,
MemoryType::Static => Some(SAFE_STATIC_HEAP_SIZE as u64), MemoryType::Static | MemoryType::SharedStatic => Some(SAFE_STATIC_HEAP_SIZE as u64),
MemoryType::SharedStatic => Some(SAFE_STATIC_HEAP_SIZE as u64),
} }
} }
} }
impl fmt::Debug for Memory { impl<S> fmt::Debug for Memory<S>
where
S: SharedPolicy,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Memory") f.debug_struct("Memory")
.field("desc", &self.desc) .field("desc", &self.desc)
@ -301,3 +212,148 @@ impl fmt::Debug for Memory {
.finish() .finish()
} }
} }
#[derive(Debug, Clone)]
pub enum MemoryVariant {
Unshared(Memory<Unshared>),
Shared(Memory<Shared>),
}
enum UnsharedMemoryStorage {
Dynamic(Box<DynamicMemory>),
Static(Box<StaticMemory>),
}
pub struct UnsharedMemory {
internal: Rc<UnsharedMemoryInternal>,
}
struct UnsharedMemoryInternal {
storage: RefCell<UnsharedMemoryStorage>,
local: Cell<vm::LocalMemory>,
}
impl<'a> MemoryImpl<'a> for UnsharedMemory {
type Access = Ref<'a, [u8]>;
type AccessMut = RefMut<'a, [u8]>;
fn new(desc: MemoryDescriptor) -> Result<Self, CreationError> {
let mut local = vm::LocalMemory {
base: ptr::null_mut(),
bound: 0,
memory: ptr::null_mut(),
};
let storage = match desc.memory_type() {
MemoryType::Dynamic => {
UnsharedMemoryStorage::Dynamic(DynamicMemory::new(desc, &mut local)?)
}
MemoryType::Static => {
UnsharedMemoryStorage::Static(StaticMemory::new(desc, &mut local)?)
}
MemoryType::SharedStatic => panic!("attempting to create shared unshared memory"),
};
Ok(UnsharedMemory {
internal: Rc::new(UnsharedMemoryInternal {
storage: RefCell::new(storage),
local: Cell::new(local),
}),
})
}
fn grow(&self, delta: Pages) -> Option<Pages> {
let mut storage = self.internal.storage.borrow_mut();
let mut local = self.internal.local.get();
let pages = match &mut *storage {
UnsharedMemoryStorage::Dynamic(dynamic_memory) => {
dynamic_memory.grow(delta, &mut local)
}
UnsharedMemoryStorage::Static(static_memory) => static_memory.grow(delta, &mut local),
};
self.internal.local.set(local);
pages
}
fn size(&self) -> Pages {
let storage = self.internal.storage.borrow();
match &*storage {
UnsharedMemoryStorage::Dynamic(ref dynamic_memory) => dynamic_memory.size(),
UnsharedMemoryStorage::Static(ref static_memory) => static_memory.size(),
}
}
fn vm_local_memory(&self) -> *mut vm::LocalMemory {
self.internal.local.as_ptr()
}
fn access(&'a self) -> Ref<'a, [u8]> {
Ref::map(
self.internal.storage.borrow(),
|memory_storage| match memory_storage {
UnsharedMemoryStorage::Dynamic(dynamic_memory) => dynamic_memory.as_slice(),
UnsharedMemoryStorage::Static(static_memory) => static_memory.as_slice(),
},
)
}
fn access_mut(&'a self) -> RefMut<'a, [u8]> {
RefMut::map(
self.internal.storage.borrow_mut(),
|memory_storage| match memory_storage {
UnsharedMemoryStorage::Dynamic(dynamic_memory) => dynamic_memory.as_slice_mut(),
UnsharedMemoryStorage::Static(static_memory) => static_memory.as_slice_mut(),
},
)
}
}
impl Clone for UnsharedMemory {
fn clone(&self) -> Self {
UnsharedMemory {
internal: Rc::clone(&self.internal),
}
}
}
pub struct SharedMemory {}
impl<'a> MemoryImpl<'a> for SharedMemory {
type Access = Vec<u8>;
type AccessMut = Vec<u8>;
fn new(_desc: MemoryDescriptor) -> Result<Self, CreationError> {
unimplemented!()
}
fn grow(&self, _delta: Pages) -> Option<Pages> {
unimplemented!()
}
fn size(&self) -> Pages {
unimplemented!()
}
fn vm_local_memory(&self) -> *mut vm::LocalMemory {
unimplemented!()
}
fn access(&self) -> Vec<u8> {
unimplemented!()
}
fn access_mut(&self) -> Vec<u8> {
unimplemented!()
}
}
impl Clone for SharedMemory {
fn clone(&self) -> Self {
unimplemented!()
}
}

View File

@ -1,6 +1,6 @@
pub use crate::backing::{ImportBacking, LocalBacking}; pub use crate::backing::{ImportBacking, LocalBacking};
use crate::{ use crate::{
memory::Memory, memory::{Memory, SharedPolicy},
module::ModuleInner, module::ModuleInner,
structures::TypedIndex, structures::TypedIndex,
types::{LocalOrImport, MemoryIndex}, types::{LocalOrImport, MemoryIndex},
@ -106,24 +106,30 @@ impl Ctx {
/// ``` /// ```
/// # use wasmer_runtime_core::{ /// # use wasmer_runtime_core::{
/// # vm::Ctx, /// # vm::Ctx,
/// # memory::Memory,
/// # }; /// # };
/// fn read_memory(ctx: &Ctx) -> u8 { /// fn read_memory(ctx: &Ctx) -> u8 {
/// let first_memory = ctx.memory(0); /// let first_memory: &Memory = ctx.memory(0);
/// // Read the first byte of that linear memory. /// // Read the first byte of that linear memory.
/// first_memory.read(0).unwrap() /// first_memory.access()[0]
/// } /// }
/// ``` /// ```
pub fn memory<'a>(&'a self, mem_index: u32) -> &'a Memory { pub fn memory<'a, S>(&'a self, mem_index: u32) -> &'a Memory<S>
where
S: SharedPolicy,
{
let module = unsafe { &*self.module }; let module = unsafe { &*self.module };
let mem_index = MemoryIndex::new(mem_index as usize); let mem_index = MemoryIndex::new(mem_index as usize);
match mem_index.local_or_import(module) { match mem_index.local_or_import(module) {
LocalOrImport::Local(local_mem_index) => unsafe { LocalOrImport::Local(local_mem_index) => unsafe {
let local_backing = &*self.local_backing; let local_backing = &*self.local_backing;
&local_backing.memories[local_mem_index] let mem_variant = &local_backing.memories[local_mem_index];
S::transform_variant(mem_variant)
}, },
LocalOrImport::Import(import_mem_index) => unsafe { LocalOrImport::Import(import_mem_index) => unsafe {
let import_backing = &*self.import_backing; let import_backing = &*self.import_backing;
&import_backing.memories[import_mem_index] let mem_variant = &import_backing.memories[import_mem_index];
S::transform_variant(mem_variant)
}, },
} }
} }
@ -195,7 +201,7 @@ impl ImportedFunc {
} }
/// Definition of a table used by the VM. (obviously) /// Definition of a table used by the VM. (obviously)
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
#[repr(C)] #[repr(C)]
pub struct LocalTable { pub struct LocalTable {
/// pointer to the elements in the table. /// pointer to the elements in the table.
@ -222,7 +228,7 @@ impl LocalTable {
} }
/// Definition of a memory used by the VM. /// Definition of a memory used by the VM.
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
#[repr(C)] #[repr(C)]
pub struct LocalMemory { pub struct LocalMemory {
/// Pointer to the bottom of this linear memory. /// Pointer to the bottom of this linear memory.
@ -251,7 +257,7 @@ impl LocalMemory {
} }
/// Definition of a global used by the VM. /// Definition of a global used by the VM.
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
#[repr(C)] #[repr(C)]
pub struct LocalGlobal { pub struct LocalGlobal {
pub data: u64, pub data: u64,
@ -277,7 +283,7 @@ impl LocalGlobal {
pub struct SigId(pub u32); pub struct SigId(pub u32);
/// Caller-checked anyfunc /// Caller-checked anyfunc
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
#[repr(C)] #[repr(C)]
pub struct Anyfunc { pub struct Anyfunc {
pub func: *const Func, pub func: *const Func,

View File

@ -16,7 +16,7 @@ fn main() -> Result<()> {
let wasm_binary = wat2wasm(IMPORT_MODULE.as_bytes()).expect("WAST not valid or malformed"); let wasm_binary = wat2wasm(IMPORT_MODULE.as_bytes()).expect("WAST not valid or malformed");
let inner_module = wasmer_runtime_core::compile_with(&wasm_binary, &CraneliftCompiler::new())?; let inner_module = wasmer_runtime_core::compile_with(&wasm_binary, &CraneliftCompiler::new())?;
let memory = Memory::new(MemoryDescriptor { let memory: Memory = Memory::new(MemoryDescriptor {
minimum: Pages(1), minimum: Pages(1),
maximum: Some(Pages(1)), maximum: Some(Pages(1)),
shared: false, shared: false,
@ -32,39 +32,38 @@ fn main() -> Result<()> {
}) })
.unwrap(); .unwrap();
memory.direct_access_mut(|slice: &mut [u32]| { memory.access_mut()[0] = 42;
slice[0] = 42;
});
let import_object = imports! { let import_object = imports! {
"env" => { "env" => {
"print_i32" => func!(print_num, [i32] -> [i32]), "print_i32" => func!(print_num),
"memory" => memory, "memory" => memory,
"global" => global, "global" => global,
"table" => table, "table" => table,
}, },
}; };
let inner_instance = inner_module.instantiate(import_object)?; let inner_instance = inner_module.instantiate(&import_object)?;
let outer_imports = imports! { let outer_imports = imports! {
"env" => inner_instance, "env" => inner_instance,
}; };
let outer_module = wasmer_runtime_core::compile_with(EXAMPLE_WASM, &CraneliftCompiler::new())?; let outer_module = wasmer_runtime_core::compile_with(EXAMPLE_WASM, &CraneliftCompiler::new())?;
let outer_instance = outer_module.instantiate(outer_imports)?; let outer_instance = outer_module.instantiate(&outer_imports)?;
let ret = outer_instance.call("main", &[Value::I32(42)])?; let ret = outer_instance.call("main", &[Value::I32(42)])?;
println!("ret: {:?}", ret); println!("ret: {:?}", ret);
Ok(()) Ok(())
} }
extern "C" fn print_num(n: i32, ctx: &mut vm::Ctx) -> i32 { fn print_num(n: i32, ctx: &mut vm::Ctx) -> i32 {
println!("print_num({})", n); println!("print_num({})", n);
let memory = ctx.memory(0); let memory: &Memory = ctx.memory(0);
let a: i32 = memory.read(0).unwrap(); let a = memory.access()[0] as i32;
a + n + 1 a + n + 1
} }

View File

@ -27,7 +27,7 @@ fn create_module_1() -> Instance {
let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &CraneliftCompiler::new()) let module = wasmer_runtime_core::compile_with(&wasm_binary[..], &CraneliftCompiler::new())
.expect("WASM can't be compiled"); .expect("WASM can't be compiled");
module module
.instantiate(generate_imports()) .instantiate(&generate_imports())
.expect("WASM can't be instantiated") .expect("WASM can't be instantiated")
} }