diff --git a/lib/clif-backend/src/func_env.rs b/lib/clif-backend/src/func_env.rs index 40ac4c073..c4e92fa07 100644 --- a/lib/clif-backend/src/func_env.rs +++ b/lib/clif-backend/src/func_env.rs @@ -13,8 +13,6 @@ use wasmer_runtime_core::{ vm, }; -const WASM_PAGE_SIZE: usize = 65_536; - pub struct FuncEnv<'env, 'module, 'isa> { env: &'env ModuleEnv<'module, 'isa>, } @@ -219,7 +217,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { func.create_heap(ir::HeapData { base: local_memory_base, - min_size: ((description.minimum as u64) * (WASM_PAGE_SIZE as u64)).into(), + min_size: (description.minimum.bytes().0 as u64).into(), offset_guard_size: mem_type.guard_size().into(), style: ir::HeapStyle::Dynamic { bound_gv: local_memory_bound, @@ -230,7 +228,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> { mem_type @ MemoryType::Static | mem_type @ MemoryType::SharedStatic => func .create_heap(ir::HeapData { base: local_memory_base, - min_size: ((description.minimum as u64) * (WASM_PAGE_SIZE as u64)).into(), + min_size: (description.minimum.bytes().0 as u64).into(), offset_guard_size: mem_type.guard_size().into(), style: ir::HeapStyle::Static { bound: mem_type.bounds().unwrap().into(), diff --git a/lib/clif-backend/src/module_env.rs b/lib/clif-backend/src/module_env.rs index 1773e7e12..9b3cb171d 100644 --- a/lib/clif-backend/src/module_env.rs +++ b/lib/clif-backend/src/module_env.rs @@ -14,6 +14,7 @@ use wasmer_runtime_core::{ ElementType, FuncSig, GlobalDescriptor, GlobalIndex, GlobalInit, Initializer, LocalFuncIndex, LocalOrImport, MemoryDescriptor, SigIndex, TableDescriptor, Value, }, + units::Pages, }; pub struct ModuleEnv<'module, 'isa> { @@ -251,8 +252,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa> /// Declares a memory to the environment fn declare_memory(&mut self, memory: cranelift_wasm::Memory) { self.module.memories.push(MemoryDescriptor { - minimum: memory.minimum, - maximum: memory.maximum, + minimum: Pages(memory.minimum), + maximum: memory.maximum.map(|max| Pages(max)), shared: memory.shared, }); } @@ -270,8 +271,8 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa> }; let memory = MemoryDescriptor { - minimum: memory.minimum, - maximum: memory.maximum, + minimum: Pages(memory.minimum), + maximum: memory.maximum.map(|max| Pages(max)), shared: memory.shared, }; diff --git a/lib/runtime-core/examples/simple/main.rs b/lib/runtime-core/examples/simple/main.rs index ad3992ba2..00dcf1890 100644 --- a/lib/runtime-core/examples/simple/main.rs +++ b/lib/runtime-core/examples/simple/main.rs @@ -7,6 +7,7 @@ use wasmer_runtime_core::{ prelude::*, table::Table, types::{ElementType, MemoryDescriptor, TableDescriptor, Value}, + units::Pages, }; static EXAMPLE_WASM: &'static [u8] = include_bytes!("simple.wasm"); @@ -16,8 +17,8 @@ fn main() -> Result<()> { let inner_module = wasmer_runtime_core::compile_with(&wasm_binary, &CraneliftCompiler::new())?; let memory = Memory::new(MemoryDescriptor { - min: 1, - max: Some(1), + minimum: Pages(1), + maximum: Some(Pages(1)), shared: false, }) .unwrap(); @@ -26,8 +27,8 @@ fn main() -> Result<()> { let table = Table::new(TableDescriptor { element: ElementType::Anyfunc, - min: 10, - max: None, + minimum: 10, + maximum: None, }) .unwrap(); diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index d6a746e60..ad9854a7b 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -3,7 +3,7 @@ use crate::{ export::{Context, Export}, global::Global, import::ImportObject, - memory::{Memory, WASM_PAGE_SIZE}, + memory::Memory, module::{ImportName, ModuleInner}, structures::{BoxedMap, Map, SliceMap, TypedIndex}, table::Table, @@ -104,7 +104,7 @@ impl LocalBacking { LocalOrImport::Local(local_memory_index) => { let memory_desc = module.memories[local_memory_index]; let data_top = init_base + init.data.len(); - assert!(memory_desc.minimum as usize * WASM_PAGE_SIZE >= data_top); + assert!(memory_desc.minimum.bytes().0 >= data_top); let mem = &memories[local_memory_index]; mem.write_many(init_base as u32, &init.data).unwrap(); @@ -167,9 +167,8 @@ impl LocalBacking { LocalOrImport::Local(local_table_index) => { let table = &tables[local_table_index]; - if (table.current_size() as usize) < init_base + init.elements.len() { - let delta = - (init_base + init.elements.len()) - table.current_size() as usize; + if (table.size() as usize) < init_base + init.elements.len() { + let delta = (init_base + init.elements.len()) - table.size() as usize; // Grow the table if it's too small. table.grow(delta as u32).expect("couldn't grow table"); } @@ -203,9 +202,8 @@ impl LocalBacking { LocalOrImport::Import(import_table_index) => { let table = &imports.tables[import_table_index]; - if (table.current_size() as usize) < init_base + init.elements.len() { - let delta = - (init_base + init.elements.len()) - table.current_size() as usize; + if (table.size() as usize) < init_base + init.elements.len() { + let delta = (init_base + init.elements.len()) - table.size() as usize; // Grow the table if it's too small. table.grow(delta as u32).expect("couldn't grow table"); } diff --git a/lib/runtime-core/src/error.rs b/lib/runtime-core/src/error.rs index f518140d3..fa3364908 100644 --- a/lib/runtime-core/src/error.rs +++ b/lib/runtime-core/src/error.rs @@ -140,6 +140,20 @@ impl PartialEq for CallError { } } +/// This error type is produced when creating something, +/// like a `Memory` or a `Table`. +#[derive(Debug, Clone)] +pub enum CreationError { + UnableToCreateMemory, + UnableToCreateTable, +} + +impl PartialEq for CreationError { + fn eq(&self, _other: &CreationError) -> bool { + false + } +} + /// The amalgamation of all errors that can occur /// during the compilation, instantiation, or execution /// of a webassembly module. @@ -152,6 +166,7 @@ pub enum Error { RuntimeError(RuntimeError), ResolveError(ResolveError), CallError(CallError), + CreationError(CreationError), } impl PartialEq for Error { @@ -220,6 +235,12 @@ impl From for Box { } } +impl From for Box { + fn from(creation_err: CreationError) -> Self { + Box::new(Error::CreationError(creation_err)) + } +} + impl From for Box { fn from(runtime_err: RuntimeError) -> Self { Box::new(CallError::Runtime(runtime_err)) diff --git a/lib/runtime-core/src/global.rs b/lib/runtime-core/src/global.rs index 4d4eb57e0..a84b15f0f 100644 --- a/lib/runtime-core/src/global.rs +++ b/lib/runtime-core/src/global.rs @@ -12,10 +12,28 @@ pub struct Global { } impl Global { + /// Create a new `Global` value. + /// + /// Usage: + /// + /// ``` + /// # use wasmer_runtime_core::global::Global; + /// # use wasmer_runtime_core::types::Value; + /// let global = Global::new(Value::I32(42)); + /// ``` pub fn new(value: Value) -> Self { Self::new_internal(value, false) } + /// Create a new, mutable `Global` value. + /// + /// Usage: + /// + /// ``` + /// # use wasmer_runtime_core::global::Global; + /// # use wasmer_runtime_core::types::Value; + /// let global = Global::new_mutable(Value::I32(42)); + /// ``` pub fn new_mutable(value: Value) -> Self { Self::new_internal(value, true) } @@ -41,10 +59,17 @@ impl Global { } } + /// Get the [`GlobalDescriptor`] generated for this global. + /// + /// [`GlobalDescriptor`]: struct.GlobalDescriptor.html pub fn descriptor(&self) -> GlobalDescriptor { self.desc } + /// Set the value help by this global. + /// + /// This method will panic if the value is + /// the wrong type. pub fn set(&self, value: Value) { if self.desc.mutable { if self.desc.ty == value.ty() { @@ -65,6 +90,7 @@ impl Global { } } + /// Get the value held by this global. pub fn get(&self) -> Value { let data = self.storage.borrow().data; diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 713d94b7d..3781bc5b9 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -19,6 +19,7 @@ pub mod structures; mod sys; pub mod table; pub mod types; +pub mod units; pub mod vm; #[doc(hidden)] pub mod vmcalls; diff --git a/lib/runtime-core/src/memory/dynamic.rs b/lib/runtime-core/src/memory/dynamic.rs index da4361c16..bfe731a83 100644 --- a/lib/runtime-core/src/memory/dynamic.rs +++ b/lib/runtime-core/src/memory/dynamic.rs @@ -1,7 +1,8 @@ use crate::{ - memory::{WASM_MAX_PAGES, WASM_PAGE_SIZE}, + error::CreationError, sys, types::MemoryDescriptor, + units::{Bytes, Pages}, vm, }; @@ -22,24 +23,24 @@ pub const DYNAMIC_GUARD_SIZE: usize = 4096; /// us to add a guard-page at the end to help elide some bounds-checks. pub struct DynamicMemory { memory: sys::Memory, - current: u32, - max: Option, + current: Pages, + max: Option, } impl DynamicMemory { - pub(super) fn new(desc: MemoryDescriptor, local: &mut vm::LocalMemory) -> Option> { + pub(super) fn new( + desc: MemoryDescriptor, + local: &mut vm::LocalMemory, + ) -> Result, CreationError> { + let min_bytes: Bytes = desc.minimum.into(); let memory = { - let mut memory = - sys::Memory::with_size((desc.minimum as usize * WASM_PAGE_SIZE) + DYNAMIC_GUARD_SIZE) - .ok()?; - if desc.minimum != 0 { + let mut memory = sys::Memory::with_size(min_bytes.0 + DYNAMIC_GUARD_SIZE) + .map_err(|_| CreationError::UnableToCreateMemory)?; + if desc.minimum != Pages(0) { unsafe { memory - .protect( - 0..(desc.minimum as usize * WASM_PAGE_SIZE), - sys::Protect::ReadWrite, - ) - .ok()?; + .protect(0..min_bytes.0, sys::Protect::ReadWrite) + .map_err(|_| CreationError::UnableToCreateMemory)?; } } @@ -54,18 +55,18 @@ impl DynamicMemory { let storage_ptr: *mut DynamicMemory = &mut *storage; local.base = storage.memory.as_ptr(); - local.bound = desc.minimum as usize * WASM_PAGE_SIZE; + local.bound = min_bytes.0; local.memory = storage_ptr as *mut (); - Some(storage) + Ok(storage) } - pub fn current(&self) -> u32 { + pub fn size(&self) -> Pages { self.current } - pub fn grow(&mut self, delta: u32, local: &mut vm::LocalMemory) -> Option { - if delta == 0 { + pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Option { + if delta == Pages(0) { return Some(self.current); } @@ -77,30 +78,22 @@ impl DynamicMemory { } } - if new_pages as usize > WASM_MAX_PAGES { - return None; - } - let mut new_memory = - sys::Memory::with_size((new_pages as usize * WASM_PAGE_SIZE) + DYNAMIC_GUARD_SIZE) - .ok()?; + sys::Memory::with_size(new_pages.bytes().0 + DYNAMIC_GUARD_SIZE).ok()?; unsafe { new_memory - .protect( - 0..(new_pages as usize * WASM_PAGE_SIZE), - sys::Protect::ReadWrite, - ) + .protect(0..new_pages.bytes().0, sys::Protect::ReadWrite) .ok()?; - new_memory.as_slice_mut()[..self.current as usize * WASM_PAGE_SIZE] - .copy_from_slice(&self.memory.as_slice()[..self.current as usize * WASM_PAGE_SIZE]); + new_memory.as_slice_mut()[..self.current.bytes().0] + .copy_from_slice(&self.memory.as_slice()[..self.current.bytes().0]); } self.memory = new_memory; //The old memory gets dropped. local.base = self.memory.as_ptr(); - local.bound = new_pages as usize * WASM_PAGE_SIZE; + local.bound = new_pages.bytes().0; let old_pages = self.current; self.current = new_pages; @@ -108,10 +101,10 @@ impl DynamicMemory { } pub fn as_slice(&self) -> &[u8] { - unsafe { &self.memory.as_slice()[0..self.current as usize * WASM_PAGE_SIZE] } + 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 as usize * WASM_PAGE_SIZE] } + unsafe { &mut self.memory.as_slice_mut()[0..self.current.bytes().0] } } } diff --git a/lib/runtime-core/src/memory/mod.rs b/lib/runtime-core/src/memory/mod.rs index fdd9a6e8e..9ec6ee99a 100644 --- a/lib/runtime-core/src/memory/mod.rs +++ b/lib/runtime-core/src/memory/mod.rs @@ -1,9 +1,11 @@ use crate::{ + error::CreationError, export::Export, import::IsExport, memory::dynamic::DYNAMIC_GUARD_SIZE, memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE}, types::{MemoryDescriptor, ValueType}, + units::Pages, vm, }; use std::{cell::RefCell, fmt, mem, ptr, rc::Rc, slice}; @@ -14,9 +16,6 @@ pub use self::static_::{SharedStaticMemory, StaticMemory}; mod dynamic; mod static_; -pub const WASM_PAGE_SIZE: usize = 65_536; -pub const WASM_MAX_PAGES: usize = 65_536; - pub struct Memory { desc: MemoryDescriptor, storage: Rc)>>, @@ -24,29 +23,28 @@ pub struct Memory { impl Memory { /// Create a new `Memory` from a [`MemoryDescriptor`] - /// + /// /// [`MemoryDescriptor`]: struct.MemoryDescriptor.html - /// + /// /// Usage: - /// + /// /// ``` /// # use wasmer_runtime_core::types::MemoryDescriptor; /// # use wasmer_runtime_core::memory::Memory; /// # use wasmer_runtime_core::error::Result; - /// + /// # use wasmer_runtime_core::units::Pages; /// # fn create_memory() -> Result<()> { /// let descriptor = MemoryDescriptor { - /// minimum: 10, + /// minimum: Pages(10), /// maximum: None, /// shared: false, /// }; - /// + /// /// let memory = Memory::new(descriptor)?; - /// /// # Ok(()) /// # } /// ``` - pub fn new(desc: MemoryDescriptor) -> Option { + pub fn new(desc: MemoryDescriptor) -> Result { let mut vm_local_memory = Box::new(vm::LocalMemory { base: ptr::null_mut(), bound: 0, @@ -63,7 +61,7 @@ impl Memory { MemoryType::SharedStatic => unimplemented!("shared memories are not yet implemented"), }; - Some(Memory { + Ok(Memory { desc, storage: Rc::new(RefCell::new((memory_storage, vm_local_memory))), }) @@ -71,14 +69,14 @@ impl Memory { /// Return the [`MemoryDescriptor`] that this memory /// was created with. - /// + /// /// [`MemoryDescriptor`]: struct.MemoryDescriptor.html pub fn descriptor(&self) -> MemoryDescriptor { self.desc } /// Grow this memory by the specfied number of pages. - pub fn grow(&mut self, delta: u32) -> Option { + pub fn grow(&mut self, delta: Pages) -> Option { match &mut *self.storage.borrow_mut() { (MemoryStorage::Dynamic(ref mut dynamic_memory), ref mut local) => { dynamic_memory.grow(delta, local) @@ -90,16 +88,11 @@ impl Memory { } } - /// The size, in bytes, of this memory. - pub fn bytes(&self) -> usize { - (self.size() as usize) * WASM_PAGE_SIZE - } - /// The size, in wasm pages, of this memory. - pub fn size(&self) -> u32 { + pub fn size(&self) -> Pages { match &*self.storage.borrow() { - (MemoryStorage::Dynamic(ref dynamic_memory), _) => dynamic_memory.current(), - (MemoryStorage::Static(ref static_memory), _) => static_memory.current(), + (MemoryStorage::Dynamic(ref dynamic_memory), _) => dynamic_memory.size(), + (MemoryStorage::Static(ref static_memory), _) => static_memory.size(), (MemoryStorage::SharedStatic(_), _) => unimplemented!(), } } @@ -304,7 +297,7 @@ impl fmt::Debug for Memory { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Memory") .field("desc", &self.desc) - .field("size", &self.bytes()) + .field("size", &self.size()) .finish() } } diff --git a/lib/runtime-core/src/memory/static_/unshared.rs b/lib/runtime-core/src/memory/static_/unshared.rs index 2959be24e..420fdc716 100644 --- a/lib/runtime-core/src/memory/static_/unshared.rs +++ b/lib/runtime-core/src/memory/static_/unshared.rs @@ -1,10 +1,9 @@ use crate::{ - memory::{ - static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE}, - WASM_MAX_PAGES, WASM_PAGE_SIZE, - }, + error::CreationError, + memory::static_::{SAFE_STATIC_GUARD_SIZE, SAFE_STATIC_HEAP_SIZE}, sys, types::MemoryDescriptor, + units::Pages, vm, }; @@ -21,26 +20,23 @@ use crate::{ /// allows them to select the type of memory used however. pub struct StaticMemory { memory: sys::Memory, - current: u32, - max: Option, + current: Pages, + max: Option, } impl StaticMemory { pub(in crate::memory) fn new( desc: MemoryDescriptor, local: &mut vm::LocalMemory, - ) -> Option> { + ) -> Result, CreationError> { let memory = { - let mut memory = - sys::Memory::with_size(SAFE_STATIC_HEAP_SIZE + SAFE_STATIC_GUARD_SIZE).ok()?; - if desc.minimum != 0 { + 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 as usize * WASM_PAGE_SIZE), - sys::Protect::ReadWrite, - ) - .ok()?; + .protect(0..desc.minimum.bytes().0, sys::Protect::ReadWrite) + .map_err(|_| CreationError::UnableToCreateMemory)?; } } @@ -55,18 +51,18 @@ impl StaticMemory { let storage_ptr: *mut StaticMemory = &mut *storage; local.base = storage.memory.as_ptr(); - local.bound = desc.minimum as usize * WASM_PAGE_SIZE; + local.bound = desc.minimum.bytes().0; local.memory = storage_ptr as *mut (); - Some(storage) + Ok(storage) } - pub fn current(&self) -> u32 { + pub fn size(&self) -> Pages { self.current } - pub fn grow(&mut self, delta: u32, local: &mut vm::LocalMemory) -> Option { - if delta == 0 { + pub fn grow(&mut self, delta: Pages, local: &mut vm::LocalMemory) -> Option { + if delta == Pages(0) { return Some(self.current); } @@ -78,20 +74,16 @@ impl StaticMemory { } } - if new_pages as usize > WASM_MAX_PAGES { - return None; - } - unsafe { self.memory .protect( - self.current as usize * WASM_PAGE_SIZE..new_pages as usize * WASM_PAGE_SIZE, + self.current.bytes().0..new_pages.bytes().0, sys::Protect::ReadWrite, ) .ok()?; } - local.bound = new_pages as usize * WASM_PAGE_SIZE; + local.bound = new_pages.bytes().0; let old_pages = self.current; @@ -101,10 +93,10 @@ impl StaticMemory { } pub fn as_slice(&self) -> &[u8] { - unsafe { &self.memory.as_slice()[0..self.current as usize * WASM_PAGE_SIZE] } + 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 as usize * WASM_PAGE_SIZE] } + unsafe { &mut self.memory.as_slice_mut()[0..self.current.bytes().0] } } } diff --git a/lib/runtime-core/src/table/anyfunc.rs b/lib/runtime-core/src/table/anyfunc.rs index e295c072b..b211c3ab9 100644 --- a/lib/runtime-core/src/table/anyfunc.rs +++ b/lib/runtime-core/src/table/anyfunc.rs @@ -1,4 +1,5 @@ use crate::{ + error::CreationError, instance::Function, sig_registry::SigRegistry, structures::TypedIndex, @@ -48,7 +49,10 @@ pub struct AnyfuncTable { } impl AnyfuncTable { - pub fn new(desc: TableDescriptor, local: &mut vm::LocalTable) -> Result, ()> { + pub fn new( + desc: TableDescriptor, + local: &mut vm::LocalTable, + ) -> Result, CreationError> { let initial_table_backing_len = match desc.maximum { Some(max) => max, None => desc.minimum, diff --git a/lib/runtime-core/src/table/mod.rs b/lib/runtime-core/src/table/mod.rs index 7aac2953a..ee312d917 100644 --- a/lib/runtime-core/src/table/mod.rs +++ b/lib/runtime-core/src/table/mod.rs @@ -1,4 +1,5 @@ use crate::{ + error::CreationError, export::Export, import::IsExport, types::{ElementType, TableDescriptor}, @@ -28,29 +29,27 @@ pub struct Table { impl Table { /// Create a new `Table` from a [`TableDescriptor`] - /// + /// /// [`TableDescriptor`]: struct.TableDescriptor.html - /// + /// /// Usage: - /// + /// /// ``` /// # use wasmer_runtime_core::types::{TableDescriptor, ElementType}; /// # use wasmer_runtime_core::table::Table; /// # use wasmer_runtime_core::error::Result; - /// /// # fn create_table() -> Result<()> { /// let descriptor = TableDescriptor { /// element: ElementType::Anyfunc, /// minimum: 10, /// maximum: None, /// }; - /// + /// /// let table = Table::new(descriptor)?; - /// /// # Ok(()) /// # } /// ``` - pub fn new(desc: TableDescriptor) -> Result { + pub fn new(desc: TableDescriptor) -> Result { let mut local = vm::LocalTable { base: ptr::null_mut(), count: 0, @@ -67,10 +66,12 @@ impl Table { }) } + /// Get the `TableDescriptor` used to create this `Table`. pub fn descriptor(&self) -> TableDescriptor { self.desc } + /// Set the element at index. pub fn set(&self, index: u32, element: Element) -> Result<(), ()> { match &mut *self.storage.borrow_mut() { (TableStorage::Anyfunc(ref mut anyfunc_table), _) => { @@ -91,15 +92,17 @@ impl Table { } } - pub fn current_size(&self) -> u32 { + /// The current size of this table. + pub fn size(&self) -> u32 { match &*self.storage.borrow() { (TableStorage::Anyfunc(ref anyfunc_table), _) => anyfunc_table.current_size(), } } + /// Grow this table by `delta`. pub fn grow(&self, delta: u32) -> Option { if delta == 0 { - return Some(self.current_size()); + return Some(self.size()); } match &mut *self.storage.borrow_mut() { @@ -131,6 +134,9 @@ impl Clone for Table { impl fmt::Debug for Table { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Table").field("desc", &self.desc).finish() + f.debug_struct("Table") + .field("desc", &self.desc) + .field("size", &self.size()) + .finish() } } diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index f8ee76dbd..0ed0134a4 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -1,4 +1,4 @@ -use crate::{memory::MemoryType, module::ModuleInner, structures::TypedIndex}; +use crate::{memory::MemoryType, module::ModuleInner, structures::TypedIndex, units::Pages}; use std::{borrow::Cow, mem}; /// Represents a WebAssembly type. @@ -142,7 +142,9 @@ impl TableDescriptor { // TODO: We should define implementation limits. let imported_max = imported.maximum.unwrap_or(u32::max_value()); let self_max = self.maximum.unwrap_or(u32::max_value()); - self.element == imported.element && imported_max <= self_max && self.minimum <= imported.minimum + self.element == imported.element + && imported_max <= self_max + && self.minimum <= imported.minimum } } @@ -174,9 +176,9 @@ pub struct GlobalInit { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct MemoryDescriptor { /// The minimum number of allowed pages. - pub minimum: u32, + pub minimum: Pages, /// The maximum number of allowed pages. - pub maximum: Option, + pub maximum: Option, /// This memory can be shared between wasm threads. pub shared: bool, } @@ -192,10 +194,12 @@ impl MemoryDescriptor { } pub(crate) fn fits_in_imported(&self, imported: MemoryDescriptor) -> bool { - let imported_max = imported.maximum.unwrap_or(65_536); - let self_max = self.maximum.unwrap_or(65_536); + let imported_max = imported.maximum.unwrap_or(Pages(65_536)); + let self_max = self.maximum.unwrap_or(Pages(65_536)); - self.shared == imported.shared && imported_max <= self_max && self.minimum <= imported.minimum + self.shared == imported.shared + && imported_max <= self_max + && self.minimum <= imported.minimum } } diff --git a/lib/runtime-core/src/units.rs b/lib/runtime-core/src/units.rs new file mode 100644 index 000000000..9802d39e7 --- /dev/null +++ b/lib/runtime-core/src/units.rs @@ -0,0 +1,94 @@ +use std::{ + fmt, + ops::{Add, Sub}, +}; + +const WASM_PAGE_SIZE: usize = 65_536; +const WASM_MAX_PAGES: usize = 65_536; + +/// Units of WebAssembly pages (as specified to be 65,536 bytes). +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Pages(pub u32); + +impl Pages { + pub fn checked_add(self, rhs: Pages) -> Option { + let added = (self.0 as usize) + (rhs.0 as usize); + if added <= WASM_MAX_PAGES { + Some(Pages(added as u32)) + } else { + None + } + } + + pub fn bytes(self) -> Bytes { + self.into() + } +} + +impl fmt::Debug for Pages { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} pages", self.0) + } +} + +/// Units of WebAssembly memory in terms of 8-bit bytes. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Bytes(pub usize); + +impl fmt::Debug for Bytes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} bytes", self.0) + } +} + +impl From for Bytes { + fn from(pages: Pages) -> Bytes { + Bytes((pages.0 as usize) * WASM_PAGE_SIZE) + } +} + +impl Sub for Pages +where + T: Into, +{ + type Output = Pages; + fn sub(self, rhs: T) -> Pages { + Pages(self.0 - rhs.into().0) + } +} + +impl Add for Pages +where + T: Into, +{ + type Output = Pages; + fn add(self, rhs: T) -> Pages { + Pages(self.0 + rhs.into().0) + } +} + +impl From for Pages { + fn from(bytes: Bytes) -> Pages { + Pages((bytes.0 / WASM_PAGE_SIZE) as u32) + } +} + +impl Sub for Bytes +where + T: Into, +{ + type Output = Bytes; + fn sub(self, rhs: T) -> Bytes { + Bytes(self.0 - rhs.into().0) + } +} + +impl Add for Bytes +where + T: Into, +{ + type Output = Bytes; + fn add(self, rhs: T) -> Bytes { + Bytes(self.0 + rhs.into().0) + } +} diff --git a/lib/runtime-core/src/vmcalls.rs b/lib/runtime-core/src/vmcalls.rs index 12b513ce8..8a6e683b5 100644 --- a/lib/runtime-core/src/vmcalls.rs +++ b/lib/runtime-core/src/vmcalls.rs @@ -4,6 +4,7 @@ use crate::{ memory::{DynamicMemory, StaticMemory}, structures::TypedIndex, types::{ImportedMemoryIndex, LocalMemoryIndex, LocalTableIndex}, + units::Pages, vm, }; @@ -13,14 +14,14 @@ use crate::{ pub unsafe extern "C" fn local_static_memory_grow( memory_index: LocalMemoryIndex, - delta: u32, + delta: Pages, ctx: &mut vm::Ctx, ) -> i32 { let local_memory = *ctx.memories.add(memory_index.index()); let memory = (*local_memory).memory as *mut StaticMemory; if let Some(old) = (*memory).grow(delta, &mut *local_memory) { - old as i32 + old.0 as i32 } else { -1 } @@ -29,23 +30,23 @@ pub unsafe extern "C" fn local_static_memory_grow( pub unsafe extern "C" fn local_static_memory_size( memory_index: LocalMemoryIndex, ctx: &vm::Ctx, -) -> u32 { +) -> Pages { let local_memory = *ctx.memories.add(memory_index.index()); let memory = (*local_memory).memory as *mut StaticMemory; - (*memory).current() + (*memory).size() } pub unsafe extern "C" fn local_dynamic_memory_grow( memory_index: LocalMemoryIndex, - delta: u32, + delta: Pages, ctx: &mut vm::Ctx, ) -> i32 { let local_memory = *ctx.memories.add(memory_index.index()); let memory = (*local_memory).memory as *mut DynamicMemory; if let Some(old) = (*memory).grow(delta, &mut *local_memory) { - old as i32 + old.0 as i32 } else { -1 } @@ -54,11 +55,11 @@ pub unsafe extern "C" fn local_dynamic_memory_grow( pub unsafe extern "C" fn local_dynamic_memory_size( memory_index: LocalMemoryIndex, ctx: &vm::Ctx, -) -> u32 { +) -> Pages { let local_memory = *ctx.memories.add(memory_index.index()); let memory = (*local_memory).memory as *mut DynamicMemory; - (*memory).current() + (*memory).size() } // +*****************************+ @@ -67,14 +68,14 @@ pub unsafe extern "C" fn local_dynamic_memory_size( pub unsafe extern "C" fn imported_static_memory_grow( import_memory_index: ImportedMemoryIndex, - delta: u32, + delta: Pages, ctx: &mut vm::Ctx, ) -> i32 { let local_memory = *ctx.imported_memories.add(import_memory_index.index()); let memory = (*local_memory).memory as *mut StaticMemory; if let Some(old) = (*memory).grow(delta, &mut *local_memory) { - old as i32 + old.0 as i32 } else { -1 } @@ -83,23 +84,23 @@ pub unsafe extern "C" fn imported_static_memory_grow( pub unsafe extern "C" fn imported_static_memory_size( import_memory_index: ImportedMemoryIndex, ctx: &vm::Ctx, -) -> u32 { +) -> Pages { let local_memory = *ctx.imported_memories.add(import_memory_index.index()); let memory = (*local_memory).memory as *mut StaticMemory; - (*memory).current() + (*memory).size() } pub unsafe extern "C" fn imported_dynamic_memory_grow( memory_index: ImportedMemoryIndex, - delta: u32, + delta: Pages, ctx: &mut vm::Ctx, ) -> i32 { let local_memory = *ctx.imported_memories.add(memory_index.index()); let memory = (*local_memory).memory as *mut DynamicMemory; if let Some(old) = (*memory).grow(delta, &mut *local_memory) { - old as i32 + old.0 as i32 } else { -1 } @@ -108,11 +109,11 @@ pub unsafe extern "C" fn imported_dynamic_memory_grow( pub unsafe extern "C" fn imported_dynamic_memory_size( memory_index: ImportedMemoryIndex, ctx: &vm::Ctx, -) -> u32 { +) -> Pages { let local_memory = *ctx.imported_memories.add(memory_index.index()); let memory = (*local_memory).memory as *mut DynamicMemory; - (*memory).current() + (*memory).size() } // +*****************************+ diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 9fd78822b..50acade30 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -88,6 +88,7 @@ pub use wasmer_runtime_core::error; pub use wasmer_runtime_core::{func, imports}; pub mod wasm { + //! Various types exposed by the Wasmer Runtime. pub use wasmer_runtime_core::global::Global; pub use wasmer_runtime_core::instance::Function; pub use wasmer_runtime_core::memory::Memory; @@ -95,6 +96,12 @@ pub mod wasm { pub use wasmer_runtime_core::types::{FuncSig, MemoryDescriptor, TableDescriptor, Type, Value}; } +pub mod units { + //! Various unit types. + + pub use wasmer_runtime_core::units::{Bytes, Pages}; +} + /// Compile WebAssembly binary code into a [`Module`]. /// This function is useful if it is necessary to /// compile a module before it can be instantiated