use crate::host_ref::HostRef; use crate::{wasm_extern_t, wasm_extern_vec_t, wasm_module_t, wasm_trap_t}; use crate::{wasm_store_t, wasmtime_error_t, ExternHost}; use anyhow::Result; use std::cell::RefCell; use std::ptr; use wasmtime::{Extern, Instance, Store, Trap}; #[repr(C)] #[derive(Clone)] pub struct wasm_instance_t { pub(crate) instance: HostRef, exports_cache: RefCell>>, } wasmtime_c_api_macros::declare_ref!(wasm_instance_t); impl wasm_instance_t { pub(crate) fn new(instance: Instance) -> wasm_instance_t { let store = instance.store().clone(); wasm_instance_t { instance: HostRef::new(&store, instance), exports_cache: RefCell::new(None), } } fn externref(&self) -> wasmtime::ExternRef { self.instance.clone().into() } } #[no_mangle] pub unsafe extern "C" fn wasm_instance_new( store: &wasm_store_t, wasm_module: &wasm_module_t, imports: *const Box, result: Option<&mut *mut wasm_trap_t>, ) -> Option> { let mut instance = ptr::null_mut(); let mut trap = ptr::null_mut(); let err = wasmtime_instance_new( store, wasm_module, imports, wasm_module.imports.len(), &mut instance, &mut trap, ); match err { Some(err) => { assert!(trap.is_null()); assert!(instance.is_null()); if let Some(result) = result { *result = Box::into_raw(err.to_trap(&store.store)); } None } None => { if instance.is_null() { assert!(!trap.is_null()); if let Some(result) = result { *result = trap; } else { drop(Box::from_raw(trap)) } None } else { assert!(trap.is_null()); Some(Box::from_raw(instance)) } } } } #[no_mangle] pub unsafe extern "C" fn wasmtime_instance_new( store: &wasm_store_t, module: &wasm_module_t, imports: *const Box, num_imports: usize, instance_ptr: &mut *mut wasm_instance_t, trap_ptr: &mut *mut wasm_trap_t, ) -> Option> { _wasmtime_instance_new( store, module, std::slice::from_raw_parts(imports, num_imports), instance_ptr, trap_ptr, ) } fn _wasmtime_instance_new( store: &wasm_store_t, module: &wasm_module_t, imports: &[Box], instance_ptr: &mut *mut wasm_instance_t, trap_ptr: &mut *mut wasm_trap_t, ) -> Option> { let store = &store.store; let imports = imports .iter() .map(|import| match &import.which { ExternHost::Func(e) => Extern::Func(e.borrow().clone()), ExternHost::Table(e) => Extern::Table(e.borrow().clone()), ExternHost::Global(e) => Extern::Global(e.borrow().clone()), ExternHost::Memory(e) => Extern::Memory(e.borrow().clone()), }) .collect::>(); let module = &module.module.borrow(); handle_instantiate( store, Instance::new(store, module, &imports), instance_ptr, trap_ptr, ) } pub fn handle_instantiate( store: &Store, instance: Result, instance_ptr: &mut *mut wasm_instance_t, trap_ptr: &mut *mut wasm_trap_t, ) -> Option> { fn write(ptr: &mut *mut T, val: T) { *ptr = Box::into_raw(Box::new(val)) } match instance { Ok(instance) => { write(instance_ptr, wasm_instance_t::new(instance)); None } Err(e) => match e.downcast::() { Ok(trap) => { write(trap_ptr, wasm_trap_t::new(store, trap)); None } Err(e) => Some(Box::new(e.into())), }, } } #[no_mangle] pub extern "C" fn wasm_instance_exports(instance: &wasm_instance_t, out: &mut wasm_extern_vec_t) { let mut cache = instance.exports_cache.borrow_mut(); let exports = cache.get_or_insert_with(|| { let instance = &instance.instance.borrow(); instance .exports() .map(|e| match e.into_extern() { Extern::Func(f) => ExternHost::Func(HostRef::new(instance.store(), f)), Extern::Global(f) => ExternHost::Global(HostRef::new(instance.store(), f)), Extern::Memory(f) => ExternHost::Memory(HostRef::new(instance.store(), f)), Extern::Table(f) => ExternHost::Table(HostRef::new(instance.store(), f)), }) .collect() }); let mut buffer = Vec::with_capacity(exports.len()); for e in exports { let ext = Box::new(wasm_extern_t { which: e.clone() }); buffer.push(Some(ext)); } out.set_buffer(buffer); }