diff --git a/src/bin/wasmtime.rs b/src/bin/wasmtime.rs index 2687fcfe6f..6c9c435b46 100644 --- a/src/bin/wasmtime.rs +++ b/src/bin/wasmtime.rs @@ -36,17 +36,15 @@ use docopt::Docopt; use failure::{bail, Error, ResultExt}; use pretty_env_logger; use serde::Deserialize; -use std::cell::RefCell; use std::collections::HashMap; use std::ffi::OsStr; use std::fs::File; use std::path::Component; use std::path::{Path, PathBuf}; use std::process::exit; -use std::rc::Rc; use wabt; use wasi_common::preopen_dir; -use wasmtime_api::{Config, Engine, Instance, Module, Store}; +use wasmtime_api::{Config, Engine, HostRef, Instance, Module, Store}; use wasmtime_environ::cache_config; use wasmtime_interface_types::ModuleData; use wasmtime_jit::Features; @@ -258,8 +256,8 @@ fn rmain() -> Result<(), Error> { } let config = Config::new(settings::Flags::new(flag_builder), features, debug_info); - let engine = Rc::new(RefCell::new(Engine::new(config))); - let store = Rc::new(RefCell::new(Store::new(engine))); + let engine = HostRef::new(Engine::new(config)); + let store = HostRef::new(Store::new(engine)); let mut module_registry = HashMap::new(); @@ -308,14 +306,14 @@ fn rmain() -> Result<(), Error> { } fn instantiate_module( - store: Rc>, + store: HostRef, module_registry: &HashMap)>, path: &Path, -) -> Result<(Rc>, Rc>, Vec), Error> { +) -> Result<(HostRef, HostRef, Vec), Error> { // Read the wasm module binary. let data = read_wasm(path.to_path_buf())?; - let module = Rc::new(RefCell::new(Module::new(store.clone(), &data)?)); + let module = HostRef::new(Module::new(store.clone(), &data)?); // Resolve import using module_registry. let imports = module @@ -341,17 +339,13 @@ fn instantiate_module( }) .collect::, _>>()?; - let instance = Rc::new(RefCell::new(Instance::new( - store.clone(), - module.clone(), - &imports, - )?)); + let instance = HostRef::new(Instance::new(store.clone(), module.clone(), &imports)?); Ok((instance, module, data)) } fn handle_module( - store: Rc>, + store: HostRef, module_registry: &HashMap)>, args: &Args, path: &Path, @@ -368,8 +362,8 @@ fn handle_module( } fn invoke_export( - store: Rc>, - instance: Rc>, + store: HostRef, + instance: HostRef, data: &ModuleData, name: &str, args: &Args, diff --git a/wasmtime-api/examples/gcd.rs b/wasmtime-api/examples/gcd.rs index 36baf7f3fc..07176f527a 100644 --- a/wasmtime-api/examples/gcd.rs +++ b/wasmtime-api/examples/gcd.rs @@ -2,20 +2,18 @@ //! invoking its exported function. use failure::{format_err, Error}; -use std::cell::RefCell; use std::fs::read; -use std::rc::Rc; use wasmtime_api::*; fn main() -> Result<(), Error> { let wasm = read("examples/gcd.wasm")?; // Instantiate engine and store. - let engine = Rc::new(RefCell::new(Engine::default())); - let store = Rc::new(RefCell::new(Store::new(engine))); + let engine = HostRef::new(Engine::default()); + let store = HostRef::new(Store::new(engine)); // Load a module. - let module = Rc::new(RefCell::new(Module::new(store.clone(), &wasm)?)); + let module = HostRef::new(Module::new(store.clone(), &wasm)?); // Find index of the `gcd` export. let gcd_index = module @@ -28,12 +26,12 @@ fn main() -> Result<(), Error> { .0; // Instantiate the module. - let instance = Rc::new(RefCell::new(Instance::new(store.clone(), module, &[])?)); + let instance = HostRef::new(Instance::new(store.clone(), module, &[])?); // Invoke `gcd` export let gcd = instance.borrow().exports()[gcd_index] - .borrow() .func() + .expect("gcd") .clone(); let result = gcd .borrow() diff --git a/wasmtime-api/examples/hello.rs b/wasmtime-api/examples/hello.rs new file mode 100644 index 0000000000..4323ac4a70 --- /dev/null +++ b/wasmtime-api/examples/hello.rs @@ -0,0 +1,72 @@ +//! Translation of hello example + +use failure::{bail, format_err, Error}; +use std::cell::Ref; +use std::fs::read; +use std::rc::Rc; +use wasmtime_api::*; + +struct HelloCallback; + +impl Callable for HelloCallback { + fn call(&self, _params: &[Val], _results: &mut [Val]) -> Result<(), HostRef> { + println!("Calling back..."); + println!("> Hello World!"); + Ok(()) + } +} + +fn main() -> Result<(), Error> { + // Initialize. + println!("Initializing..."); + let engine = HostRef::new(Engine::new(Config::default())); + let store = HostRef::new(Store::new(engine)); + + // Load binary. + println!("Loading binary..."); + let binary = read("examples/hello.wasm")?; + + // Compile. + println!("Compiling module..."); + let module = HostRef::new( + Module::new(store.clone(), &binary) + .map_err(|_| format_err!("> Error compiling module!"))?, + ); + + // Create external print functions. + println!("Creating callback..."); + let hello_type = FuncType::new(Box::new([]), Box::new([])); + let hello_func = HostRef::new(Func::new(store.clone(), hello_type, Rc::new(HelloCallback))); + + // Instantiate. + println!("Instantiating module..."); + let imports = vec![hello_func.into()]; + let instance = HostRef::new( + Instance::new(store.clone(), module, imports.as_slice()) + .map_err(|_| format_err!("> Error instantiating module!"))?, + ); + + // Extract export. + println!("Extracting export..."); + let exports = Ref::map(instance.borrow(), |instance| instance.exports()); + if exports.len() == 0 { + bail!("> Error accessing exports!"); + } + let run_func = exports[0] + .func() + .ok_or_else(|| format_err!("> Error accessing exports!"))?; + + // Call. + println!("Calling export..."); + if let Err(_) = run_func.borrow().call(&[]) { + bail!("> Error calling function!"); + } + + // Shut down. + println!("Shutting down..."); + drop(store); + + // All done. + println!("Done."); + Ok(()) +} diff --git a/wasmtime-api/examples/hello.wasm b/wasmtime-api/examples/hello.wasm new file mode 100644 index 0000000000..2207c03eea Binary files /dev/null and b/wasmtime-api/examples/hello.wasm differ diff --git a/wasmtime-api/examples/hello.wat b/wasmtime-api/examples/hello.wat new file mode 100644 index 0000000000..1c56c55822 --- /dev/null +++ b/wasmtime-api/examples/hello.wat @@ -0,0 +1,4 @@ +(module + (func $hello (import "" "hello")) + (func (export "run") (call $hello)) +) diff --git a/wasmtime-api/examples/memory.rs b/wasmtime-api/examples/memory.rs new file mode 100644 index 0000000000..400c94a3bd --- /dev/null +++ b/wasmtime-api/examples/memory.rs @@ -0,0 +1,158 @@ +//! Translation of the memory example + +use failure::{bail, format_err, Error}; +use std::cell::Ref; +use std::fs::read; +use wasmtime_api::*; + +fn get_export_memory(exports: &[Extern], i: usize) -> Result, Error> { + if exports.len() <= i { + bail!("> Error accessing memory export {}!", i); + } + Ok(exports[i] + .memory() + .ok_or_else(|| format_err!("> Error accessing memory export {}!", i))? + .clone()) +} + +fn get_export_func(exports: &[Extern], i: usize) -> Result, Error> { + if exports.len() <= i { + bail!("> Error accessing function export {}!", i); + } + Ok(exports[i] + .func() + .ok_or_else(|| format_err!("> Error accessing function export {}!", i))? + .clone()) +} + +macro_rules! check { + ($actual:expr, $expected:expr) => { + if $actual != $expected { + bail!("> Error on result, expected {}, got {}", $expected, $actual); + } + }; +} + +macro_rules! check_ok { + ($func:expr, $($p:expr),*) => { + if let Err(_) = $func.borrow().call(&[$($p.into()),*]) { + bail!("> Error on result, expected return"); + } + } +} + +macro_rules! check_trap { + ($func:expr, $($p:expr),*) => { + if let Ok(_) = $func.borrow().call(&[$($p.into()),*]) { + bail!("> Error on result, expected trap"); + } + } +} + +macro_rules! call { + ($func:expr, $($p:expr),*) => { + match $func.borrow().call(&[$($p.into()),*]) { + Ok(result) => { + let result: i32 = result[0].clone().into(); + result + } + Err(_) => { bail!("> Error on result, expected return"); } + } + } +} + +fn main() -> Result<(), Error> { + // Initialize. + println!("Initializing..."); + let engine = HostRef::new(Engine::new(Config::default())); + let store = HostRef::new(Store::new(engine)); + + // Load binary. + println!("Loading binary..."); + let binary = read("examples/memory.wasm")?; + + // Compile. + println!("Compiling module..."); + let module = HostRef::new( + Module::new(store.clone(), &binary) + .map_err(|_| format_err!("> Error compiling module!"))?, + ); + + // Instantiate. + println!("Instantiating module..."); + let instance = HostRef::new( + Instance::new(store.clone(), module, &[]) + .map_err(|_| format_err!("> Error instantiating module!"))?, + ); + + // Extract export. + println!("Extracting export..."); + let exports = Ref::map(instance.borrow(), |instance| instance.exports()); + if exports.len() == 0 { + bail!("> Error accessing exports!"); + } + let memory = get_export_memory(&exports, 0)?; + let size_func = get_export_func(&exports, 1)?; + let load_func = get_export_func(&exports, 2)?; + let store_func = get_export_func(&exports, 3)?; + + // Try cloning. + check!(memory.clone().ptr_eq(&memory), true); + + // Check initial memory. + println!("Checking memory..."); + check!(memory.borrow().size(), 2u32); + check!(memory.borrow().data_size(), 0x20000usize); + check!(memory.borrow().data()[0], 0); + check!(memory.borrow().data()[0x1000], 1); + check!(memory.borrow().data()[0x1003], 4); + + check!(call!(size_func,), 2); + check!(call!(load_func, 0), 0); + check!(call!(load_func, 0x1000), 1); + check!(call!(load_func, 0x1003), 4); + check!(call!(load_func, 0x1ffff), 0); + check_trap!(load_func, 0x20000); + + // Mutate memory. + println!("Mutating memory..."); + memory.borrow_mut().data()[0x1003] = 5; + + check_ok!(store_func, 0x1002, 6); + check_trap!(store_func, 0x20000, 0); + + check!(memory.borrow().data()[0x1002], 6); + check!(memory.borrow().data()[0x1003], 5); + check!(call!(load_func, 0x1002), 6); + check!(call!(load_func, 0x1003), 5); + + // Grow memory. + println!("Growing memory..."); + check!(memory.borrow_mut().grow(1), true); + check!(memory.borrow().size(), 3u32); + check!(memory.borrow().data_size(), 0x30000usize); + + check!(call!(load_func, 0x20000), 0); + check_ok!(store_func, 0x20000, 0); + check_trap!(load_func, 0x30000); + check_trap!(store_func, 0x30000, 0); + + check!(memory.borrow_mut().grow(1), false); + check!(memory.borrow_mut().grow(0), true); + + // Create stand-alone memory. + // TODO(wasm+): Once Wasm allows multiple memories, turn this into import. + println!("Creating stand-alone memory..."); + let memorytype = MemoryType::new(Limits::new(5, 5)); + let mut memory2 = Memory::new(store.clone(), memorytype); + check!(memory2.size(), 5u32); + check!(memory2.grow(1), false); + check!(memory2.grow(0), true); + + // Shut down. + println!("Shutting down..."); + drop(store); + + println!("Done."); + Ok(()) +} diff --git a/wasmtime-api/examples/memory.wasm b/wasmtime-api/examples/memory.wasm new file mode 100644 index 0000000000..6f6518b187 Binary files /dev/null and b/wasmtime-api/examples/memory.wasm differ diff --git a/wasmtime-api/examples/memory.wat b/wasmtime-api/examples/memory.wat new file mode 100644 index 0000000000..4cf43e2c7d --- /dev/null +++ b/wasmtime-api/examples/memory.wat @@ -0,0 +1,11 @@ +(module + (memory (export "memory") 2 3) + + (func (export "size") (result i32) (memory.size)) + (func (export "load") (param i32) (result i32) (i32.load8_s (local.get 0))) + (func (export "store") (param i32 i32) + (i32.store8 (local.get 0) (local.get 1)) + ) + + (data (i32.const 0x1000) "\01\02\03\04") +) diff --git a/wasmtime-api/src/callable.rs b/wasmtime-api/src/callable.rs index 9783909d8b..187d1ffd43 100644 --- a/wasmtime-api/src/callable.rs +++ b/wasmtime-api/src/callable.rs @@ -1,8 +1,8 @@ +use crate::r#ref::HostRef; use crate::runtime::Store; use crate::trap::Trap; use crate::types::FuncType; use crate::values::Val; -use std::cell::RefCell; use std::rc::Rc; use crate::trampoline::generate_func_export; @@ -11,11 +11,11 @@ use wasmtime_jit::InstanceHandle; use wasmtime_runtime::Export; pub trait Callable { - fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Rc>>; + fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), HostRef>; } pub(crate) trait WrappedCallable { - fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Rc>>; + fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), HostRef>; fn signature(&self) -> &ir::Signature { match self.wasmtime_export() { Export::Function { signature, .. } => signature, @@ -27,13 +27,13 @@ pub(crate) trait WrappedCallable { } pub(crate) struct WasmtimeFn { - store: Rc>, + store: HostRef, instance: InstanceHandle, export: Export, } impl WasmtimeFn { - pub fn new(store: Rc>, instance: InstanceHandle, export: Export) -> WasmtimeFn { + pub fn new(store: HostRef, instance: InstanceHandle, export: Export) -> WasmtimeFn { WasmtimeFn { store, instance, @@ -43,7 +43,7 @@ impl WasmtimeFn { } impl WrappedCallable for WasmtimeFn { - fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Rc>> { + fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), HostRef> { use core::cmp::max; use core::{mem, ptr}; @@ -81,7 +81,7 @@ impl WrappedCallable for WasmtimeFn { let exec_code_buf = context .compiler() .get_published_trampoline(body, &signature, value_size) - .map_err(|_| Rc::new(RefCell::new(Trap::fake())))?; //was ActionError::Setup)?; + .map_err(|_| HostRef::new(Trap::fake()))?; //was ActionError::Setup)?; // Call the trampoline. if let Err(message) = unsafe { @@ -91,7 +91,7 @@ impl WrappedCallable for WasmtimeFn { values_vec.as_mut_ptr() as *mut u8, ) } { - return Err(Rc::new(RefCell::new(Trap::new(message)))); + return Err(HostRef::new(Trap::new(message))); } // Load the return values out of `values_vec`. @@ -129,7 +129,7 @@ impl NativeCallable { pub(crate) fn new( callable: Rc, ft: &FuncType, - store: &Rc>, + store: &HostRef, ) -> Self { let (instance, export) = generate_func_export(ft, &callable, store).expect("generated func"); @@ -142,7 +142,7 @@ impl NativeCallable { } impl WrappedCallable for NativeCallable { - fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Rc>> { + fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), HostRef> { self.callable.call(params, results) } fn wasmtime_handle(&self) -> &InstanceHandle { diff --git a/wasmtime-api/src/externals.rs b/wasmtime-api/src/externals.rs index f1cde77b90..a2296c457b 100644 --- a/wasmtime-api/src/externals.rs +++ b/wasmtime-api/src/externals.rs @@ -1,46 +1,48 @@ use crate::callable::{Callable, NativeCallable, WasmtimeFn, WrappedCallable}; +use crate::r#ref::{AnyRef, HostRef}; use crate::runtime::Store; 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::{from_checked_anyfunc, into_checked_anyfunc, AnyRef, Val}; -use std::cell::RefCell; +use crate::values::{from_checked_anyfunc, into_checked_anyfunc, Val}; use std::rc::Rc; use std::result::Result; +use std::slice; use wasmtime_runtime::InstanceHandle; // Externals +#[derive(Clone)] pub enum Extern { - Func(Rc>), - Global(Rc>), - Table(Rc>), - Memory(Rc>), + Func(HostRef), + Global(HostRef), + Table(HostRef), + Memory(HostRef), } impl Extern { - pub fn func(&self) -> &Rc> { + pub fn func(&self) -> Option<&HostRef> { match self { - Extern::Func(func) => func, - _ => panic!("Extern::Func expected"), + Extern::Func(func) => Some(func), + _ => None, } } - pub fn global(&self) -> &Rc> { + pub fn global(&self) -> Option<&HostRef> { match self { - Extern::Global(global) => global, - _ => panic!("Extern::Global expected"), + Extern::Global(global) => Some(global), + _ => None, } } - pub fn table(&self) -> &Rc> { + pub fn table(&self) -> Option<&HostRef
> { match self { - Extern::Table(table) => table, - _ => panic!("Extern::Table expected"), + Extern::Table(table) => Some(table), + _ => None, } } - pub fn memory(&self) -> &Rc> { + pub fn memory(&self) -> Option<&HostRef> { match self { - Extern::Memory(memory) => memory, - _ => panic!("Extern::Memory expected"), + Extern::Memory(memory) => Some(memory), + _ => None, } } @@ -63,45 +65,65 @@ impl Extern { } pub(crate) fn from_wasmtime_export( - store: Rc>, + store: HostRef, instance_handle: InstanceHandle, export: wasmtime_runtime::Export, ) -> Extern { match export { - wasmtime_runtime::Export::Function { .. } => Extern::Func(Rc::new(RefCell::new( + wasmtime_runtime::Export::Function { .. } => Extern::Func(HostRef::new( Func::from_wasmtime_function(export, store, instance_handle), - ))), - wasmtime_runtime::Export::Memory { .. } => Extern::Memory(Rc::new(RefCell::new( + )), + wasmtime_runtime::Export::Memory { .. } => Extern::Memory(HostRef::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 { .. } => Extern::Table(Rc::new(RefCell::new( + )), + wasmtime_runtime::Export::Global { .. } => { + Extern::Global(HostRef::new(Global::from_wasmtime_global(export, store))) + } + wasmtime_runtime::Export::Table { .. } => Extern::Table(HostRef::new( Table::from_wasmtime_table(export, store, instance_handle), - ))), + )), } } } +impl From> for Extern { + fn from(r: HostRef) -> Self { + Extern::Func(r) + } +} + +impl From> for Extern { + fn from(r: HostRef) -> Self { + Extern::Global(r) + } +} + +impl From> for Extern { + fn from(r: HostRef) -> Self { + Extern::Memory(r) + } +} + +impl From> for Extern { + fn from(r: HostRef
) -> Self { + Extern::Table(r) + } +} + pub struct Func { - _store: Rc>, + _store: HostRef, callable: Rc, r#type: FuncType, } impl Func { - pub fn new( - store: Rc>, - ty: FuncType, - callable: Rc, - ) -> Self { + pub fn new(store: HostRef, 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>, + store: HostRef, r#type: FuncType, callable: Rc, ) -> Func { @@ -116,11 +138,6 @@ impl Func { &self.r#type } - #[cfg(feature = "wasm-c-api")] - pub(crate) fn callable(&self) -> &Rc { - &self.callable - } - pub fn param_arity(&self) -> usize { self.r#type.params().len() } @@ -129,19 +146,19 @@ impl Func { self.r#type.results().len() } - pub fn call(&self, params: &[Val]) -> Result, Rc>> { + pub fn call(&self, params: &[Val]) -> Result, HostRef> { 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 { + pub(crate) fn wasmtime_export(&self) -> &wasmtime_runtime::Export { self.callable.wasmtime_export() } - fn from_wasmtime_function( + pub(crate) fn from_wasmtime_function( export: wasmtime_runtime::Export, - store: Rc>, + store: HostRef, instance_handle: InstanceHandle, ) -> Self { let ty = if let wasmtime_runtime::Export::Function { signature, .. } = &export { @@ -154,8 +171,14 @@ impl Func { } } +impl std::fmt::Debug for Func { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Func") + } +} + pub struct Global { - _store: Rc>, + _store: HostRef, r#type: GlobalType, wasmtime_export: wasmtime_runtime::Export, #[allow(dead_code)] @@ -163,7 +186,7 @@ pub struct Global { } impl Global { - pub fn new(store: Rc>, r#type: GlobalType, val: Val) -> Global { + pub fn new(store: HostRef, r#type: GlobalType, val: Val) -> Global { let (wasmtime_export, wasmtime_state) = generate_global_export(&r#type, val).expect("generated global"); Global { @@ -224,7 +247,7 @@ impl Global { pub(crate) fn from_wasmtime_global( export: wasmtime_runtime::Export, - store: Rc>, + store: HostRef, ) -> Global { let global = if let wasmtime_runtime::Export::Global { ref global, .. } = export { global @@ -242,7 +265,7 @@ impl Global { } pub struct Table { - store: Rc>, + store: HostRef, r#type: TableType, wasmtime_handle: InstanceHandle, wasmtime_export: wasmtime_runtime::Export, @@ -250,7 +273,7 @@ pub struct Table { fn get_table_item( handle: &InstanceHandle, - store: &Rc>, + store: &HostRef, table_index: cranelift_wasm::DefinedTableIndex, item_index: u32, ) -> Val { @@ -263,7 +286,7 @@ fn get_table_item( fn set_table_item( handle: &mut InstanceHandle, - store: &Rc>, + store: &HostRef, table_index: cranelift_wasm::DefinedTableIndex, item_index: u32, val: Val, @@ -278,7 +301,7 @@ fn set_table_item( } impl Table { - pub fn new(store: Rc>, r#type: TableType, init: Val) -> Table { + pub fn new(store: HostRef, r#type: TableType, init: Val) -> Table { match r#type.element() { ValType::FuncRef => (), _ => panic!("table is not for funcref"), @@ -363,7 +386,7 @@ impl Table { pub(crate) fn from_wasmtime_table( export: wasmtime_runtime::Export, - store: Rc>, + store: HostRef, instance_handle: wasmtime_runtime::InstanceHandle, ) -> Table { let table = if let wasmtime_runtime::Export::Table { ref table, .. } = export { @@ -382,14 +405,14 @@ impl Table { } pub struct Memory { - _store: Rc>, + _store: HostRef, r#type: MemoryType, wasmtime_handle: InstanceHandle, wasmtime_export: wasmtime_runtime::Export, } impl Memory { - pub fn new(store: Rc>, r#type: MemoryType) -> Memory { + pub fn new(store: HostRef, r#type: MemoryType) -> Memory { let (wasmtime_handle, wasmtime_export) = generate_memory_export(&r#type).expect("generated memory"); Memory { @@ -411,7 +434,14 @@ impl Memory { } } - pub fn data(&self) -> *mut u8 { + pub fn data(&self) -> &mut [u8] { + unsafe { + let definition = &*self.wasmtime_memory_definition(); + slice::from_raw_parts_mut(definition.base, definition.current_length) + } + } + + pub fn data_ptr(&self) -> *mut u8 { unsafe { (*self.wasmtime_memory_definition()).base } } @@ -440,7 +470,7 @@ impl Memory { pub(crate) fn from_wasmtime_memory( export: wasmtime_runtime::Export, - store: Rc>, + store: HostRef, instance_handle: wasmtime_runtime::InstanceHandle, ) -> Memory { let memory = if let wasmtime_runtime::Export::Memory { ref memory, .. } = export { diff --git a/wasmtime-api/src/instance.rs b/wasmtime-api/src/instance.rs index df76133191..a3bc0274e4 100644 --- a/wasmtime-api/src/instance.rs +++ b/wasmtime-api/src/instance.rs @@ -1,6 +1,7 @@ use crate::context::Context; use crate::externals::Extern; use crate::module::Module; +use crate::r#ref::HostRef; use crate::runtime::Store; use failure::Error; use std::cell::RefCell; @@ -11,22 +12,22 @@ use wasmtime_jit::{instantiate, Resolver}; use wasmtime_runtime::{Export, InstanceHandle}; struct SimpleResolver { - imports: Vec<(String, String, Rc>)>, + imports: Vec<(String, String, Extern)>, } impl Resolver for SimpleResolver { fn resolve(&mut self, name: &str, field: &str) -> Option { // TODO speedup lookup self.imports - .iter() + .iter_mut() .find(|(n, f, _)| name == n && field == f) - .map(|(_, _, e)| e.borrow_mut().get_wasmtime_export()) + .map(|(_, _, e)| e.get_wasmtime_export()) } } pub fn instantiate_in_context( data: &[u8], - imports: Vec<(String, String, Rc>)>, + imports: Vec<(String, String, Extern)>, mut context: Context, exports: Rc>>>, ) -> Result<(InstanceHandle, HashSet), Error> { @@ -51,14 +52,14 @@ pub struct Instance { // We need to keep CodeMemory alive. contexts: HashSet, - exports: Box<[Rc>]>, + exports: Box<[Extern]>, } impl Instance { pub fn new( - store: Rc>, - module: Rc>, - externs: &[Rc>], + store: HostRef, + module: HostRef, + externs: &[Extern], ) -> Result { let context = store.borrow_mut().context().clone(); let exports = store.borrow_mut().global_exports().clone(); @@ -78,11 +79,11 @@ impl Instance { for export in module.exports() { let name = export.name().to_string(); let export = instance_handle.lookup(&name).expect("export"); - exports.push(Rc::new(RefCell::new(Extern::from_wasmtime_export( + exports.push(Extern::from_wasmtime_export( store.clone(), instance_handle.clone(), export, - )))); + )); } exports.into_boxed_slice() }; @@ -93,12 +94,12 @@ impl Instance { }) } - pub fn exports(&self) -> &[Rc>] { + pub fn exports(&self) -> &[Extern] { &self.exports } pub fn from_handle( - store: Rc>, + store: HostRef, instance_handle: InstanceHandle, ) -> Result<(Instance, HashMap), Error> { let contexts = HashSet::new(); @@ -115,11 +116,11 @@ impl Instance { 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( + exports.push(Extern::from_wasmtime_export( store.clone(), instance_handle.clone(), export.clone(), - )))); + )); } Ok(( diff --git a/wasmtime-api/src/lib.rs b/wasmtime-api/src/lib.rs index 5427a48082..7248dc8616 100644 --- a/wasmtime-api/src/lib.rs +++ b/wasmtime-api/src/lib.rs @@ -5,6 +5,7 @@ mod context; mod externals; mod instance; mod module; +mod r#ref; mod runtime; mod trampoline; mod trap; @@ -21,6 +22,7 @@ pub use crate::callable::Callable; pub use crate::externals::*; pub use crate::instance::Instance; pub use crate::module::Module; +pub use crate::r#ref::{AnyRef, HostInfo, HostRef}; pub use crate::runtime::{Config, Engine, Store}; pub use crate::trap::Trap; pub use crate::types::*; diff --git a/wasmtime-api/src/module.rs b/wasmtime-api/src/module.rs index e2ed946a18..2383c2fb1a 100644 --- a/wasmtime-api/src/module.rs +++ b/wasmtime-api/src/module.rs @@ -1,11 +1,10 @@ +use crate::r#ref::HostRef; use crate::runtime::Store; use crate::types::{ ExportType, ExternType, FuncType, GlobalType, ImportType, Limits, MemoryType, Mutability, TableType, ValType, }; use failure::Error; -use std::cell::RefCell; -use std::rc::Rc; use wasmparser::{validate, ExternalKind, ImportSectionEntryType, ModuleReader, SectionCode}; @@ -170,14 +169,14 @@ fn read_imports_and_exports( #[derive(Clone)] pub struct Module { - store: Rc>, + store: HostRef, binary: Box<[u8]>, imports: Box<[ImportType]>, exports: Box<[ExportType]>, } impl Module { - pub fn new(store: Rc>, binary: &[u8]) -> Result { + pub fn new(store: HostRef, binary: &[u8]) -> Result { let (imports, exports) = read_imports_and_exports(binary)?; Ok(Module { store, diff --git a/wasmtime-api/src/ref.rs b/wasmtime-api/src/ref.rs new file mode 100644 index 0000000000..c6010c0624 --- /dev/null +++ b/wasmtime-api/src/ref.rs @@ -0,0 +1,210 @@ +use std::any::Any; +use std::cell::{self, RefCell}; +use std::fmt; +use std::rc::{Rc, Weak}; + +pub trait HostInfo { + fn finalize(&mut self) {} +} + +trait InternalRefBase: Any { + fn as_any(&self) -> &dyn Any; + fn host_info(&self) -> Option>>; + fn set_host_info(&self, info: Option>); + fn ptr_eq(&self, other: &dyn InternalRefBase) -> bool; +} + +#[derive(Clone)] +pub struct InternalRef(Rc); + +impl InternalRef { + pub fn is_ref(&self) -> bool { + let r = self.0.as_any(); + Any::is::>(r) + } + pub fn get_ref(&self) -> HostRef { + let r = self.0.as_any(); + r.downcast_ref::>() + .expect("reference is not T type") + .clone() + } +} + +struct AnyAndHostInfo { + any: Box, + host_info: Option>, +} + +impl Drop for AnyAndHostInfo { + fn drop(&mut self) { + if let Some(info) = &mut self.host_info { + info.finalize(); + } + } +} + +#[derive(Clone)] +pub struct OtherRef(Rc>); + +#[derive(Clone)] +pub enum AnyRef { + Null, + Ref(InternalRef), + Other(OtherRef), +} + +impl AnyRef { + pub fn new(data: Box) -> Self { + let info = AnyAndHostInfo { + any: data, + host_info: None, + }; + AnyRef::Other(OtherRef(Rc::new(RefCell::new(info)))) + } + + pub fn null() -> Self { + AnyRef::Null + } + + pub fn data(&self) -> cell::Ref> { + match self { + AnyRef::Other(OtherRef(r)) => cell::Ref::map(r.borrow(), |r| &r.any), + _ => panic!("expected AnyRef::Other"), + } + } + + pub fn ptr_eq(&self, other: &AnyRef) -> bool { + match (self, other) { + (AnyRef::Null, AnyRef::Null) => true, + (AnyRef::Ref(InternalRef(ref a)), AnyRef::Ref(InternalRef(ref b))) => { + a.ptr_eq(b.as_ref()) + } + (AnyRef::Other(OtherRef(ref a)), AnyRef::Other(OtherRef(ref b))) => Rc::ptr_eq(a, b), + _ => false, + } + } + + pub fn host_info(&self) -> Option>> { + match self { + AnyRef::Null => panic!("null"), + AnyRef::Ref(r) => r.0.host_info(), + AnyRef::Other(r) => { + let info = cell::RefMut::map(r.0.borrow_mut(), |b| &mut b.host_info); + if info.is_none() { + return None; + } + Some(cell::RefMut::map(info, |info| info.as_mut().unwrap())) + } + } + } + + pub fn set_host_info(&self, info: Option>) { + match self { + AnyRef::Null => panic!("null"), + AnyRef::Ref(r) => r.0.set_host_info(info), + AnyRef::Other(r) => { + r.0.borrow_mut().host_info = info; + } + } + } +} + +impl fmt::Debug for AnyRef { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + AnyRef::Null => write!(f, "null"), + AnyRef::Ref(_) => write!(f, "anyref"), + AnyRef::Other(_) => write!(f, "other ref"), + } + } +} + +struct ContentBox { + content: T, + host_info: Option>, + anyref_data: Weak, +} + +impl Drop for ContentBox { + fn drop(&mut self) { + if let Some(info) = &mut self.host_info { + info.finalize(); + } + } +} + +pub struct HostRef(Rc>>); + +impl HostRef { + pub fn new(item: T) -> HostRef { + let anyref_data: Weak> = Weak::new(); + let content = ContentBox { + content: item, + host_info: None, + anyref_data, + }; + HostRef(Rc::new(RefCell::new(content))) + } + + pub fn borrow(&self) -> cell::Ref { + cell::Ref::map(self.0.borrow(), |b| &b.content) + } + + pub fn borrow_mut(&self) -> cell::RefMut { + cell::RefMut::map(self.0.borrow_mut(), |b| &mut b.content) + } + + pub fn ptr_eq(&self, other: &HostRef) -> bool { + Rc::ptr_eq(&self.0, &other.0) + } + + pub fn anyref(&self) -> AnyRef { + let r = self.0.borrow_mut().anyref_data.upgrade(); + if let Some(r) = r { + return AnyRef::Ref(InternalRef(r)); + } + let anyref_data: Rc = Rc::new(self.clone()); + self.0.borrow_mut().anyref_data = Rc::downgrade(&anyref_data); + AnyRef::Ref(InternalRef(anyref_data)) + } +} + +impl InternalRefBase for HostRef { + fn ptr_eq(&self, other: &dyn InternalRefBase) -> bool { + if let Some(other) = other.as_any().downcast_ref() { + self.ptr_eq(other) + } else { + false + } + } + + fn as_any(&self) -> &dyn Any { + self + } + + fn host_info(&self) -> Option>> { + let info = cell::RefMut::map(self.0.borrow_mut(), |b| &mut b.host_info); + if info.is_none() { + return None; + } + Some(cell::RefMut::map(info, |info| info.as_mut().unwrap())) + } + + fn set_host_info(&self, info: Option>) { + self.0.borrow_mut().host_info = info; + } +} + +impl Clone for HostRef { + fn clone(&self) -> HostRef { + HostRef(self.0.clone()) + } +} + +impl fmt::Debug for HostRef { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Ref(")?; + self.0.borrow().content.fmt(f)?; + write!(f, ")") + } +} diff --git a/wasmtime-api/src/runtime.rs b/wasmtime-api/src/runtime.rs index f00481c411..61de46a3b6 100644 --- a/wasmtime-api/src/runtime.rs +++ b/wasmtime-api/src/runtime.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use std::rc::Rc; use crate::context::{create_compiler, Context}; +use crate::r#ref::HostRef; use cranelift_codegen::{ir, settings}; use wasmtime_jit::Features; @@ -80,14 +81,14 @@ impl Engine { // Store pub struct Store { - engine: Rc>, + engine: HostRef, context: Context, global_exports: Rc>>>, signature_cache: HashMap, } impl Store { - pub fn new(engine: Rc>) -> Store { + pub fn new(engine: HostRef) -> Store { let flags = engine.borrow().config().flags().clone(); let features = engine.borrow().config().features().clone(); let debug_info = engine.borrow().config().debug_info(); @@ -99,7 +100,7 @@ impl Store { } } - pub fn engine(&self) -> &Rc> { + pub fn engine(&self) -> &HostRef { &self.engine } diff --git a/wasmtime-api/src/trampoline/func.rs b/wasmtime-api/src/trampoline/func.rs index 0b32f2b25f..3107ed28f4 100644 --- a/wasmtime-api/src/trampoline/func.rs +++ b/wasmtime-api/src/trampoline/func.rs @@ -1,5 +1,6 @@ //! Support for a calling of an imported function. +use crate::r#ref::HostRef; use crate::trampoline::code_memory::CodeMemory; use cranelift_codegen::ir::types; use cranelift_codegen::ir::{InstBuilder, StackSlotData, StackSlotKind, TrapCode}; @@ -14,7 +15,6 @@ use wasmtime_environ::{Export, Module}; use wasmtime_runtime::{InstanceHandle, VMContext, VMFunctionBody}; use core::cmp; -use std::cell::RefCell; use std::rc::Rc; use crate::{Callable, FuncType, Store, Trap, Val}; @@ -23,7 +23,7 @@ use super::create_handle::create_handle; struct TrampolineState { func: Rc, - trap: Option>>, + trap: Option>, #[allow(dead_code)] code_memory: CodeMemory, } @@ -191,7 +191,7 @@ fn make_trampoline( pub fn create_handle_with_function( ft: &FuncType, func: &Rc, - store: &Rc>, + store: &HostRef, ) -> Result { let sig = ft.get_cranelift_signature().clone(); diff --git a/wasmtime-api/src/trampoline/mod.rs b/wasmtime-api/src/trampoline/mod.rs index f08ca6e2ef..1d789c13f9 100644 --- a/wasmtime-api/src/trampoline/mod.rs +++ b/wasmtime-api/src/trampoline/mod.rs @@ -7,8 +7,8 @@ mod global; mod memory; mod table; +use crate::r#ref::HostRef; use failure::Error; -use std::cell::RefCell; use std::rc::Rc; use self::func::create_handle_with_function; @@ -22,7 +22,7 @@ pub use self::global::GlobalState; pub fn generate_func_export( ft: &FuncType, func: &Rc, - store: &Rc>, + store: &HostRef, ) -> 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"); diff --git a/wasmtime-api/src/values.rs b/wasmtime-api/src/values.rs index f8b1430f13..561f3ddcc8 100644 --- a/wasmtime-api/src/values.rs +++ b/wasmtime-api/src/values.rs @@ -1,63 +1,12 @@ -use crate::callable::{WasmtimeFn, WrappedCallable}; +use crate::externals::Func; +use crate::r#ref::{AnyRef, HostRef}; use crate::runtime::Store; use crate::types::ValType; -use std::any::Any; -use std::cell::RefCell; -use std::fmt; use std::ptr; -use std::rc::Rc; use cranelift_codegen::ir; use wasmtime_jit::RuntimeValue; -#[derive(Clone)] -pub enum AnyRef { - Null, - Rc(Rc), - Func(FuncRef), -} - -impl AnyRef { - pub fn null() -> AnyRef { - AnyRef::Null - } -} - -impl fmt::Debug for AnyRef { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - AnyRef::Null => write!(f, "null"), - AnyRef::Rc(_) => write!(f, "anyref"), - AnyRef::Func(func) => func.fmt(f), - } - } -} - -#[derive(Clone)] -pub struct FuncRef(pub(crate) Rc); - -impl fmt::Debug for FuncRef { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "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), @@ -65,7 +14,7 @@ pub enum Val { F32(u32), F64(u64), AnyRef(AnyRef), - FuncRef(FuncRef), + FuncRef(HostRef), } impl Val { @@ -179,15 +128,21 @@ impl Into for Val { impl From for Val { fn from(val: AnyRef) -> Val { - match val { - AnyRef::Func(f) => Val::FuncRef(f), - _ => Val::AnyRef(val), + match &val { + AnyRef::Ref(r) => { + if r.is_ref::() { + Val::FuncRef(r.get_ref()) + } else { + Val::AnyRef(val) + } + } + _ => unimplemented!("AnyRef::Other"), } } } -impl From for Val { - fn from(val: FuncRef) -> Val { +impl From> for Val { + fn from(val: HostRef) -> Val { Val::FuncRef(val) } } @@ -196,7 +151,7 @@ impl Into for Val { fn into(self) -> AnyRef { match self { Val::AnyRef(r) => r, - Val::FuncRef(f) => AnyRef::Func(f), + Val::FuncRef(f) => f.anyref(), _ => panic!("Invalid conversion of {:?} to anyref.", self), } } @@ -204,7 +159,7 @@ impl Into for Val { pub(crate) fn into_checked_anyfunc( val: Val, - store: &Rc>, + store: &HostRef, ) -> wasmtime_runtime::VMCallerCheckedAnyfunc { match val { Val::AnyRef(AnyRef::Null) => wasmtime_runtime::VMCallerCheckedAnyfunc { @@ -212,8 +167,9 @@ pub(crate) fn into_checked_anyfunc( type_index: wasmtime_runtime::VMSharedSignatureIndex::default(), vmctx: ptr::null_mut(), }, - Val::AnyRef(AnyRef::Func(f)) | Val::FuncRef(f) => { - let (vmctx, func_ptr, signature) = match f.0.wasmtime_export() { + Val::FuncRef(f) => { + let f = f.borrow(); + let (vmctx, func_ptr, signature) = match f.wasmtime_export() { wasmtime_runtime::Export::Function { vmctx, address, @@ -234,7 +190,7 @@ pub(crate) fn into_checked_anyfunc( pub(crate) fn from_checked_anyfunc( item: &wasmtime_runtime::VMCallerCheckedAnyfunc, - store: &Rc>, + store: &HostRef, ) -> Val { if item.type_index == wasmtime_runtime::VMSharedSignatureIndex::default() { return Val::AnyRef(AnyRef::Null); @@ -250,6 +206,6 @@ pub(crate) fn from_checked_anyfunc( signature, vmctx: item.vmctx, }; - let f = WasmtimeFn::new(store.clone(), instance_handle, export); - Val::FuncRef(FuncRef(Rc::new(f))) + let f = Func::from_wasmtime_function(export, store.clone(), instance_handle); + Val::FuncRef(HostRef::new(f)) } diff --git a/wasmtime-api/src/wasm.rs b/wasmtime-api/src/wasm.rs index b90c6be24d..9f56eaefeb 100644 --- a/wasmtime-api/src/wasm.rs +++ b/wasmtime-api/src/wasm.rs @@ -6,12 +6,11 @@ // TODO complete the C API use super::{ - AnyRef, Callable, Engine, ExportType, Extern, ExternType, Func, FuncRef, FuncType, Global, - GlobalType, ImportType, Instance, Limits, Memory, MemoryType, Module, Name, Store, Table, - TableType, Trap, Val, ValType, + AnyRef, Callable, Engine, ExportType, Extern, ExternType, Func, FuncType, Global, GlobalType, + HostInfo, HostRef, ImportType, Instance, Limits, Memory, MemoryType, Module, Name, Store, + Table, TableType, Trap, Val, ValType, }; use std::boxed::Box; -use std::cell::RefCell; use std::mem; use std::ptr; use std::rc::Rc; @@ -166,12 +165,12 @@ pub struct wasm_config_t { #[repr(C)] #[derive(Clone)] pub struct wasm_engine_t { - engine: Rc>, + engine: HostRef, } #[repr(C)] #[derive(Clone)] pub struct wasm_store_t { - store: Rc>, + store: HostRef, } #[doc = ""] pub type wasm_mutability_t = u8; @@ -312,13 +311,13 @@ declare_vec!(wasm_frame_vec_t, *mut wasm_frame_t); #[repr(C)] #[derive(Clone)] pub struct wasm_instance_t { - instance: Rc>, + instance: HostRef, } pub type wasm_message_t = wasm_name_t; #[repr(C)] #[derive(Clone)] pub struct wasm_trap_t { - trap: Rc>, + trap: HostRef, } #[repr(C)] #[derive(Clone)] @@ -328,7 +327,7 @@ pub struct wasm_foreign_t { #[repr(C)] #[derive(Clone)] pub struct wasm_module_t { - module: Rc>, + module: HostRef, imports: Vec, exports: Vec, } @@ -340,7 +339,7 @@ pub struct wasm_shared_module_t { #[repr(C)] #[derive(Clone)] pub struct wasm_func_t { - func: Rc>, + func: HostRef, } pub type wasm_func_callback_t = ::std::option::Option< unsafe extern "C" fn(args: *const wasm_val_t, results: *mut wasm_val_t) -> *mut wasm_trap_t, @@ -355,24 +354,24 @@ pub type wasm_func_callback_with_env_t = ::std::option::Option< #[repr(C)] #[derive(Clone)] pub struct wasm_global_t { - global: Rc>, + global: HostRef, } #[repr(C)] #[derive(Clone)] pub struct wasm_table_t { - table: Rc>, + table: HostRef
, } pub type wasm_table_size_t = u32; #[repr(C)] #[derive(Clone)] pub struct wasm_memory_t { - memory: Rc>, + memory: HostRef, } pub type wasm_memory_pages_t = u32; #[repr(C)] #[derive(Clone)] pub struct wasm_extern_t { - ext: Rc>, + ext: Extern, } declare_vec!(wasm_extern_vec_t, *mut wasm_extern_t); @@ -395,14 +394,18 @@ pub unsafe extern "C" fn wasm_engine_delete(engine: *mut wasm_engine_t) { #[no_mangle] pub unsafe extern "C" fn wasm_engine_new() -> *mut wasm_engine_t { let engine = Box::new(wasm_engine_t { - engine: Rc::new(RefCell::new(Engine::default())), + engine: HostRef::new(Engine::default()), }); Box::into_raw(engine) } #[no_mangle] pub unsafe extern "C" fn wasm_extern_as_func(e: *mut wasm_extern_t) -> *mut wasm_func_t { - let func = (*e).ext.borrow().func().clone(); + let func = if let Some(f) = (*e).ext.func() { + f.clone() + } else { + return ptr::null_mut(); + }; let func = Box::new(wasm_func_t { func }); Box::into_raw(func) } @@ -415,9 +418,7 @@ pub unsafe extern "C" fn wasm_extern_vec_delete(v: *mut wasm_extern_vec_t) { #[no_mangle] pub unsafe extern "C" fn wasm_func_as_extern(f: *mut wasm_func_t) -> *mut wasm_extern_t { let ext = Extern::Func((*f).func.clone()); - let ext = Box::new(wasm_extern_t { - ext: Rc::new(RefCell::new(ext)), - }); + let ext = Box::new(wasm_extern_t { ext }); Box::into_raw(ext) } @@ -512,7 +513,7 @@ impl wasm_val_t { } impl Callable for wasm_func_callback_t { - fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Rc>> { + fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), HostRef> { let params = params .iter() .map(|p| wasm_val_t::from_val(p)) @@ -531,8 +532,8 @@ impl Callable for wasm_func_callback_t { } } -impl Into>> for wasm_trap_t { - fn into(self) -> Rc> { +impl Into> for wasm_trap_t { + fn into(self) -> HostRef { self.trap } } @@ -544,7 +545,7 @@ struct CallbackWithEnv { } impl Callable for CallbackWithEnv { - fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), Rc>> { + fn call(&self, params: &[Val], results: &mut [Val]) -> Result<(), HostRef> { let params = params .iter() .map(|p| wasm_val_t::from_val(p)) @@ -583,7 +584,7 @@ pub unsafe extern "C" fn wasm_func_new( let ty = (*ty).functype.clone(); let callback = Rc::new(callback); let func = Box::new(wasm_func_t { - func: Rc::new(RefCell::new(Func::new(store, ty, callback))), + func: HostRef::new(Func::new(store, ty, callback)), }); Box::into_raw(func) } @@ -633,7 +634,7 @@ pub unsafe extern "C" fn wasm_instance_new( result: *mut *mut wasm_trap_t, ) -> *mut wasm_instance_t { let store = (*store).store.clone(); - let mut externs: Vec>> = Vec::with_capacity((*module).imports.len()); + let mut externs: Vec = Vec::with_capacity((*module).imports.len()); for i in 0..(*module).imports.len() { let import = *imports.offset(i as isize); externs.push((*import).ext.clone()); @@ -642,7 +643,7 @@ pub unsafe extern "C" fn wasm_instance_new( match Instance::new(store, module, &externs) { Ok(instance) => { let instance = Box::new(wasm_instance_t { - instance: Rc::new(RefCell::new(instance)), + instance: HostRef::new(instance), }); if !result.is_null() { (*result) = ptr::null_mut(); @@ -653,9 +654,7 @@ pub unsafe extern "C" fn wasm_instance_new( if !result.is_null() { // TODO Unwrap trap from failure::Error let trap = Box::new(wasm_trap_t { - trap: Rc::new(RefCell::new(Trap::new( - "trap during instantiation".to_string(), - ))), + trap: HostRef::new(Trap::new("trap during instantiation".to_string())), }); (*result) = Box::into_raw(trap); } @@ -715,7 +714,7 @@ pub unsafe extern "C" fn wasm_module_new( }) .collect::>(); let module = Box::new(wasm_module_t { - module: Rc::new(RefCell::new(module)), + module: HostRef::new(module), imports, exports, }); @@ -731,7 +730,7 @@ pub unsafe extern "C" fn wasm_store_delete(store: *mut wasm_store_t) { pub unsafe extern "C" fn wasm_store_new(engine: *mut wasm_engine_t) -> *mut wasm_store_t { let engine = (*engine).engine.clone(); let store = Box::new(wasm_store_t { - store: Rc::new(RefCell::new(Store::new(engine))), + store: HostRef::new(Store::new(engine)), }); Box::into_raw(store) } @@ -757,7 +756,7 @@ pub unsafe extern "C" fn wasm_func_new_with_env( finalizer, }); let func = Box::new(wasm_func_t { - func: Rc::new(RefCell::new(Func::new(store, ty, callback))), + func: HostRef::new(Func::new(store, ty, callback)), }); Box::into_raw(func) } @@ -867,7 +866,7 @@ pub unsafe extern "C" fn wasm_trap_new( } let message = String::from_utf8_lossy(message).to_string(); let trap = Box::new(wasm_trap_t { - trap: Rc::new(RefCell::new(Trap::new(message))), + trap: HostRef::new(Trap::new(message)), }); Box::into_raw(trap) } @@ -927,13 +926,13 @@ fn from_externtype(ty: &ExternType) -> wasm_externkind_t { #[no_mangle] pub unsafe extern "C" fn wasm_extern_kind(e: *const wasm_extern_t) -> wasm_externkind_t { - from_externtype(&(*e).ext.borrow().r#type()) + from_externtype(&(*e).ext.r#type()) } #[no_mangle] pub unsafe extern "C" fn wasm_extern_type(e: *const wasm_extern_t) -> *mut wasm_externtype_t { let et = Box::new(wasm_externtype_t { - ty: (*e).ext.borrow().r#type(), + ty: (*e).ext.r#type(), cache: wasm_externtype_t_type_cache::Empty, }); Box::into_raw(et) @@ -1175,15 +1174,18 @@ pub unsafe extern "C" fn wasm_valtype_kind(vt: *const wasm_valtype_t) -> wasm_va #[no_mangle] pub unsafe extern "C" fn wasm_extern_as_global(e: *mut wasm_extern_t) -> *mut wasm_global_t { - let g = Box::new(wasm_global_t { - global: (*e).ext.borrow().global().clone(), - }); + let global = if let Some(g) = (*e).ext.global() { + g.clone() + } else { + return ptr::null_mut(); + }; + let g = Box::new(wasm_global_t { global }); Box::into_raw(g) } #[no_mangle] pub unsafe extern "C" fn wasm_global_as_extern(g: *mut wasm_global_t) -> *mut wasm_extern_t { - let ext = Rc::new(RefCell::new(Extern::Global((*g).global.clone()))); + let ext = (*g).global.clone().into(); let ext = Box::new(wasm_extern_t { ext }); Box::into_raw(ext) } @@ -1203,7 +1205,7 @@ pub unsafe extern "C" fn wasm_global_same( g1: *const wasm_global_t, g2: *const wasm_global_t, ) -> bool { - (*g1).global.as_ptr() == (*g2).global.as_ptr() + (*g1).global.ptr_eq(&(*g2).global) } #[no_mangle] @@ -1212,11 +1214,11 @@ pub unsafe extern "C" fn wasm_global_new( gt: *const wasm_globaltype_t, val: *const wasm_val_t, ) -> *mut wasm_global_t { - let global = Rc::new(RefCell::new(Global::new( + let global = HostRef::new(Global::new( (*store).store.clone(), (*gt).globaltype.clone(), (*val).val(), - ))); + )); let g = Box::new(wasm_global_t { global }); Box::into_raw(g) } @@ -1258,9 +1260,12 @@ pub unsafe extern "C" fn wasm_globaltype_new( #[no_mangle] pub unsafe extern "C" fn wasm_extern_as_memory(e: *mut wasm_extern_t) -> *mut wasm_memory_t { - let g = Box::new(wasm_memory_t { - memory: (*e).ext.borrow().memory().clone(), - }); + let memory = if let Some(m) = (*e).ext.memory() { + m.clone() + } else { + return ptr::null_mut(); + }; + let g = Box::new(wasm_memory_t { memory }); Box::into_raw(g) } @@ -1279,12 +1284,12 @@ pub unsafe extern "C" fn wasm_memory_same( m1: *const wasm_memory_t, m2: *const wasm_memory_t, ) -> bool { - (*m1).memory.as_ptr() == (*m2).memory.as_ptr() + (*m1).memory.ptr_eq(&(*m2).memory) } #[no_mangle] pub unsafe extern "C" fn wasm_memory_data(m: *mut wasm_memory_t) -> *mut u8 { - (*m).memory.borrow().data() + (*m).memory.borrow().data_ptr() } #[no_mangle] @@ -1310,10 +1315,10 @@ pub unsafe extern "C" fn wasm_memory_new( store: *mut wasm_store_t, mt: *const wasm_memorytype_t, ) -> *mut wasm_memory_t { - let memory = Rc::new(RefCell::new(Memory::new( + let memory = HostRef::new(Memory::new( (*store).store.clone(), (*mt).memorytype.clone(), - ))); + )); let m = Box::new(wasm_memory_t { memory }); Box::into_raw(m) } @@ -1337,18 +1342,19 @@ pub unsafe extern "C" fn wasm_memorytype_new( #[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(), - }); + let table = if let Some(t) = (*e).ext.table() { + t.clone() + } else { + return ptr::null_mut(); + }; + let t = Box::new(wasm_table_t { table }); 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)), - }); + let r = (*f).func.anyref(); + let f = Box::new(wasm_ref_t { r }); Box::into_raw(f) } @@ -1381,11 +1387,11 @@ pub unsafe extern "C" fn wasm_table_new( Val::AnyRef(AnyRef::Null) }; let t = Box::new(wasm_table_t { - table: Rc::new(RefCell::new(Table::new( + table: HostRef::new(Table::new( (*store).store.clone(), (*tt).tabletype.clone(), init, - ))), + )), }); Box::into_raw(t) } @@ -1442,7 +1448,7 @@ pub unsafe extern "C" fn wasm_table_grow( #[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() + (*t1).table.ptr_eq(&(*t2).table) } #[no_mangle] @@ -1464,3 +1470,33 @@ pub unsafe extern "C" fn wasm_tabletype_new( }); Box::into_raw(tt) } + +struct HostInfoState { + info: *mut ::std::os::raw::c_void, + finalizer: ::std::option::Option, +} + +impl HostInfo for HostInfoState { + fn finalize(&mut self) { + if let Some(f) = &self.finalizer { + unsafe { + f(self.info); + } + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn wasm_instance_set_host_info_with_finalizer( + instance: *mut wasm_instance_t, + info: *mut ::std::os::raw::c_void, + finalizer: ::std::option::Option, +) { + let info = if info.is_null() && finalizer.is_none() { + None + } else { + let b: Box = Box::new(HostInfoState { info, finalizer }); + Some(b) + }; + (*instance).instance.anyref().set_host_info(info); +}