use wasmtime::Caller;
use pezsc_allocator::{AllocationStats, FreeingBumpHeapAllocator};
use pezsp_wasm_interface::{Pointer, WordSize};
use crate::{instance_wrapper::MemoryWrapper, runtime::StoreData, util};
pub struct HostState {
allocator: Option<FreeingBumpHeapAllocator>,
panic_message: Option<String>,
}
impl HostState {
pub fn new(allocator: FreeingBumpHeapAllocator) -> Self {
HostState { allocator: Some(allocator), panic_message: None }
}
pub fn take_panic_message(&mut self) -> Option<String> {
self.panic_message.take()
}
pub(crate) fn allocation_stats(&self) -> AllocationStats {
self.allocator.as_ref()
.expect("Allocator is always set and only unavailable when doing an allocation/deallocation; qed")
.stats()
}
}
pub(crate) struct HostContext<'a> {
pub(crate) caller: Caller<'a, StoreData>,
}
impl<'a> HostContext<'a> {
fn host_state_mut(&mut self) -> &mut HostState {
self.caller
.data_mut()
.host_state_mut()
.expect("host state is not empty when calling a function in wasm; qed")
}
}
impl<'a> pezsp_wasm_interface::FunctionContext for HostContext<'a> {
fn read_memory_into(
&self,
address: Pointer<u8>,
dest: &mut [u8],
) -> pezsp_wasm_interface::Result<()> {
util::read_memory_into(&self.caller, address, dest).map_err(|e| e.to_string())
}
fn write_memory(
&mut self,
address: Pointer<u8>,
data: &[u8],
) -> pezsp_wasm_interface::Result<()> {
util::write_memory_from(&mut self.caller, address, data).map_err(|e| e.to_string())
}
fn allocate_memory(&mut self, size: WordSize) -> pezsp_wasm_interface::Result<Pointer<u8>> {
let memory = self.caller.data().memory();
let mut allocator = self
.host_state_mut()
.allocator
.take()
.expect("allocator is not empty when calling a function in wasm; qed");
let res = allocator
.allocate(&mut MemoryWrapper(&memory, &mut self.caller), size)
.map_err(|e| e.to_string());
self.host_state_mut().allocator = Some(allocator);
res
}
fn deallocate_memory(&mut self, ptr: Pointer<u8>) -> pezsp_wasm_interface::Result<()> {
let memory = self.caller.data().memory();
let mut allocator = self
.host_state_mut()
.allocator
.take()
.expect("allocator is not empty when calling a function in wasm; qed");
let res = allocator
.deallocate(&mut MemoryWrapper(&memory, &mut self.caller), ptr)
.map_err(|e| e.to_string());
self.host_state_mut().allocator = Some(allocator);
res
}
fn register_panic_error_message(&mut self, message: &str) {
self.host_state_mut().panic_message = Some(message.to_owned());
}
}