From de1c0f63eb16580ed8ad542b57f095463b774916 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Tue, 27 Aug 2019 11:44:02 -0500 Subject: [PATCH] Table operation; refactor Callable --- wasmtime-api/src/callable.rs | 95 +++++++++--- wasmtime-api/src/externals.rs | 148 +++++++++++++------ wasmtime-api/src/instance.rs | 6 + wasmtime-api/src/lib.rs | 1 + wasmtime-api/src/runtime.rs | 38 ++++- wasmtime-api/src/table_utils.rs | 123 +++++++++++++++ wasmtime-api/src/trampoline/create_handle.rs | 21 ++- wasmtime-api/src/trampoline/func.rs | 29 ++-- wasmtime-api/src/trampoline/global.rs | 3 +- wasmtime-api/src/trampoline/memory.rs | 2 +- wasmtime-api/src/trampoline/mod.rs | 24 ++- wasmtime-api/src/trampoline/table.rs | 35 +++++ wasmtime-api/src/values.rs | 69 +++++++-- wasmtime-api/src/wasm.rs | 140 +++++++++++++++++- wasmtime-jit/src/compiler.rs | 3 +- wasmtime-runtime/src/lib.rs | 5 +- wasmtime-runtime/src/vmcontext.rs | 13 +- 17 files changed, 641 insertions(+), 114 deletions(-) create mode 100644 wasmtime-api/src/table_utils.rs create mode 100644 wasmtime-api/src/trampoline/table.rs diff --git a/wasmtime-api/src/callable.rs b/wasmtime-api/src/callable.rs index 9da8735ec9..9783909d8b 100644 --- a/wasmtime-api/src/callable.rs +++ b/wasmtime-api/src/callable.rs @@ -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>>; } +pub(crate) trait WrappedCallable { + fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Rc>>; + 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>, - signature: ir::Signature, - body: *const VMFunctionBody, - vmctx: *mut VMContext, + instance: InstanceHandle, + export: Export, } impl WasmtimeFn { - pub fn new( - store: Rc>, - signature: ir::Signature, - body: *const VMFunctionBody, - vmctx: *mut VMContext, - ) -> WasmtimeFn { + pub fn new(store: Rc>, 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>> { 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, + instance: InstanceHandle, + export: Export, +} + +impl NativeCallable { + pub(crate) fn new( + callable: Rc, + ft: &FuncType, + store: &Rc>, + ) -> 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>> { + self.callable.call(params, results) + } + fn wasmtime_handle(&self) -> &InstanceHandle { + &self.instance + } + fn wasmtime_export(&self) -> &Export { + &self.export + } } diff --git a/wasmtime-api/src/externals.rs b/wasmtime-api/src/externals.rs index 1491f7d356..46775afbb6 100644 --- a/wasmtime-api/src/externals.rs +++ b/wasmtime-api/src/externals.rs @@ -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>, - callable: Rc, + callable: Rc, r#type: FuncType, - pub(crate) anchor: Option<(InstanceHandle, wasmtime_runtime::Export)>, } impl Func { pub fn new( store: Rc>, - r#type: FuncType, + ty: FuncType, callable: Rc, + ) -> Self { + let callable = Rc::new(NativeCallable::new(callable, &ty, &store)); + Func::from_wrapped(store, ty, callable) + } + + fn from_wrapped( + store: Rc>, + r#type: FuncType, + callable: Rc, ) -> Func { Func { _store: store, callable, r#type, - anchor: None, } } @@ -127,6 +117,10 @@ impl Func { &self.r#type } + pub(crate) fn callable(&self) -> &Rc { + &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, Rc>> { 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>, + 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>, + store: Rc>, r#type: TableType, + #[allow(dead_code)] + wasmtime_handle: InstanceHandle, + wasmtime_export: wasmtime_runtime::Export, } impl Table { - pub fn new(store: Rc>, r#type: TableType) -> Table { + pub fn new(store: Rc>, 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>, + 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, + } } } diff --git a/wasmtime-api/src/instance.rs b/wasmtime-api/src/instance.rs index 6c93f934b5..98e4d34c75 100644 --- a/wasmtime-api/src/instance.rs +++ b/wasmtime-api/src/instance.rs @@ -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(), diff --git a/wasmtime-api/src/lib.rs b/wasmtime-api/src/lib.rs index 5427a48082..e6e4aa1e41 100644 --- a/wasmtime-api/src/lib.rs +++ b/wasmtime-api/src/lib.rs @@ -6,6 +6,7 @@ mod externals; mod instance; mod module; mod runtime; +mod table_utils; mod trampoline; mod trap; mod types; diff --git a/wasmtime-api/src/runtime.rs b/wasmtime-api/src/runtime.rs index 6eb812e213..4e43a11cdf 100644 --- a/wasmtime-api/src/runtime.rs +++ b/wasmtime-api/src/runtime.rs @@ -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>, context: Context, global_exports: Rc>>>, + signature_cache: HashMap, } 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) + } +} diff --git a/wasmtime-api/src/table_utils.rs b/wasmtime-api/src/table_utils.rs new file mode 100644 index 0000000000..1b67028db4 --- /dev/null +++ b/wasmtime-api/src/table_utils.rs @@ -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>) -> 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>) -> 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>, + 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>, + 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>, + 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 +} diff --git a/wasmtime-api/src/trampoline/create_handle.rs b/wasmtime-api/src/trampoline/create_handle.rs index d1f4f2b888..af7aa35545 100644 --- a/wasmtime-api/src/trampoline/create_handle.rs +++ b/wasmtime-api/src/trampoline/create_handle.rs @@ -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>, finished_functions: PrimaryMap, state: Box, ) -> Result { @@ -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::>(), + ) + }) + .unwrap_or_else(|| PrimaryMap::new()); Ok(InstanceHandle::new( Rc::new(module), diff --git a/wasmtime-api/src/trampoline/func.rs b/wasmtime-api/src/trampoline/func.rs index 288b4e00e6..0b32f2b25f 100644 --- a/wasmtime-api/src/trampoline/func.rs +++ b/wasmtime-api/src/trampoline/func.rs @@ -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>, + func: Rc, trap: Option>>, #[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::() .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>) -> Result { - let sig = func.borrow().r#type().get_cranelift_signature().clone(); +pub fn create_handle_with_function( + ft: &FuncType, + func: &Rc, + store: &Rc>, +) -> Result { + let sig = ft.get_cranelift_signature().clone(); let isa = { let isa_builder = @@ -229,7 +233,12 @@ pub fn create_handle_with_function(func: &Rc>) -> Result Result>) -> Result<(), Error> { - let mut instance = create_handle_with_function(f)?; +pub fn generate_func_export( + ft: &FuncType, + func: &Rc, + store: &Rc>, +) -> 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)) +} diff --git a/wasmtime-api/src/trampoline/table.rs b/wasmtime-api/src/trampoline/table.rs new file mode 100644 index 0000000000..f5060abc7f --- /dev/null +++ b/wasmtime-api/src/trampoline/table.rs @@ -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 { + 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(())) +} diff --git a/wasmtime-api/src/values.rs b/wasmtime-api/src/values.rs index 878f3a00b2..a9a4f9c77f 100644 --- a/wasmtime-api/src/values.rs +++ b/wasmtime-api/src/values.rs @@ -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), + 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, -} +#[derive(Clone)] +pub struct FuncRef(pub(crate) Rc); 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 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 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>), - FuncRef(Rc>), + 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 for Val { } } -impl From>> for Val { - fn from(val: Rc>) -> Val { - Val::AnyRef(val) +impl From for Val { + fn from(val: AnyRef) -> Val { + match val { + AnyRef::Func(f) => Val::FuncRef(f), + _ => Val::AnyRef(val), + } } } -impl From>> for Val { - fn from(val: Rc>) -> Val { +impl From for Val { + fn from(val: FuncRef) -> Val { Val::FuncRef(val) } } + +impl Into 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), + } + } +} diff --git a/wasmtime-api/src/wasm.rs b/wasmtime-api/src/wasm.rs index d260d89081..b90c6be24d 100644 --- a/wasmtime-api/src/wasm.rs +++ b/wasmtime-api/src/wasm.rs @@ -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>, } 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) +} diff --git a/wasmtime-jit/src/compiler.rs b/wasmtime-jit/src/compiler.rs index 8cd3de4398..76a91ef5cb 100644 --- a/wasmtime-jit/src/compiler.rs +++ b/wasmtime-jit/src/compiler.rs @@ -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 } } diff --git a/wasmtime-runtime/src/lib.rs b/wasmtime-runtime/src/lib.rs index 8365d85423..8efb012a16 100644 --- a/wasmtime-runtime/src/lib.rs +++ b/wasmtime-runtime/src/lib.rs @@ -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. diff --git a/wasmtime-runtime/src/vmcontext.rs b/wasmtime-runtime/src/vmcontext.rs index 51cec31f84..fe840b0020 100644 --- a/wasmtime-runtime/src/vmcontext.rs +++ b/wasmtime-runtime/src/vmcontext.rs @@ -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(), } }