Add Table as a trait

This commit is contained in:
Mark McCaskey
2020-06-17 12:18:22 -07:00
parent 67044eb9bb
commit 3d46711cb3
12 changed files with 153 additions and 129 deletions

View File

@@ -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`].

View File

@@ -12,6 +12,7 @@ mod native;
mod ordered_resolver;
mod ptr;
mod store;
mod table;
mod tunables;
mod types;
mod utils;

104
lib/api/src/table.rs Normal file
View File

@@ -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<Vec<VMCallerCheckedAnyfunc>>,
maximum: Option<u32>,
plan: TablePlan,
}
impl LinearTable {
/// Create a new table instance with specified minimum and maximum number of elements.
pub fn new(plan: &TablePlan) -> Result<Self, String> {
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<u32> {
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<VMCallerCheckedAnyfunc> {
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(),
}
}
}

View File

@@ -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, String> {
Table::new(&plan)
fn create_table(&self, plan: TablePlan) -> Result<Arc<dyn Table>, String> {
Ok(Arc::new(LinearTable::new(&plan)?))
}
}

View File

@@ -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) => {

View File

@@ -21,7 +21,7 @@ pub trait Tunables {
fn create_memory(&self, memory_type: MemoryPlan) -> Result<Arc<dyn Memory>, MemoryError>;
/// Create a memory given a memory type
fn create_table(&self, table_type: TablePlan) -> Result<Table, String>;
fn create_table(&self, table_type: TablePlan) -> Result<Arc<dyn Table>, 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<TableIndex, TablePlan>,
) -> Result<PrimaryMap<LocalTableIndex, Table>, LinkError> {
) -> Result<PrimaryMap<LocalTableIndex, Arc<dyn Table>>, LinkError> {
let num_imports = module.num_imported_tables;
let mut tables: PrimaryMap<LocalTableIndex, _> =
PrimaryMap::with_capacity(module.tables.len() - num_imports);

View File

@@ -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<dyn Table>,
}
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
}
}

View File

@@ -76,7 +76,7 @@ pub(crate) struct Instance {
memories: BoxedSlice<LocalMemoryIndex, Arc<dyn Memory>>,
/// WebAssembly table data.
tables: BoxedSlice<LocalTableIndex, Table>,
tables: BoxedSlice<LocalTableIndex, Arc<dyn Table>>,
/// 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<ModuleInfo>,
finished_functions: BoxedSlice<LocalFunctionIndex, *mut [VMFunctionBody]>,
finished_memories: BoxedSlice<LocalMemoryIndex, Arc<dyn Memory>>,
finished_tables: BoxedSlice<LocalTableIndex, Table>,
finished_tables: BoxedSlice<LocalTableIndex, Arc<dyn Table>>,
finished_globals: BoxedSlice<LocalGlobalIndex, VMGlobalDefinition>,
imports: Imports,
vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
@@ -791,7 +787,7 @@ impl InstanceHandle {
) -> Result<Self, Trap> {
let vmctx_tables = finished_tables
.values()
.map(Table::vmtable)
.map(|t| t.vmtable())
.collect::<PrimaryMap<LocalTableIndex, _>>()
.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)
}

View File

@@ -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);

View File

@@ -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<Vec<VMCallerCheckedAnyfunc>>,
maximum: Option<u32>,
plan: TablePlan,
}
impl Table {
/// Create a new table instance with specified minimum and maximum number of elements.
pub fn new(plan: &TablePlan) -> Result<Self, String> {
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<u32> {
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<u32>;
/// Get reference to the specified element.
///
/// Returns `None` if the index is out of bounds.
pub fn get(&self, index: u32) -> Option<VMCallerCheckedAnyfunc> {
self.vec.borrow().get(index as usize).cloned()
}
fn get(&self, index: u32) -> Option<VMCallerCheckedAnyfunc>;
/// 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
}
}

View File

@@ -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<dyn Table>,
}
#[cfg(test)]

View File

@@ -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
}
}