use crate::host::HostState;
use crate::imports::{Imports, resolve_imports};
use crate::instance_wrapper::{ModuleWrapper, InstanceWrapper, GlobalsSnapshot, EntryPoint};
use crate::state_holder;
use std::rc::Rc;
use std::sync::Arc;
use tc_executor_common::{
error::{Result, WasmError},
wasm_runtime::{WasmModule, WasmInstance, InvokeMethod},
};
use tp_allocator::FreeingBumpHeapAllocator;
use tp_runtime_interface::unpack_ptr_and_len;
use tetcore_wasm_interface::{Function, Pointer, WordSize, Value};
use wasmtime::{Config, Engine, Store};
pub struct WasmtimeRuntime {
module_wrapper: Arc<ModuleWrapper>,
heap_pages: u32,
allow_missing_func_imports: bool,
host_functions: Vec<&'static dyn Function>,
engine: Engine,
}
impl WasmModule for WasmtimeRuntime {
fn new_instance(&self) -> Result<Box<dyn WasmInstance>> {
let store = Store::new(&self.engine);
let imports = resolve_imports(
&store,
self.module_wrapper.module(),
&self.host_functions,
self.heap_pages,
self.allow_missing_func_imports,
)?;
let instance_wrapper =
InstanceWrapper::new(&store, &self.module_wrapper, &imports, self.heap_pages)?;
let heap_base = instance_wrapper.extract_heap_base()?;
let globals_snapshot = GlobalsSnapshot::take(&instance_wrapper)?;
Ok(Box::new(WasmtimeInstance {
store,
instance_wrapper: Rc::new(instance_wrapper),
module_wrapper: Arc::clone(&self.module_wrapper),
imports,
globals_snapshot,
heap_pages: self.heap_pages,
heap_base,
}))
}
}
pub struct WasmtimeInstance {
store: Store,
module_wrapper: Arc<ModuleWrapper>,
instance_wrapper: Rc<InstanceWrapper>,
globals_snapshot: GlobalsSnapshot,
imports: Imports,
heap_pages: u32,
heap_base: u32,
}
unsafe impl Send for WasmtimeInstance {}
impl WasmInstance for WasmtimeInstance {
fn call(&self, method: InvokeMethod, data: &[u8]) -> Result<Vec<u8>> {
let entrypoint = self.instance_wrapper.resolve_entrypoint(method)?;
let allocator = FreeingBumpHeapAllocator::new(self.heap_base);
self.module_wrapper
.data_segments_snapshot()
.apply(|offset, contents| {
self.instance_wrapper
.write_memory_from(Pointer::new(offset), contents)
})?;
self.globals_snapshot.apply(&*self.instance_wrapper)?;
perform_call(
data,
Rc::clone(&self.instance_wrapper),
entrypoint,
allocator,
)
}
fn get_global_const(&self, name: &str) -> Result<Option<Value>> {
let instance = InstanceWrapper::new(&self.store, &self.module_wrapper, &self.imports, self.heap_pages)?;
instance.get_global_val(name)
}
}
pub fn create_runtime(
code: &[u8],
heap_pages: u64,
host_functions: Vec<&'static dyn Function>,
allow_missing_func_imports: bool,
) -> std::result::Result<WasmtimeRuntime, WasmError> {
let mut config = Config::new();
config.cranelift_opt_level(wasmtime::OptLevel::SpeedAndSize);
let engine = Engine::new(&config);
let module_wrapper = ModuleWrapper::new(&engine, code)
.map_err(|e| WasmError::Other(format!("cannot create module: {}", e)))?;
Ok(WasmtimeRuntime {
module_wrapper: Arc::new(module_wrapper),
heap_pages: heap_pages as u32,
allow_missing_func_imports,
host_functions,
engine,
})
}
fn perform_call(
data: &[u8],
instance_wrapper: Rc<InstanceWrapper>,
entrypoint: EntryPoint,
mut allocator: FreeingBumpHeapAllocator,
) -> Result<Vec<u8>> {
let (data_ptr, data_len) = inject_input_data(&instance_wrapper, &mut allocator, data)?;
let host_state = HostState::new(allocator, instance_wrapper.clone());
let ret = state_holder::with_initialized_state(&host_state, || -> Result<_> {
Ok(unpack_ptr_and_len(entrypoint.call(data_ptr, data_len)?))
});
let (output_ptr, output_len) = ret?;
let output = extract_output_data(&instance_wrapper, output_ptr, output_len)?;
Ok(output)
}
fn inject_input_data(
instance: &InstanceWrapper,
allocator: &mut FreeingBumpHeapAllocator,
data: &[u8],
) -> Result<(Pointer<u8>, WordSize)> {
let data_len = data.len() as WordSize;
let data_ptr = instance.allocate(allocator, data_len)?;
instance.write_memory_from(data_ptr, data)?;
Ok((data_ptr, data_len))
}
fn extract_output_data(
instance: &InstanceWrapper,
output_ptr: u32,
output_len: u32,
) -> Result<Vec<u8>> {
let mut output = vec![0; output_len as usize];
instance.read_memory_into(Pointer::new(output_ptr), &mut output)?;
Ok(output)
}