diff --git a/lib/runtime-core/examples/simple/main.rs b/lib/runtime-core/examples/simple/main.rs index dcf016a81..1737c4163 100644 --- a/lib/runtime-core/examples/simple/main.rs +++ b/lib/runtime-core/examples/simple/main.rs @@ -8,13 +8,15 @@ fn main() -> Result<()> { 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 mut memory = Memory::new(MemoryDesc { + let memory = Memory::new(MemoryDesc { min: 1, max: Some(1), shared: false, }).unwrap(); - memory.as_slice_mut()[0] = 42; + memory.direct_access_mut(|slice: &mut [u32]| { + slice[0] = 42; + }); let import_object = imports! { "env" => { diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index 3f8980bcf..36adc322e 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -104,11 +104,8 @@ impl LocalBacking { let data_top = init_base + init.data.len(); assert!(memory_desc.min as usize * WASM_PAGE_SIZE >= data_top); - let mem: &mut Memory = &mut memories[local_memory_index]; - let mem_init_view = - &mut mem.as_slice_mut()[init_base..init_base + init.data.len()]; - - mem_init_view.copy_from_slice(&init.data); + let mem = &memories[local_memory_index]; + mem.set(init_base as u32, &init.data).unwrap(); } LocalOrImport::Import(imported_memory_index) => { // Write the initialization data to the memory that diff --git a/lib/runtime-core/src/global.rs b/lib/runtime-core/src/global.rs new file mode 100644 index 000000000..66457d052 --- /dev/null +++ b/lib/runtime-core/src/global.rs @@ -0,0 +1,91 @@ +use crate::{ + types::{GlobalDesc, Type, Value}, + vm, +}; +use std::{cell::UnsafeCell, rc::Rc}; + +pub struct Global { + desc: GlobalDesc, + storage: Rc>, +} + +impl Global { + pub fn new(value: Value) -> Self { + Self::_new(value, false) + } + + pub fn new_mutable(value: Value) -> Self { + Self::_new(value, true) + } + + fn _new(value: Value, mutable: bool) -> Self { + let desc = GlobalDesc { + mutable, + ty: value.ty(), + }; + + let local_global = vm::LocalGlobal { + data: match value { + Value::I32(x) => x as u64, + Value::I64(x) => x as u64, + Value::F32(x) => x.to_bits() as u64, + Value::F64(x) => x.to_bits(), + }, + }; + + Self { + desc, + storage: Rc::new(UnsafeCell::new(local_global)) + } + } + + pub fn description(&self) -> GlobalDesc { + self.desc + } + + pub fn set(&mut self, value: Value) { + if self.desc.mutable { + if self.desc.ty == value.ty() { + let local_global = vm::LocalGlobal { + data: match value { + Value::I32(x) => x as u64, + Value::I64(x) => x as u64, + Value::F32(x) => x.to_bits() as u64, + Value::F64(x) => x.to_bits(), + }, + }; + unsafe { + (*self.storage.get()) = local_global; + } + } else { + panic!("Wrong type for setting this global") + } + } else { + panic!("Cannot modify global immutable by default") + } + } + + pub fn get(&self) -> Value { + let data = unsafe { (*self.storage.get()).data }; + + match self.desc.ty { + Type::I32 => Value::I32(data as i32), + Type::I64 => Value::I64(data as i64), + Type::F32 => Value::F32(f32::from_bits(data as u32)), + Type::F64 => Value::F64(f64::from_bits(data)), + } + } + + pub(crate) fn vm_local_global(&mut self) -> *mut vm::LocalGlobal { + &mut *unsafe { &mut *self.storage.get() } + } +} + +impl Clone for Global { + fn clone(&self) -> Self { + Self { + desc: self.desc, + storage: Rc::clone(&self.storage), + } + } +} \ No newline at end of file diff --git a/lib/runtime-core/src/import.rs b/lib/runtime-core/src/import.rs index 16a6a0684..9da8bdcc3 100644 --- a/lib/runtime-core/src/import.rs +++ b/lib/runtime-core/src/import.rs @@ -24,11 +24,11 @@ impl IsExport for Export { /// /// # Usage: /// ``` -/// # use wasmer_runtime_core::imports; +/// # use wasmer_runtime_core::{imports, func}; /// # use wasmer_runtime_core::vm::Ctx; /// let import_object = imports! { /// "env" => { -/// "foo" => foo<[i32] -> [i32]>, +/// "foo" => func!(foo, [i32] -> [i32]), /// }, /// }; /// diff --git a/lib/runtime-core/src/macros.rs b/lib/runtime-core/src/macros.rs index 06a5fcdd1..a84435fc7 100644 --- a/lib/runtime-core/src/macros.rs +++ b/lib/runtime-core/src/macros.rs @@ -64,11 +64,11 @@ macro_rules! __export_func_convert_type { /// /// # Usage: /// ``` -/// # use wasmer_runtime_core::imports; +/// # use wasmer_runtime_core::{imports, func}; /// # use wasmer_runtime_core::vm::Ctx; /// let import_object = imports! { /// "env" => { -/// "foo" => foo<[i32] -> [i32]>, +/// "foo" => func!(foo, [i32] -> [i32]), /// }, /// }; /// diff --git a/lib/runtime-core/src/memory/mod.rs b/lib/runtime-core/src/memory/mod.rs index 959692a18..4d21a8431 100644 --- a/lib/runtime-core/src/memory/mod.rs +++ b/lib/runtime-core/src/memory/mod.rs @@ -3,10 +3,10 @@ use crate::{ import::IsExport, memory::dynamic::DYNAMIC_GUARD_SIZE, memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE}, - types::MemoryDesc, + types::{MemoryDesc, ValueType}, vm, }; -use std::{cell::UnsafeCell, fmt, ptr, rc::Rc}; +use std::{cell::RefCell, fmt, mem, ptr, slice, rc::Rc}; pub use self::dynamic::DynamicMemory; pub use self::static_::{SharedStaticMemory, StaticMemory}; @@ -19,7 +19,7 @@ pub const WASM_MAX_PAGES: usize = 65_536; pub struct Memory { desc: MemoryDesc, - storage: Rc)>>, + storage: Rc)>>, } impl Memory { @@ -42,7 +42,7 @@ impl Memory { Some(Memory { desc, - storage: Rc::new(UnsafeCell::new((memory_storage, vm_local_memory))), + storage: Rc::new(RefCell::new((memory_storage, vm_local_memory))), }) } @@ -51,40 +51,112 @@ impl Memory { } pub fn grow(&mut self, delta: u32) -> Option { - match unsafe { &mut *self.storage.get() } { - (MemoryStorage::Dynamic(dynamic_memory), local) => dynamic_memory.grow(delta, local), - (MemoryStorage::Static(static_memory), local) => static_memory.grow(delta, local), + match &mut *self.storage.borrow_mut() { + (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!(), } } /// This returns the number of pages in the memory. pub fn current_pages(&self) -> u32 { - match unsafe { &*self.storage.get() } { - (MemoryStorage::Dynamic(dynamic_memory), _) => dynamic_memory.current(), - (MemoryStorage::Static(static_memory), _) => static_memory.current(), + match &*self.storage.borrow() { + (MemoryStorage::Dynamic(ref dynamic_memory), _) => dynamic_memory.current(), + (MemoryStorage::Static(ref static_memory), _) => static_memory.current(), (MemoryStorage::SharedStatic(_), _) => unimplemented!(), } } - pub fn as_slice(&self) -> &[u8] { - match unsafe { &*self.storage.get() } { - (MemoryStorage::Dynamic(dynamic_memory), _) => dynamic_memory.as_slice(), - (MemoryStorage::Static(static_memory), _) => static_memory.as_slice(), - (MemoryStorage::SharedStatic(_), _) => panic!("cannot slice a shared memory"), + pub fn get(&self, offset: u32, count: usize) -> Result, ()> { + let offset = offset as usize; + 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::(); + + 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::()) + }; + Ok(value_type_buffer.to_vec()) + } else { + Err(()) } } - pub fn as_slice_mut(&mut self) -> &mut [u8] { - match unsafe { &mut *self.storage.get() } { - (MemoryStorage::Dynamic(dynamic_memory), _) => dynamic_memory.as_slice_mut(), - (MemoryStorage::Static(static_memory), _) => static_memory.as_slice_mut(), - (MemoryStorage::SharedStatic(_), _) => panic!("cannot slice a shared memory"), + pub fn set(&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::(); + + 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(&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::()) + }; + + f(t_buffer) + } + + pub fn direct_access_mut(&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::()) + }; + + f(t_buffer) + } + pub(crate) fn vm_local_memory(&mut self) -> *mut vm::LocalMemory { - &mut *unsafe { &mut *self.storage.get() }.1 + &mut *self.storage.borrow_mut().1 } } diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index 4be427f00..1defb8ef7 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -1,4 +1,5 @@ use crate::{memory::MemoryType, module::ModuleInner, structures::TypedIndex}; +use std::mem; /// Represents a WebAssembly type. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -64,6 +65,62 @@ impl From for Value { } } +pub enum ValueError { + BufferTooSmall, +} + +pub trait ValueType: Copy + Clone +where + Self: Sized +{ + fn into_le(self, buffer: &mut [u8]); + fn from_le(buffer: &[u8]) -> Result; +} + +macro_rules! convert_value_impl { + ($t:ty) => { + impl ValueType for $t { + fn into_le(self, buffer: &mut [u8]) { + buffer.copy_from_slice(&self.to_le_bytes()); + } + fn from_le(buffer: &[u8]) -> Result { + if buffer.len() >= mem::size_of::() { + let mut array = [0u8; mem::size_of::()]; + array.copy_from_slice(buffer); + Ok(Self::from_le_bytes(array)) + } else { + Err(ValueError::BufferTooSmall) + } + } + } + }; + ( $($t:ty),* ) => { + $( + convert_value_impl!($t); + )* + }; +} + +convert_value_impl!(u8, i8, u16, i16, u32, i32, u64, i64); + +impl ValueType for f32 { + fn into_le(self, buffer: &mut [u8]) { + self.to_bits().into_le(buffer); + } + fn from_le(buffer: &[u8]) -> Result { + Ok(f32::from_bits(::from_le(buffer)?)) + } +} + +impl ValueType for f64 { + fn into_le(self, buffer: &mut [u8]) { + self.to_bits().into_le(buffer); + } + fn from_le(buffer: &[u8]) -> Result { + Ok(f64::from_bits(::from_le(buffer)?)) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ElementType { /// Any wasm function.