Table operation; refactor Callable

This commit is contained in:
Yury Delendik
2019-08-27 11:44:02 -05:00
committed by Dan Gohman
parent e60bf7f7e8
commit de1c0f63eb
17 changed files with 641 additions and 114 deletions

View File

@@ -1,44 +1,61 @@
use crate::runtime::Store;
use crate::trap::Trap;
use crate::types::FuncType;
use crate::values::Val;
use core::any::Any;
use std::cell::RefCell;
use std::rc::Rc;
use crate::trampoline::generate_func_export;
use cranelift_codegen::ir;
use wasmtime_runtime::{VMContext, VMFunctionBody};
use wasmtime_jit::InstanceHandle;
use wasmtime_runtime::Export;
pub trait Callable: Any {
pub trait Callable {
fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Rc<RefCell<Trap>>>;
}
pub(crate) trait WrappedCallable {
fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Rc<RefCell<Trap>>>;
fn signature(&self) -> &ir::Signature {
match self.wasmtime_export() {
Export::Function { signature, .. } => signature,
_ => panic!("unexpected export type in Callable"),
}
}
fn wasmtime_handle(&self) -> &InstanceHandle;
fn wasmtime_export(&self) -> &Export;
}
pub(crate) struct WasmtimeFn {
store: Rc<RefCell<Store>>,
signature: ir::Signature,
body: *const VMFunctionBody,
vmctx: *mut VMContext,
instance: InstanceHandle,
export: Export,
}
impl WasmtimeFn {
pub fn new(
store: Rc<RefCell<Store>>,
signature: ir::Signature,
body: *const VMFunctionBody,
vmctx: *mut VMContext,
) -> WasmtimeFn {
pub fn new(store: Rc<RefCell<Store>>, instance: InstanceHandle, export: Export) -> WasmtimeFn {
WasmtimeFn {
store,
signature,
body,
vmctx,
instance,
export,
}
}
}
impl Callable for WasmtimeFn {
impl WrappedCallable for WasmtimeFn {
fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Rc<RefCell<Trap>>> {
use core::cmp::max;
use core::{mem, ptr};
let (vmctx, body, signature) = match self.wasmtime_export() {
Export::Function {
vmctx,
address,
signature,
} => (*vmctx, *address, signature.clone()),
_ => panic!("unexpected export type in Callable"),
};
let mut store = self.store.borrow_mut();
let context = store.context();
@@ -63,13 +80,13 @@ impl Callable for WasmtimeFn {
// Get the trampoline to call for this function.
let exec_code_buf = context
.compiler()
.get_published_trampoline(self.body, &self.signature, value_size)
.get_published_trampoline(body, &signature, value_size)
.map_err(|_| Rc::new(RefCell::new(Trap::fake())))?; //was ActionError::Setup)?;
// Call the trampoline.
if let Err(message) = unsafe {
wasmtime_runtime::wasmtime_call_trampoline(
self.vmctx,
vmctx,
exec_code_buf,
values_vec.as_mut_ptr() as *mut u8,
)
@@ -78,7 +95,7 @@ impl Callable for WasmtimeFn {
}
// Load the return values out of `values_vec`.
for (index, abi_param) in self.signature.returns.iter().enumerate() {
for (index, abi_param) in signature.returns.iter().enumerate() {
unsafe {
let ptr = values_vec.as_ptr().add(index);
@@ -94,4 +111,44 @@ impl Callable for WasmtimeFn {
Ok(())
}
fn wasmtime_handle(&self) -> &InstanceHandle {
&self.instance
}
fn wasmtime_export(&self) -> &Export {
&self.export
}
}
pub struct NativeCallable {
callable: Rc<dyn Callable + 'static>,
instance: InstanceHandle,
export: Export,
}
impl NativeCallable {
pub(crate) fn new(
callable: Rc<dyn Callable + 'static>,
ft: &FuncType,
store: &Rc<RefCell<Store>>,
) -> Self {
let (instance, export) =
generate_func_export(ft, &callable, store).expect("generated func");
NativeCallable {
callable,
instance,
export,
}
}
}
impl WrappedCallable for NativeCallable {
fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Rc<RefCell<Trap>>> {
self.callable.call(params, results)
}
fn wasmtime_handle(&self) -> &InstanceHandle {
&self.instance
}
fn wasmtime_export(&self) -> &Export {
&self.export
}
}

View File

@@ -1,14 +1,15 @@
use crate::callable::{Callable, WasmtimeFn};
use crate::callable::{Callable, NativeCallable, WasmtimeFn, WrappedCallable};
use crate::runtime::Store;
use crate::table_utils;
use crate::trampoline::{generate_global_export, generate_memory_export, generate_table_export};
use crate::trap::Trap;
use crate::types::{ExternType, FuncType, GlobalType, MemoryType, TableType, ValType};
use crate::values::Val;
use std::cell::RefCell;
use std::rc::Rc;
use std::result::Result;
use crate::trampoline::{generate_func_export, generate_global_export, generate_memory_export};
use wasmtime_runtime::InstanceHandle;
// Externals
pub enum Extern {
@@ -55,15 +56,10 @@ impl Extern {
pub(crate) fn get_wasmtime_export(&mut self) -> wasmtime_runtime::Export {
match self {
Extern::Func(f) => {
if f.borrow().anchor.is_none() {
generate_func_export(&f).expect("generate_func_export");
}
f.borrow().anchor.as_ref().unwrap().1.clone()
}
Extern::Func(f) => f.borrow().wasmtime_export().clone(),
Extern::Global(g) => g.borrow().wasmtime_export().clone(),
Extern::Memory(m) => m.borrow().wasmtime_export().clone(),
_ => unimplemented!("get_wasmtime_export"),
Extern::Table(t) => t.borrow().wasmtime_export().clone(),
}
}
@@ -73,53 +69,47 @@ impl Extern {
export: wasmtime_runtime::Export,
) -> Extern {
match export {
wasmtime_runtime::Export::Function {
address,
vmctx,
ref signature,
} => {
let ty = FuncType::from_cranelift_signature(signature.clone());
let callable = WasmtimeFn::new(store.clone(), signature.clone(), address, vmctx);
let mut f = Func::new(store, ty, Rc::new(callable));
f.anchor = Some((instance_handle, export.clone()));
Extern::Func(Rc::new(RefCell::new(f)))
}
wasmtime_runtime::Export::Function { .. } => Extern::Func(Rc::new(RefCell::new(
Func::from_wasmtime_function(export, store, instance_handle),
))),
wasmtime_runtime::Export::Memory { .. } => Extern::Memory(Rc::new(RefCell::new(
Memory::from_wasmtime_memory(export, store, instance_handle),
))),
wasmtime_runtime::Export::Global { .. } => Extern::Global(Rc::new(RefCell::new(
Global::from_wasmtime_global(export, store),
))),
wasmtime_runtime::Export::Table {
definition: _,
vmctx: _,
table,
} => {
let ty = TableType::from_cranelift_table(table.table.clone());
Extern::Table(Rc::new(RefCell::new(Table::new(store, ty))))
}
wasmtime_runtime::Export::Table { .. } => Extern::Table(Rc::new(RefCell::new(
Table::from_wasmtime_table(export, store, instance_handle),
))),
}
}
}
pub struct Func {
_store: Rc<RefCell<Store>>,
callable: Rc<dyn Callable + 'static>,
callable: Rc<dyn WrappedCallable + 'static>,
r#type: FuncType,
pub(crate) anchor: Option<(InstanceHandle, wasmtime_runtime::Export)>,
}
impl Func {
pub fn new(
store: Rc<RefCell<Store>>,
r#type: FuncType,
ty: FuncType,
callable: Rc<dyn Callable + 'static>,
) -> Self {
let callable = Rc::new(NativeCallable::new(callable, &ty, &store));
Func::from_wrapped(store, ty, callable)
}
fn from_wrapped(
store: Rc<RefCell<Store>>,
r#type: FuncType,
callable: Rc<dyn WrappedCallable + 'static>,
) -> Func {
Func {
_store: store,
callable,
r#type,
anchor: None,
}
}
@@ -127,6 +117,10 @@ impl Func {
&self.r#type
}
pub(crate) fn callable(&self) -> &Rc<dyn WrappedCallable + 'static> {
&self.callable
}
pub fn param_arity(&self) -> usize {
self.r#type.params().len()
}
@@ -135,15 +129,29 @@ impl Func {
self.r#type.results().len()
}
pub fn callable(&self) -> &(dyn Callable + 'static) {
self.callable.as_ref()
}
pub fn call(&self, params: &[Val]) -> Result<Box<[Val]>, Rc<RefCell<Trap>>> {
let mut results = vec![Val::default(); self.result_arity()];
self.callable.call(params, &mut results)?;
Ok(results.into_boxed_slice())
}
fn wasmtime_export(&self) -> &wasmtime_runtime::Export {
self.callable.wasmtime_export()
}
fn from_wasmtime_function(
export: wasmtime_runtime::Export,
store: Rc<RefCell<Store>>,
instance_handle: InstanceHandle,
) -> Self {
let ty = if let wasmtime_runtime::Export::Function { signature, .. } = &export {
FuncType::from_cranelift_signature(signature.clone())
} else {
panic!("expected function export")
};
let callable = WasmtimeFn::new(store.clone(), instance_handle, export.clone());
Func::from_wrapped(store, ty, Rc::new(callable))
}
}
pub struct Global {
@@ -234,15 +242,27 @@ impl Global {
}
pub struct Table {
_store: Rc<RefCell<Store>>,
store: Rc<RefCell<Store>>,
r#type: TableType,
#[allow(dead_code)]
wasmtime_handle: InstanceHandle,
wasmtime_export: wasmtime_runtime::Export,
}
impl Table {
pub fn new(store: Rc<RefCell<Store>>, r#type: TableType) -> Table {
pub fn new(store: Rc<RefCell<Store>>, r#type: TableType, _init: Val) -> Table {
match r#type.element() {
ValType::FuncRef => (),
_ => panic!("table is not for funcref"),
}
// TODO implement _init initialization
let (wasmtime_handle, wasmtime_export) =
generate_table_export(&r#type).expect("generated table");
Table {
_store: store,
store,
r#type,
wasmtime_handle,
wasmtime_export,
}
}
@@ -250,20 +270,54 @@ impl Table {
&self.r#type
}
pub fn get(&self, _index: u32) -> Val {
unimplemented!("Table::get")
fn wasmtime_table_definition(&self) -> *mut wasmtime_runtime::VMTableDefinition {
match self.wasmtime_export {
wasmtime_runtime::Export::Table { definition, .. } => definition,
_ => panic!("global definition not found"),
}
}
pub fn set(&self, _index: u32, _val: &Val) -> usize {
unimplemented!("Table::set")
pub fn get(&self, index: u32) -> Val {
let definition = self.wasmtime_table_definition();
unsafe { table_utils::get_item(definition, &self.store, index) }
}
pub fn set(&self, index: u32, val: Val) -> bool {
let definition = self.wasmtime_table_definition();
unsafe { table_utils::set_item(definition, &self.store, index, val) }
}
pub fn size(&self) -> u32 {
unimplemented!("Table::size")
let definition = self.wasmtime_table_definition();
unsafe { table_utils::get_size(definition) }
}
pub fn grow(&mut self, _delta: u32) -> bool {
unimplemented!("Table::grow")
pub fn grow(&mut self, delta: u32, init: Val) -> bool {
let definition = self.wasmtime_table_definition();
unsafe { table_utils::grow_table(definition, &self.r#type, &self.store, delta, init) }
}
pub(crate) fn wasmtime_export(&self) -> &wasmtime_runtime::Export {
&self.wasmtime_export
}
pub(crate) fn from_wasmtime_table(
export: wasmtime_runtime::Export,
store: Rc<RefCell<Store>>,
instance_handle: wasmtime_runtime::InstanceHandle,
) -> Table {
let table = if let wasmtime_runtime::Export::Table { ref table, .. } = export {
table
} else {
panic!("wasmtime export is not table")
};
let ty = TableType::from_cranelift_table(table.table.clone());
Table {
store,
r#type: ty,
wasmtime_handle: instance_handle,
wasmtime_export: export,
}
}
}

View File

@@ -108,6 +108,12 @@ impl Instance {
let mut mutable = instance_handle.clone();
for (name, _) in instance_handle.clone().exports() {
let export = mutable.lookup(name).expect("export");
if let wasmtime_runtime::Export::Function { signature, .. } = &export {
// HACK ensure all handles, instantiated outside Store, present in
// the store's SignatureRegistry.
use crate::runtime::SignatureRegistry;
let _ = store.borrow_mut().register_cranelift_signature(signature);
}
export_names_map.insert(name.to_owned(), exports.len());
exports.push(Rc::new(RefCell::new(Extern::from_wasmtime_export(
store.clone(),

View File

@@ -6,6 +6,7 @@ mod externals;
mod instance;
mod module;
mod runtime;
mod table_utils;
mod trampoline;
mod trap;
mod types;

View File

@@ -4,7 +4,7 @@ use std::rc::Rc;
use crate::context::{create_compiler, Context};
use cranelift_codegen::settings;
use cranelift_codegen::{ir, settings};
use wasmtime_jit::Features;
// Runtime Environment
@@ -79,10 +79,22 @@ impl Engine {
// Store
pub(crate) trait SignatureRegistry {
fn register_cranelift_signature(
&mut self,
signature: &ir::Signature,
) -> wasmtime_runtime::VMSharedSignatureIndex;
fn lookup_cranelift_signature(
&self,
type_index: wasmtime_runtime::VMSharedSignatureIndex,
) -> Option<&ir::Signature>;
}
pub struct Store {
engine: Rc<RefCell<Engine>>,
context: Context,
global_exports: Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>>,
signature_cache: HashMap<wasmtime_runtime::VMSharedSignatureIndex, ir::Signature>,
}
impl Store {
@@ -94,6 +106,7 @@ impl Store {
engine,
context: Context::create(flags, features, debug_info),
global_exports: Rc::new(RefCell::new(HashMap::new())),
signature_cache: HashMap::new(),
}
}
@@ -112,3 +125,26 @@ impl Store {
&self.global_exports
}
}
impl SignatureRegistry for Store {
fn register_cranelift_signature(
&mut self,
signature: &ir::Signature,
) -> wasmtime_runtime::VMSharedSignatureIndex {
use std::collections::hash_map::Entry;
let index = self.context().compiler().signatures().register(signature);
match self.signature_cache.entry(index) {
Entry::Vacant(v) => {
v.insert(signature.clone());
}
Entry::Occupied(_) => (),
}
index
}
fn lookup_cranelift_signature(
&self,
type_index: wasmtime_runtime::VMSharedSignatureIndex,
) -> Option<&ir::Signature> {
self.signature_cache.get(&type_index)
}
}

View File

@@ -0,0 +1,123 @@
use std::cell::RefCell;
use std::mem;
use std::ptr;
use std::rc::Rc;
use std::slice;
use wasmtime_runtime::{
InstanceHandle, VMCallerCheckedAnyfunc, VMSharedSignatureIndex, VMTableDefinition,
};
use crate::callable::WasmtimeFn;
use crate::runtime::SignatureRegistry;
use crate::runtime::Store;
use crate::types::TableType;
use crate::values::{AnyRef, FuncRef, Val};
fn into_checked_anyfunc(val: Val, store: &Rc<RefCell<Store>>) -> VMCallerCheckedAnyfunc {
match val {
Val::AnyRef(AnyRef::Null) => VMCallerCheckedAnyfunc {
func_ptr: ptr::null(),
type_index: VMSharedSignatureIndex::default(),
vmctx: ptr::null_mut(),
},
Val::AnyRef(AnyRef::Func(f)) | Val::FuncRef(f) => {
let (vmctx, func_ptr, signature) = match f.0.wasmtime_export() {
wasmtime_runtime::Export::Function {
vmctx,
address,
signature,
} => (*vmctx, *address, signature),
_ => panic!("expected function export"),
};
let type_index = store.borrow_mut().register_cranelift_signature(signature);
VMCallerCheckedAnyfunc {
func_ptr,
type_index,
vmctx,
}
}
_ => panic!("val is not funcref"),
}
}
unsafe fn from_checked_anyfunc(item: &VMCallerCheckedAnyfunc, store: &Rc<RefCell<Store>>) -> Val {
if item.type_index == VMSharedSignatureIndex::default() {
return Val::AnyRef(AnyRef::Null);
}
let signature = store
.borrow()
.lookup_cranelift_signature(item.type_index)
.expect("signature")
.clone();
let instance_handle = InstanceHandle::from_vmctx(item.vmctx);
let export = wasmtime_runtime::Export::Function {
address: item.func_ptr,
signature,
vmctx: item.vmctx,
};
let f = WasmtimeFn::new(store.clone(), instance_handle, export);
Val::FuncRef(FuncRef(Rc::new(f)))
}
pub unsafe fn get_item(
table: *mut VMTableDefinition,
store: &Rc<RefCell<Store>>,
index: u32,
) -> Val {
let base = slice::from_raw_parts(
(*table).base as *const VMCallerCheckedAnyfunc,
(*table).current_elements,
);
from_checked_anyfunc(&base[index as usize], store)
}
pub unsafe fn set_item(
table: *mut VMTableDefinition,
store: &Rc<RefCell<Store>>,
index: u32,
val: Val,
) -> bool {
let base = slice::from_raw_parts_mut(
(*table).base as *mut VMCallerCheckedAnyfunc,
(*table).current_elements,
);
if index as usize >= base.len() {
return false;
}
base[index as usize] = into_checked_anyfunc(val, store);
true
}
pub unsafe fn get_size(table: *mut VMTableDefinition) -> u32 {
(*table).current_elements as u32
}
pub unsafe fn grow_table(
table: *mut VMTableDefinition,
table_type: &TableType,
store: &Rc<RefCell<Store>>,
delta: u32,
init: Val,
) -> bool {
let new_len = (*table).current_elements + delta as usize;
if (table_type.limits().max() as usize) < new_len {
return false;
}
let mut buffer = Vec::from_raw_parts(
(*table).base as *mut VMCallerCheckedAnyfunc,
(*table).current_elements,
(*table).current_elements,
);
buffer.resize(new_len, into_checked_anyfunc(init, store));
buffer.shrink_to_fit();
assert!(buffer.capacity() == new_len);
(*table).base = buffer.as_mut_ptr() as *mut u8;
(*table).current_elements = new_len;
mem::forget(buffer);
true
}

View File

@@ -8,12 +8,15 @@ use wasmtime_environ::Module;
use wasmtime_runtime::{Imports, InstanceHandle, VMFunctionBody};
use std::any::Any;
use std::cell::RefCell;
use std::cell::{RefCell, RefMut};
use std::collections::{HashMap, HashSet};
use std::rc::Rc;
pub fn create_handle(
use crate::runtime::SignatureRegistry;
pub(crate) fn create_handle(
module: Module,
signature_registry: Option<RefMut<dyn SignatureRegistry>>,
finished_functions: PrimaryMap<DefinedFuncIndex, *const VMFunctionBody>,
state: Box<dyn Any>,
) -> Result<InstanceHandle, Error> {
@@ -28,7 +31,19 @@ pub fn create_handle(
PrimaryMap::new(),
);
let data_initializers = Vec::new();
let signatures = PrimaryMap::new();
// Compute indices into the shared signature table.
let signatures = signature_registry
.and_then(|mut signature_registry| {
Some(
module
.signatures
.values()
.map(|sig| signature_registry.register_cranelift_signature(sig))
.collect::<PrimaryMap<_, _>>(),
)
})
.unwrap_or_else(|| PrimaryMap::new());
Ok(InstanceHandle::new(
Rc::new(module),

View File

@@ -17,12 +17,12 @@ use core::cmp;
use std::cell::RefCell;
use std::rc::Rc;
use crate::{Func, Trap, Val};
use crate::{Callable, FuncType, Store, Trap, Val};
use super::create_handle::create_handle;
struct TrampolineState {
func: Rc<RefCell<Func>>,
func: Rc<dyn Callable + 'static>,
trap: Option<Rc<RefCell<Trap>>>,
#[allow(dead_code)]
code_memory: CodeMemory,
@@ -45,15 +45,15 @@ unsafe extern "C" fn stub_fn(vmctx: *mut VMContext, call_id: u32, values_vec: *m
(args, signature.returns.len())
};
let func = instance
let mut returns = vec![Val::default(); returns_len];
let func = &instance
.host_state()
.downcast_mut::<TrampolineState>()
.expect("state")
.func
.borrow();
.func;
match func.call(&args) {
Ok(returns) => {
match func.call(&args, &mut returns) {
Ok(()) => {
for i in 0..returns_len {
// TODO check signature.returns[i].value_type ?
returns[i].write_value_to(values_vec.offset(i as isize));
@@ -188,8 +188,12 @@ fn make_trampoline(
.as_ptr()
}
pub fn create_handle_with_function(func: &Rc<RefCell<Func>>) -> Result<InstanceHandle, Error> {
let sig = func.borrow().r#type().get_cranelift_signature().clone();
pub fn create_handle_with_function(
ft: &FuncType,
func: &Rc<dyn Callable + 'static>,
store: &Rc<RefCell<Store>>,
) -> Result<InstanceHandle, Error> {
let sig = ft.get_cranelift_signature().clone();
let isa = {
let isa_builder =
@@ -229,7 +233,12 @@ pub fn create_handle_with_function(func: &Rc<RefCell<Func>>) -> Result<InstanceH
code_memory,
};
create_handle(module, finished_functions, Box::new(trampoline_state))
create_handle(
module,
Some(store.borrow_mut()),
finished_functions,
Box::new(trampoline_state),
)
}
/// We don't expect trampoline compilation to produce any relocations, so

View File

@@ -35,7 +35,8 @@ pub fn create_global(
},
initializer: cranelift_wasm::GlobalInit::Import, // TODO is it right?
};
let mut handle = create_handle(Module::new(), PrimaryMap::new(), Box::new(())).expect("handle");
let mut handle =
create_handle(Module::new(), None, PrimaryMap::new(), Box::new(())).expect("handle");
Ok((
wasmtime_runtime::Export::Global {
definition: definition.as_mut(),

View File

@@ -29,5 +29,5 @@ pub fn create_handle_with_memory(memory: &MemoryType) -> Result<InstanceHandle,
wasmtime_environ::Export::Memory(memory_id),
);
create_handle(module, PrimaryMap::new(), Box::new(()))
create_handle(module, None, PrimaryMap::new(), Box::new(()))
}

View File

@@ -5,6 +5,7 @@ mod create_handle;
mod func;
mod global;
mod memory;
mod table;
use failure::Error;
use std::cell::RefCell;
@@ -13,16 +14,19 @@ use std::rc::Rc;
use self::func::create_handle_with_function;
use self::global::create_global;
use self::memory::create_handle_with_memory;
use super::{Func, GlobalType, MemoryType, Val};
use self::table::create_handle_with_table;
use super::{Callable, FuncType, GlobalType, MemoryType, Store, TableType, Val};
pub use self::global::GlobalState;
pub fn generate_func_export(f: &Rc<RefCell<Func>>) -> Result<(), Error> {
let mut instance = create_handle_with_function(f)?;
pub fn generate_func_export(
ft: &FuncType,
func: &Rc<dyn Callable + 'static>,
store: &Rc<RefCell<Store>>,
) -> Result<(wasmtime_runtime::InstanceHandle, wasmtime_runtime::Export), Error> {
let mut instance = create_handle_with_function(ft, func, store)?;
let export = instance.lookup("trampoline").expect("trampoline export");
f.borrow_mut().anchor = Some((instance, export));
Ok(())
Ok((instance, export))
}
pub fn generate_global_export(
@@ -39,3 +43,11 @@ pub fn generate_memory_export(
let export = instance.lookup("memory").expect("memory export");
Ok((instance, export))
}
pub fn generate_table_export(
t: &TableType,
) -> Result<(wasmtime_runtime::InstanceHandle, wasmtime_runtime::Export), Error> {
let mut instance = create_handle_with_table(t)?;
let export = instance.lookup("table").expect("table export");
Ok((instance, export))
}

View File

@@ -0,0 +1,35 @@
use cranelift_entity::PrimaryMap;
use cranelift_wasm::TableElementType;
use failure::Error;
use wasmtime_environ::Module;
use wasmtime_runtime::InstanceHandle;
use super::create_handle::create_handle;
use crate::{TableType, ValType};
pub fn create_handle_with_table(table: &TableType) -> Result<InstanceHandle, Error> {
let mut module = Module::new();
let table = cranelift_wasm::Table {
minimum: table.limits().min(),
maximum: if table.limits().max() == std::u32::MAX {
None
} else {
Some(table.limits().max())
},
ty: match table.element() {
ValType::FuncRef => TableElementType::Func,
_ => TableElementType::Val(table.element().get_cranelift_type()),
},
};
let tunable = Default::default();
let table_plan = wasmtime_environ::TablePlan::for_table(table, &tunable);
let table_id = module.table_plans.push(table_plan);
module.exports.insert(
"table".to_string(),
wasmtime_environ::Export::Table(table_id),
);
create_handle(module, None, PrimaryMap::new(), Box::new(()))
}

View File

@@ -1,6 +1,6 @@
use crate::callable::Callable;
use crate::callable::WrappedCallable;
use crate::types::ValType;
use std::cell::RefCell;
use std::any::Any;
use std::fmt;
use std::ptr;
use std::rc::Rc;
@@ -9,22 +9,30 @@ use cranelift_codegen::ir;
use wasmtime_jit::RuntimeValue;
#[derive(Clone)]
pub struct AnyRef;
pub enum AnyRef {
Null,
Rc(Rc<dyn Any>),
Func(FuncRef),
}
impl AnyRef {
pub fn null() -> AnyRef {
AnyRef
AnyRef::Null
}
}
impl fmt::Debug for AnyRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "anyref")
match self {
AnyRef::Null => write!(f, "null"),
AnyRef::Rc(_) => write!(f, "anyref"),
AnyRef::Func(func) => func.fmt(f),
}
}
}
pub struct FuncRef {
pub callable: Box<dyn Callable + 'static>,
}
#[derive(Clone)]
pub struct FuncRef(pub(crate) Rc<dyn WrappedCallable + 'static>);
impl fmt::Debug for FuncRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -32,19 +40,35 @@ impl fmt::Debug for FuncRef {
}
}
impl From<AnyRef> for FuncRef {
fn from(anyref: AnyRef) -> FuncRef {
match anyref {
AnyRef::Func(f) => f,
AnyRef::Rc(_) => unimplemented!("try to unwrap?"),
AnyRef::Null => panic!("null anyref"),
}
}
}
impl Into<AnyRef> for FuncRef {
fn into(self) -> AnyRef {
AnyRef::Func(self)
}
}
#[derive(Debug, Clone)]
pub enum Val {
I32(i32),
I64(i64),
F32(u32),
F64(u64),
AnyRef(Rc<RefCell<AnyRef>>),
FuncRef(Rc<RefCell<FuncRef>>),
AnyRef(AnyRef),
FuncRef(FuncRef),
}
impl Val {
pub fn default() -> Val {
Val::AnyRef(Rc::new(RefCell::new(AnyRef::null())))
Val::AnyRef(AnyRef::null())
}
pub fn r#type(&self) -> ValType {
@@ -151,14 +175,27 @@ impl Into<f64> for Val {
}
}
impl From<Rc<RefCell<AnyRef>>> for Val {
fn from(val: Rc<RefCell<AnyRef>>) -> Val {
Val::AnyRef(val)
impl From<AnyRef> for Val {
fn from(val: AnyRef) -> Val {
match val {
AnyRef::Func(f) => Val::FuncRef(f),
_ => Val::AnyRef(val),
}
}
}
impl From<Rc<RefCell<FuncRef>>> for Val {
fn from(val: Rc<RefCell<FuncRef>>) -> Val {
impl From<FuncRef> for Val {
fn from(val: FuncRef) -> Val {
Val::FuncRef(val)
}
}
impl Into<AnyRef> for Val {
fn into(self) -> AnyRef {
match self {
Val::AnyRef(r) => r,
Val::FuncRef(f) => AnyRef::Func(f),
_ => panic!("Invalid conversion of {:?} to anyref.", self),
}
}
}

View File

@@ -6,9 +6,9 @@
// TODO complete the C API
use super::{
Callable, Engine, ExportType, Extern, ExternType, Func, FuncType, Global, GlobalType,
ImportType, Instance, Limits, Memory, MemoryType, Module, Name, Store, TableType, Trap, Val,
ValType,
AnyRef, Callable, Engine, ExportType, Extern, ExternType, Func, FuncRef, FuncType, Global,
GlobalType, ImportType, Instance, Limits, Memory, MemoryType, Module, Name, Store, Table,
TableType, Trap, Val, ValType,
};
use std::boxed::Box;
use std::cell::RefCell;
@@ -268,7 +268,7 @@ declare_vec!(wasm_exporttype_vec_t, *mut wasm_exporttype_t);
#[repr(C)]
#[derive(Clone)]
pub struct wasm_ref_t {
_unused: [u8; 0],
r: AnyRef,
}
#[repr(C)]
#[derive(Copy, Clone)]
@@ -360,7 +360,7 @@ pub struct wasm_global_t {
#[repr(C)]
#[derive(Clone)]
pub struct wasm_table_t {
_unused: [u8; 0],
table: Rc<RefCell<Table>>,
}
pub type wasm_table_size_t = u32;
#[repr(C)]
@@ -1334,3 +1334,133 @@ pub unsafe extern "C" fn wasm_memorytype_new(
});
Box::into_raw(mt)
}
#[no_mangle]
pub unsafe extern "C" fn wasm_extern_as_table(e: *mut wasm_extern_t) -> *mut wasm_table_t {
let t = Box::new(wasm_table_t {
table: (*e).ext.borrow().table().clone(),
});
Box::into_raw(t)
}
#[no_mangle]
pub unsafe extern "C" fn wasm_func_as_ref(f: *mut wasm_func_t) -> *mut wasm_ref_t {
let callable = (*f).func.borrow().callable().clone();
let f = Box::new(wasm_ref_t {
r: AnyRef::Func(FuncRef(callable)),
});
Box::into_raw(f)
}
#[no_mangle]
pub unsafe extern "C" fn wasm_ref_delete(r: *mut wasm_ref_t) {
if !r.is_null() {
let _ = Box::from_raw(r);
}
}
#[no_mangle]
pub unsafe extern "C" fn wasm_table_delete(t: *mut wasm_table_t) {
let _ = Box::from_raw(t);
}
#[no_mangle]
pub unsafe extern "C" fn wasm_table_copy(t: *const wasm_table_t) -> *mut wasm_table_t {
Box::into_raw(Box::new((*t).clone()))
}
#[no_mangle]
pub unsafe extern "C" fn wasm_table_new(
store: *mut wasm_store_t,
tt: *const wasm_tabletype_t,
init: *mut wasm_ref_t,
) -> *mut wasm_table_t {
let init: Val = if !init.is_null() {
Box::from_raw(init).r.into()
} else {
Val::AnyRef(AnyRef::Null)
};
let t = Box::new(wasm_table_t {
table: Rc::new(RefCell::new(Table::new(
(*store).store.clone(),
(*tt).tabletype.clone(),
init,
))),
});
Box::into_raw(t)
}
unsafe fn into_funcref(val: Val) -> *mut wasm_ref_t {
if let Val::AnyRef(AnyRef::Null) = val {
return ptr::null_mut();
}
let r = Box::new(wasm_ref_t { r: val.into() });
Box::into_raw(r)
}
unsafe fn from_funcref(r: *mut wasm_ref_t) -> Val {
if !r.is_null() {
Box::from_raw(r).r.into()
} else {
Val::AnyRef(AnyRef::Null)
}
}
#[no_mangle]
pub unsafe extern "C" fn wasm_table_get(
t: *const wasm_table_t,
index: wasm_table_size_t,
) -> *mut wasm_ref_t {
let val = (*t).table.borrow().get(index);
into_funcref(val)
}
#[no_mangle]
pub unsafe extern "C" fn wasm_table_set(
t: *mut wasm_table_t,
index: wasm_table_size_t,
r: *mut wasm_ref_t,
) -> bool {
let val = from_funcref(r);
(*t).table.borrow().set(index, val)
}
#[no_mangle]
pub unsafe extern "C" fn wasm_table_size(t: *const wasm_table_t) -> wasm_table_size_t {
(*t).table.borrow().size()
}
#[no_mangle]
pub unsafe extern "C" fn wasm_table_grow(
t: *mut wasm_table_t,
delta: wasm_table_size_t,
init: *mut wasm_ref_t,
) -> bool {
let init = from_funcref(init);
(*t).table.borrow_mut().grow(delta, init)
}
#[no_mangle]
pub unsafe extern "C" fn wasm_table_same(t1: *const wasm_table_t, t2: *const wasm_table_t) -> bool {
(*t1).table.as_ptr() == (*t2).table.as_ptr()
}
#[no_mangle]
pub unsafe extern "C" fn wasm_tabletype_delete(tt: *mut wasm_tabletype_t) {
let _ = Box::from_raw(tt);
}
#[no_mangle]
pub unsafe extern "C" fn wasm_tabletype_new(
ty: *mut wasm_valtype_t,
limits: *const wasm_limits_t,
) -> *mut wasm_tabletype_t {
let ty = Box::from_raw(ty).ty;
let limits = Limits::new((*limits).min, (*limits).max);
let tt = Box::new(wasm_tabletype_t {
tabletype: TableType::new(ty, limits),
element_cache: None,
limits_cache: None,
});
Box::into_raw(tt)
}

View File

@@ -181,7 +181,8 @@ impl Compiler {
self.code_memory.publish();
}
pub(crate) fn signatures(&mut self) -> &mut SignatureRegistry {
/// Shared signature registry.
pub fn signatures(&mut self) -> &mut SignatureRegistry {
&mut self.signatures
}
}

View File

@@ -52,8 +52,9 @@ pub use crate::sig_registry::SignatureRegistry;
pub use crate::signalhandlers::{wasmtime_init_eager, wasmtime_init_finish};
pub use crate::traphandlers::{wasmtime_call, wasmtime_call_trampoline};
pub use crate::vmcontext::{
VMContext, VMFunctionBody, VMFunctionImport, VMGlobalDefinition, VMGlobalImport,
VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport,
VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMFunctionImport, VMGlobalDefinition,
VMGlobalImport, VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition,
VMTableImport,
};
/// Version number of this crate.

View File

@@ -387,7 +387,7 @@ impl VMGlobalDefinition {
/// An index into the shared signature registry, usable for checking signatures
/// at indirect calls.
#[repr(C)]
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
pub struct VMSharedSignatureIndex(u32);
#[cfg(test)]
@@ -422,14 +422,23 @@ impl VMSharedSignatureIndex {
}
}
impl Default for VMSharedSignatureIndex {
fn default() -> Self {
VMSharedSignatureIndex::new(u32::MAX)
}
}
/// The VM caller-checked "anyfunc" record, for caller-side signature checking.
/// It consists of the actual function pointer and a signature id to be checked
/// by the caller.
#[derive(Debug, Clone)]
#[repr(C)]
pub struct VMCallerCheckedAnyfunc {
/// Function body.
pub func_ptr: *const VMFunctionBody,
/// Function signature id.
pub type_index: VMSharedSignatureIndex,
/// Function `VMContext`.
pub vmctx: *mut VMContext,
// If more elements are added here, remember to add offset_of tests below!
}
@@ -467,7 +476,7 @@ impl Default for VMCallerCheckedAnyfunc {
fn default() -> Self {
Self {
func_ptr: ptr::null_mut(),
type_index: VMSharedSignatureIndex::new(u32::MAX),
type_index: Default::default(),
vmctx: ptr::null_mut(),
}
}