diff --git a/lib/api/src/externals/table.rs b/lib/api/src/externals/table.rs index 74b14f742..ba4c22d28 100644 --- a/lib/api/src/externals/table.rs +++ b/lib/api/src/externals/table.rs @@ -20,7 +20,7 @@ pub struct Table { } fn set_table_item( - table: &RuntimeTable, + table: &dyn RuntimeTable, item_index: u32, item: VMCallerCheckedAnyfunc, ) -> Result<(), RuntimeError> { @@ -41,21 +41,21 @@ impl Table { let definition = table.vmtable(); for i in 0..definition.current_elements { - set_table_item(&table, i, item.clone())?; + set_table_item(table.as_ref(), i, item.clone())?; } Ok(Table { store: store.clone(), owned_by_store: true, exported: ExportTable { - from: Box::leak(Box::new(table)), + from: table, definition: Box::leak(Box::new(definition)), }, }) } - fn table(&self) -> &RuntimeTable { - unsafe { &*self.exported.from } + fn table(&self) -> &dyn RuntimeTable { + &*self.exported.from } /// Gets the underlying [`TableType`]. diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 327c5df8a..03c7d5b33 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -12,6 +12,7 @@ mod native; mod ordered_resolver; mod ptr; mod store; +mod table; mod tunables; mod types; mod utils; diff --git a/lib/api/src/table.rs b/lib/api/src/table.rs new file mode 100644 index 000000000..e984be57a --- /dev/null +++ b/lib/api/src/table.rs @@ -0,0 +1,104 @@ +use crate::ValType; +use std::cell::RefCell; +use std::convert::{TryFrom, TryInto}; +use wasmer_runtime::{ + Table, TablePlan, TableStyle, Trap, TrapCode, VMCallerCheckedAnyfunc, VMTableDefinition, +}; + +/// A table instance. +#[derive(Debug)] +pub struct LinearTable { + vec: RefCell>, + maximum: Option, + plan: TablePlan, +} + +impl LinearTable { + /// Create a new table instance with specified minimum and maximum number of elements. + pub fn new(plan: &TablePlan) -> Result { + match plan.table.ty { + ValType::FuncRef => (), + ty => return Err(format!("tables of types other than anyfunc ({})", ty)), + }; + if let Some(max) = plan.table.maximum { + if max < plan.table.minimum { + return Err(format!( + "Table minimum ({}) is larger than maximum ({})!", + plan.table.minimum, max + )); + } + } + match plan.style { + TableStyle::CallerChecksSignature => Ok(Self { + vec: RefCell::new(vec![ + VMCallerCheckedAnyfunc::default(); + usize::try_from(plan.table.minimum).map_err(|_| { + "Table minimum is bigger than usize".to_string() + })? + ]), + maximum: plan.table.maximum, + plan: plan.clone(), + }), + } + } +} + +impl Table for LinearTable { + /// Returns the table plan for this Table. + fn plan(&self) -> &TablePlan { + &self.plan + } + + /// Returns the number of allocated elements. + fn size(&self) -> u32 { + self.vec.borrow().len().try_into().unwrap() + } + + /// Grow table by the specified amount of elements. + /// + /// Returns `None` if table can't be grown by the specified amount + /// of elements, otherwise returns the previous size of the table. + fn grow(&self, delta: u32) -> Option { + let size = self.size(); + let new_len = size.checked_add(delta)?; + if self.maximum.map_or(false, |max| new_len > max) { + return None; + } + self.vec.borrow_mut().resize( + usize::try_from(new_len).unwrap(), + VMCallerCheckedAnyfunc::default(), + ); + Some(size) + } + + /// Get reference to the specified element. + /// + /// Returns `None` if the index is out of bounds. + fn get(&self, index: u32) -> Option { + self.vec.borrow().get(index as usize).cloned() + } + + /// Set reference to the specified element. + /// + /// # Errors + /// + /// Returns an error if the index is out of bounds. + fn set(&self, index: u32, func: VMCallerCheckedAnyfunc) -> Result<(), Trap> { + match self.vec.borrow_mut().get_mut(index as usize) { + Some(slot) => { + *slot = func; + Ok(()) + } + None => Err(Trap::wasm(TrapCode::TableAccessOutOfBounds)), + } + } + + /// Return a `VMTableDefinition` for exposing the table to compiled wasm code. + fn vmtable(&self) -> VMTableDefinition { + let mut vec = self.vec.borrow_mut(); + VMTableDefinition { + base: vec.as_mut_ptr() as *mut u8, + current_elements: vec.len().try_into().unwrap(), + } + } +} diff --git a/lib/api/src/tunables.rs b/lib/api/src/tunables.rs index 9cb11c7eb..bb5f79e47 100644 --- a/lib/api/src/tunables.rs +++ b/lib/api/src/tunables.rs @@ -1,4 +1,5 @@ use crate::memory::LinearMemory; +use crate::table::LinearTable; use crate::{MemoryType, Pages, TableType}; use more_asserts::assert_ge; use std::cmp::min; @@ -97,8 +98,8 @@ impl BaseTunables for Tunables { } /// Create a memory given a memory type - fn create_table(&self, plan: TablePlan) -> Result { - Table::new(&plan) + fn create_table(&self, plan: TablePlan) -> Result, String> { + Ok(Arc::new(LinearTable::new(&plan)?)) } } diff --git a/lib/engine/src/resolver.rs b/lib/engine/src/resolver.rs index dfa97270d..ba6b5e1e5 100644 --- a/lib/engine/src/resolver.rs +++ b/lib/engine/src/resolver.rs @@ -181,7 +181,7 @@ pub fn resolve_imports( Export::Table(ref t) => { table_imports.push(VMTableImport { definition: t.definition, - from: t.from, + from: t.from.clone(), }); } Export::Memory(ref m) => { diff --git a/lib/engine/src/tunables.rs b/lib/engine/src/tunables.rs index 0fe399248..0f7a25f51 100644 --- a/lib/engine/src/tunables.rs +++ b/lib/engine/src/tunables.rs @@ -21,7 +21,7 @@ pub trait Tunables { fn create_memory(&self, memory_type: MemoryPlan) -> Result, MemoryError>; /// Create a memory given a memory type - fn create_table(&self, table_type: TablePlan) -> Result; + fn create_table(&self, table_type: TablePlan) -> Result, String>; /// Allocate memory for just the memories of the current module. fn create_memories( @@ -47,7 +47,7 @@ pub trait Tunables { &self, module: &ModuleInfo, table_plans: &PrimaryMap, - ) -> Result, LinkError> { + ) -> Result>, LinkError> { let num_imports = module.num_imported_tables; let mut tables: PrimaryMap = PrimaryMap::with_capacity(module.tables.len() - num_imports); diff --git a/lib/runtime/src/export.rs b/lib/runtime/src/export.rs index b106eb034..29a21d35b 100644 --- a/lib/runtime/src/export.rs +++ b/lib/runtime/src/export.rs @@ -51,18 +51,19 @@ pub struct ExportTable { /// The address of the table descriptor. pub definition: *mut VMTableDefinition, /// Pointer to the containing `Table`. - pub from: *mut Table, + pub from: Arc, } impl ExportTable { /// Get the plan for this exported memory pub fn plan(&self) -> &TablePlan { - unsafe { self.from.as_ref().unwrap() }.plan() + self.from.plan() } /// Returns whether or not the two `ExportTable`s refer to the same Memory. pub fn same(&self, other: &Self) -> bool { - self.definition == other.definition && self.from == other.from + // TODO: comparing + self.definition == other.definition //&& self.from == other.from } } diff --git a/lib/runtime/src/instance.rs b/lib/runtime/src/instance.rs index 612bb9cad..c01dd0daa 100644 --- a/lib/runtime/src/instance.rs +++ b/lib/runtime/src/instance.rs @@ -76,7 +76,7 @@ pub(crate) struct Instance { memories: BoxedSlice>, /// WebAssembly table data. - tables: BoxedSlice, + tables: BoxedSlice>, /// Passive elements in this instantiation. As `elem.drop`s happen, these /// entries get removed. A missing entry is considered equivalent to an @@ -312,13 +312,10 @@ impl Instance { ExportIndex::Table(index) => { let (definition, from) = if let Some(def_index) = self.module.local_table_index(*index) { - ( - self.table_ptr(def_index), - self.tables[def_index].as_mut_ptr(), - ) + (self.table_ptr(def_index), self.tables[def_index].clone()) } else { let import = self.imported_table(*index); - (import.definition, import.from) + (import.definition, import.from.clone()) }; ExportTable { definition, from }.into() } @@ -735,7 +732,7 @@ impl Instance { /// Get a table by index regardless of whether it is locally-defined or an /// imported, foreign table. - pub(crate) fn get_table(&self, table_index: TableIndex) -> &Table { + pub(crate) fn get_table(&self, table_index: TableIndex) -> &dyn Table { if let Some(local_table_index) = self.module.local_table_index(table_index) { self.get_local_table(local_table_index) } else { @@ -744,15 +741,14 @@ impl Instance { } /// Get a locally-defined table. - pub(crate) fn get_local_table(&self, index: LocalTableIndex) -> &Table { - &self.tables[index] + pub(crate) fn get_local_table(&self, index: LocalTableIndex) -> &dyn Table { + self.tables[index].as_ref() } /// Get an imported, foreign table. - pub(crate) fn get_foreign_table(&self, index: TableIndex) -> &Table { + pub(crate) fn get_foreign_table(&self, index: TableIndex) -> &dyn Table { let import = self.imported_table(index); - unsafe { &*import.from } - // *unsafe { import.table.as_ref().unwrap() } + &*import.from } } @@ -783,7 +779,7 @@ impl InstanceHandle { module: Arc, finished_functions: BoxedSlice, finished_memories: BoxedSlice>, - finished_tables: BoxedSlice, + finished_tables: BoxedSlice>, finished_globals: BoxedSlice, imports: Imports, vmshared_signatures: BoxedSlice, @@ -791,7 +787,7 @@ impl InstanceHandle { ) -> Result { let vmctx_tables = finished_tables .values() - .map(Table::vmtable) + .map(|t| t.vmtable()) .collect::>() .into_boxed_slice(); @@ -1033,7 +1029,7 @@ impl InstanceHandle { } /// Get a table defined locally within this module. - pub fn get_local_table(&self, index: LocalTableIndex) -> &Table { + pub fn get_local_table(&self, index: LocalTableIndex) -> &dyn Table { self.instance().get_local_table(index) } diff --git a/lib/runtime/src/libcalls.rs b/lib/runtime/src/libcalls.rs index 6d3a24b0d..ec67422f9 100644 --- a/lib/runtime/src/libcalls.rs +++ b/lib/runtime/src/libcalls.rs @@ -36,7 +36,6 @@ //! ``` use crate::probestack::PROBESTACK; -use crate::table::Table; use crate::trap::{raise_lib_trap, Trap, TrapCode}; use crate::vmcontext::VMContext; use serde::{Deserialize, Serialize}; @@ -217,7 +216,7 @@ pub unsafe extern "C" fn wasmer_table_copy( let instance = (&*vmctx).instance(); let dst_table = instance.get_table(dst_table_index); let src_table = instance.get_table(src_table_index); - Table::copy(dst_table, src_table, dst, src, len) + dst_table.copy(src_table, dst, src, len) }; if let Err(trap) = result { raise_lib_trap(trap); diff --git a/lib/runtime/src/table.rs b/lib/runtime/src/table.rs index d1fbca7e4..920b24476 100644 --- a/lib/runtime/src/table.rs +++ b/lib/runtime/src/table.rs @@ -8,9 +8,8 @@ use crate::trap::{Trap, TrapCode}; use crate::vmcontext::{VMCallerCheckedAnyfunc, VMTableDefinition}; use serde::{Deserialize, Serialize}; -use std::cell::RefCell; -use std::convert::{TryFrom, TryInto}; -use wasm_common::{FunctionIndex, GlobalIndex, TableIndex, TableType, Type}; +use std::fmt; +use wasm_common::{FunctionIndex, GlobalIndex, TableIndex, TableType}; /// A WebAssembly table initializer. #[derive(Clone, Debug, Hash, Serialize, Deserialize)] @@ -42,91 +41,34 @@ pub struct TablePlan { pub style: TableStyle, } -/// A table instance. -#[derive(Debug)] -pub struct Table { - vec: RefCell>, - maximum: Option, - plan: TablePlan, -} - -impl Table { - /// Create a new table instance with specified minimum and maximum number of elements. - pub fn new(plan: &TablePlan) -> Result { - match plan.table.ty { - Type::FuncRef => (), - ty => return Err(format!("tables of types other than anyfunc ({})", ty)), - }; - if let Some(max) = plan.table.maximum { - if max < plan.table.minimum { - return Err(format!( - "Table minimum ({}) is larger than maximum ({})!", - plan.table.minimum, max - )); - } - } - match plan.style { - TableStyle::CallerChecksSignature => Ok(Self { - vec: RefCell::new(vec![ - VMCallerCheckedAnyfunc::default(); - usize::try_from(plan.table.minimum).map_err(|_| { - "Table minimum is bigger than usize".to_string() - })? - ]), - maximum: plan.table.maximum, - plan: plan.clone(), - }), - } - } - +/// Trait for implementing the interface of a Wasm table. +pub trait Table: fmt::Debug { /// Returns the table plan for this Table. - pub fn plan(&self) -> &TablePlan { - &self.plan - } + fn plan(&self) -> &TablePlan; /// Returns the number of allocated elements. - pub fn size(&self) -> u32 { - self.vec.borrow().len().try_into().unwrap() - } + fn size(&self) -> u32; /// Grow table by the specified amount of elements. /// /// Returns `None` if table can't be grown by the specified amount /// of elements, otherwise returns the previous size of the table. - pub fn grow(&self, delta: u32) -> Option { - let size = self.size(); - let new_len = size.checked_add(delta)?; - if self.maximum.map_or(false, |max| new_len > max) { - return None; - } - self.vec.borrow_mut().resize( - usize::try_from(new_len).unwrap(), - VMCallerCheckedAnyfunc::default(), - ); - Some(size) - } + fn grow(&self, delta: u32) -> Option; /// Get reference to the specified element. /// /// Returns `None` if the index is out of bounds. - pub fn get(&self, index: u32) -> Option { - self.vec.borrow().get(index as usize).cloned() - } + fn get(&self, index: u32) -> Option; /// Set reference to the specified element. /// /// # Errors /// /// Returns an error if the index is out of bounds. - pub fn set(&self, index: u32, func: VMCallerCheckedAnyfunc) -> Result<(), Trap> { - match self.vec.borrow_mut().get_mut(index as usize) { - Some(slot) => { - *slot = func; - Ok(()) - } - None => Err(Trap::wasm(TrapCode::TableAccessOutOfBounds)), - } - } + fn set(&self, index: u32, func: VMCallerCheckedAnyfunc) -> Result<(), Trap>; + + /// Return a `VMTableDefinition` for exposing the table to compiled wasm code. + fn vmtable(&self) -> VMTableDefinition; /// Copy `len` elements from `src_table[src_index..]` into `dst_table[dst_index..]`. /// @@ -134,9 +76,9 @@ impl Table { /// /// Returns an error if the range is out of bounds of either the source or /// destination tables. - pub fn copy( - dst_table: &Self, - src_table: &Self, + fn copy( + &self, + src_table: &dyn Table, dst_index: u32, src_index: u32, len: u32, @@ -150,10 +92,7 @@ impl Table { return Err(Trap::wasm(TrapCode::TableAccessOutOfBounds)); } - if dst_index - .checked_add(len) - .map_or(true, |m| m > dst_table.size()) - { + if dst_index.checked_add(len).map_or(true, |m| m > self.size()) { return Err(Trap::wasm(TrapCode::TableSetterOutOfBounds)); } @@ -166,31 +105,14 @@ impl Table { // TODO: investigate replacing this get/set loop with a `memcpy`. if dst_index <= src_index { for (s, d) in (srcs).zip(dsts) { - dst_table.set(d, src_table.get(s).unwrap())?; + self.set(d, src_table.get(s).unwrap())?; } } else { for (s, d) in srcs.rev().zip(dsts.rev()) { - dst_table.set(d, src_table.get(s).unwrap())?; + self.set(d, src_table.get(s).unwrap())?; } } Ok(()) } - - /// Return a `VMTableDefinition` for exposing the table to compiled wasm code. - pub fn vmtable(&self) -> VMTableDefinition { - let mut vec = self.vec.borrow_mut(); - VMTableDefinition { - base: vec.as_mut_ptr() as *mut u8, - current_elements: vec.len().try_into().unwrap(), - } - } - - /// Get the table host as mutable pointer - /// - /// This function is used in the `wasmer_runtime::Instance` to retrieve - /// the host table pointer and interact with the host table directly. - pub fn as_mut_ptr(&self) -> *mut Self { - self as *const Self as *mut Self - } } diff --git a/lib/runtime/src/vmcontext.rs b/lib/runtime/src/vmcontext.rs index c7f857619..0c1198bb2 100644 --- a/lib/runtime/src/vmcontext.rs +++ b/lib/runtime/src/vmcontext.rs @@ -136,14 +136,14 @@ pub enum VMFunctionKind { /// The fields compiled code needs to access to utilize a WebAssembly table /// imported from another instance. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone)] #[repr(C)] pub struct VMTableImport { /// A pointer to the imported table description. pub definition: *mut VMTableDefinition, /// A pointer to the `Table` that owns the table description. - pub from: *mut Table, + pub from: Arc, } #[cfg(test)] diff --git a/lib/runtime/src/vmoffsets.rs b/lib/runtime/src/vmoffsets.rs index b0c3fdb6e..e0566ee2c 100644 --- a/lib/runtime/src/vmoffsets.rs +++ b/lib/runtime/src/vmoffsets.rs @@ -166,7 +166,7 @@ impl VMOffsets { /// /// [`VMTableImport`]: crate::vmcontext::VMTableImport pub const fn size_of_vmtable_import(&self) -> u8 { - 2 * self.pointer_size + 3 * self.pointer_size } }