wasmtime: Add support for func.ref and table.grow with funcrefs
`funcref`s are implemented as `NonNull<VMCallerCheckedAnyfunc>`. This should be more efficient than using a `VMExternRef` that points at a `VMCallerCheckedAnyfunc` because it gets rid of an indirection, dynamic allocation, and some reference counting. Note that the null function reference is *NOT* a null pointer; it is a `VMCallerCheckedAnyfunc` that has a null `func_ptr` member. Part of #929
This commit is contained in:
@@ -6,6 +6,7 @@ use crate::vmcontext::{VMCallerCheckedAnyfunc, VMTableDefinition};
|
||||
use crate::{Trap, VMExternRef};
|
||||
use std::cell::RefCell;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::ptr;
|
||||
use wasmtime_environ::wasm::TableElementType;
|
||||
use wasmtime_environ::{ir, TablePlan, TableStyle};
|
||||
|
||||
@@ -20,35 +21,28 @@ pub struct Table {
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum TableElement {
|
||||
/// A `funcref`.
|
||||
FuncRef(VMCallerCheckedAnyfunc),
|
||||
FuncRef(*mut VMCallerCheckedAnyfunc),
|
||||
/// An `exrernref`.
|
||||
ExternRef(Option<VMExternRef>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum TableElements {
|
||||
FuncRefs(Vec<VMCallerCheckedAnyfunc>),
|
||||
FuncRefs(Vec<*mut 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 {
|
||||
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),
|
||||
});
|
||||
let min = usize::try_from(plan.table.minimum).unwrap();
|
||||
let elements = RefCell::new(match plan.table.ty {
|
||||
TableElementType::Func => TableElements::FuncRefs(vec![ptr::null_mut(); min]),
|
||||
TableElementType::Val(ty) => {
|
||||
debug_assert_eq!(ty, crate::ref_type());
|
||||
TableElements::ExternRefs(vec![None; min])
|
||||
}
|
||||
});
|
||||
match plan.style {
|
||||
TableStyle::CallerChecksSignature => Self {
|
||||
elements,
|
||||
@@ -57,6 +51,14 @@ impl Table {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the type of the elements in this table.
|
||||
pub fn element_type(&self) -> TableElementType {
|
||||
match &*self.elements.borrow() {
|
||||
TableElements::FuncRefs(_) => TableElementType::Func,
|
||||
TableElements::ExternRefs(_) => TableElementType::Val(crate::ref_type()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of allocated elements.
|
||||
pub fn size(&self) -> u32 {
|
||||
match &*self.elements.borrow() {
|
||||
@@ -199,7 +201,7 @@ impl Table {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<TableElement> for VMCallerCheckedAnyfunc {
|
||||
impl TryFrom<TableElement> for *mut VMCallerCheckedAnyfunc {
|
||||
type Error = TableElement;
|
||||
|
||||
fn try_from(e: TableElement) -> Result<Self, Self::Error> {
|
||||
@@ -221,8 +223,8 @@ impl TryFrom<TableElement> for Option<VMExternRef> {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<VMCallerCheckedAnyfunc> for TableElement {
|
||||
fn from(f: VMCallerCheckedAnyfunc) -> TableElement {
|
||||
impl From<*mut VMCallerCheckedAnyfunc> for TableElement {
|
||||
fn from(f: *mut VMCallerCheckedAnyfunc) -> TableElement {
|
||||
TableElement::FuncRef(f)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user