@ -3,7 +3,7 @@
//! `Table` is to WebAssembly tables what `LinearMemory` is to WebAssembly linear memories.
use crate ::vmcontext ::{ VMCallerCheckedAnyfunc , VMTableDefinition } ;
use crate ::Trap ;
use crate ::{ Trap , VMExternRef } ;
use std ::cell ::RefCell ;
use std ::convert ::{ TryFrom , TryInto } ;
use wasmtime_environ ::wasm ::TableElementType ;
@ -12,25 +12,46 @@ use wasmtime_environ::{ir, TablePlan, TableStyle};
/// A table instance.
#[ derive(Debug) ]
pub struct Table {
vec : RefCell < Vec < VMCallerCheckedAnyfunc > > ,
elements : RefCell < TableElements > ,
maximum : Option < u32 > ,
}
/// An element going into or coming out of a table.
#[ derive(Clone, Debug) ]
pub enum TableElement {
/// A `funcref`.
FuncRef ( VMCallerCheckedAnyfunc ) ,
/// An `exrernref`.
ExternRef ( Option < VMExternRef > ) ,
}
#[ derive(Debug) ]
enum TableElements {
FuncRefs ( Vec < VMCallerCheckedAnyfunc > ) ,
ExternRefs ( Vec < Option < VMExternRef > > ) ,
}
impl Table {
/// Create a new table instance with specified minimum and maximum number of elements.
pub fn new ( plan : & TablePlan ) -> Self {
match plan . table . ty {
TableElementType ::Func = > ( ) ,
TableElementType ::Val ( ty ) = > {
unimplemented ! ( "tables of types other than anyfunc ({})" , ty )
}
} ;
match plan . style {
TableStyle ::CallerChecksSignature = > Self {
vec : RefCell ::new ( vec ! [
let elements =
RefCell ::new ( match plan . table . ty {
TableElementType ::Func = > TableElements ::FuncRefs ( vec ! [
VMCallerCheckedAnyfunc ::default ( ) ;
usize ::try_from ( plan . table . minimum ) . unwrap ( )
] ) ,
TableElementType ::Val ( ty )
if ( cfg ! ( target_pointer_width = "64" ) & & ty = = ir ::types ::R64 )
| | ( cfg ! ( target_pointer_width = "32" ) & & ty = = ir ::types ::R32 ) = >
{
let min = usize ::try_from ( plan . table . minimum ) . unwrap ( ) ;
TableElements ::ExternRefs ( vec ! [ None ; min ] )
}
TableElementType ::Val ( ty ) = > unimplemented ! ( "unsupported table type ({})" , ty ) ,
} ) ;
match plan . style {
TableStyle ::CallerChecksSignature = > Self {
elements ,
maximum : plan . table . maximum ,
} ,
}
@ -38,7 +59,10 @@ impl Table {
/// Returns the number of allocated elements.
pub fn size ( & self ) -> u32 {
self . vec . borrow ( ) . len ( ) . try_into ( ) . unwrap ( )
match & * self . elements . borrow ( ) {
TableElements ::FuncRefs ( x ) = > x . len ( ) . try_into ( ) . unwrap ( ) ,
TableElements ::ExternRefs ( x ) = > x . len ( ) . try_into ( ) . unwrap ( ) ,
}
}
/// Grow table by the specified amount of elements.
@ -61,33 +85,45 @@ impl Table {
return None ;
}
} ;
self . vec . borrow_mut ( ) . resize (
usize ::try_from ( new_len ) . unwrap ( ) ,
VMCallerCheckedAnyfunc ::default ( ) ,
) ;
let new_len = usize ::try_from ( new_len ) . unwrap ( ) ;
match & mut * self . elements . borrow_mut ( ) {
TableElements ::FuncRefs ( x ) = > x . resize ( new_len , VMCallerCheckedAnyfunc ::default ( ) ) ,
TableElements ::ExternRefs ( x ) = > x . resize ( new_len , None ) ,
}
Some ( size )
}
/// 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 ( )
pub fn get ( & self , index : u32 ) -> Option < TableElement > {
match & * self . elements . borrow ( ) {
TableElements ::FuncRefs ( x ) = > x . get ( index as usize ) . cloned ( ) . map ( TableElement ::FuncRef ) ,
TableElements ::ExternRefs ( x ) = > {
x . get ( index as usize ) . cloned ( ) . map ( TableElement ::ExternRef )
}
}
}
/// Set reference to the specified element.
///
/// # Panics
/// # Error s
///
/// Panics if `index` is out of bounds.
pub fn set ( & self , index : u32 , func : VMCallerCheckedAnyfunc ) -> Result < ( ) , ( ) > {
match self . vec . borrow_mut ( ) . get_mut ( index as usize ) {
Some ( slot ) = > {
* slot = func ;
Ok ( ( ) )
/// Returns an error if `index` is out of bounds or if this table type does
/// not match the element type.
pub fn set ( & self , index : u32 , elem : TableElement ) -> Result < ( ) , ( ) > {
let mut elems = self . elements . borrow_mut ( ) ;
match & mut * elems {
TableElements ::FuncRefs ( x ) = > {
let slot = x . get_mut ( index as usize ) . ok_or ( ( ) ) ? ;
* slot = elem . try_into ( ) . or ( Err ( ( ) ) ) ? ;
}
TableElements ::ExternRefs ( x ) = > {
let slot = x . get_mut ( index as usize ) . ok_or ( ( ) ) ? ;
* slot = elem . try_into ( ) . or ( Err ( ( ) ) ) ? ;
}
None = > Err ( ( ) ) ,
}
Ok ( ( ) )
}
/// Copy `len` elements from `src_table[src_index..]` into `dst_table[dst_index..]`.
@ -137,10 +173,37 @@ impl Table {
/// 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 ( ) ,
match & * self . elements . borrow ( ) {
TableElements ::FuncRefs ( x ) = > VMTableDefinition {
base : x . as_ptr ( ) as * const u8 as * mut u8 ,
current_elements : x . len ( ) . try_into ( ) . unwrap ( ) ,
} ,
TableElements ::ExternRefs ( x ) = > VMTableDefinition {
base : x . as_ptr ( ) as * const u8 as * mut u8 ,
current_elements : x . len ( ) . try_into ( ) . unwrap ( ) ,
} ,
}
}
}
impl TryFrom < TableElement > for VMCallerCheckedAnyfunc {
type Error = TableElement ;
fn try_from ( e : TableElement ) -> Result < Self , Self ::Error > {
match e {
TableElement ::FuncRef ( f ) = > Ok ( f ) ,
_ = > Err ( e ) ,
}
}
}
impl TryFrom < TableElement > for Option < VMExternRef > {
type Error = TableElement ;
fn try_from ( e : TableElement ) -> Result < Self , Self ::Error > {
match e {
TableElement ::ExternRef ( x ) = > Ok ( x ) ,
_ = > Err ( e ) ,
}
}
}