mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-06 20:58:28 +00:00
Add Table as a trait
This commit is contained in:
10
lib/api/src/externals/table.rs
vendored
10
lib/api/src/externals/table.rs
vendored
@@ -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`].
|
||||
|
||||
@@ -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
104
lib/api/src/table.rs
Normal 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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)?))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user