use crate::{
wasmtime::{context::WrappedContext, WasmtimeCaller},
TrapCode, Value, F32, F64,
};
use smallvec::SmallVec;
use wasmtime::Val;
pub fn wasmtime_syscall_handler<'a, T: 'static>(
sys_func_idx: u32,
caller: wasmtime::Caller<'a, WrappedContext<T>>,
params: &[Val],
result: &mut [Val],
) -> anyhow::Result<()> {
let mut buffer = SmallVec::<[Value; 32]>::new();
buffer.extend(params.iter().map(|x| match x {
Val::I32(value) => Value::I32(*value),
Val::I64(value) => Value::I64(*value),
Val::F32(value) => Value::F32(F32::from_bits(*value)),
Val::F64(value) => Value::F64(F64::from_bits(*value)),
_ => unreachable!("wasmtime: unsupported type: {:?}", x),
}));
buffer.extend(core::iter::repeat_n(Value::I32(0), result.len()));
let (mapped_params, mapped_result) = buffer.split_at_mut(params.len());
let syscall_handler = caller.data().syscall_handler;
let mut caller_adapter = WasmtimeCaller::<'a>::wrap_typed(caller);
let syscall_result = syscall_handler(
&mut caller_adapter,
sys_func_idx,
mapped_params,
mapped_result,
);
let should_terminate = syscall_result.map(|_| false).or_else(|trap_code| {
if trap_code == TrapCode::ExecutionHalted {
Ok(true)
} else {
Err(trap_code)
}
})?;
for (i, value) in mapped_result.iter().enumerate() {
result[i] = match value {
Value::I32(value) => Val::I32(*value),
Value::I64(value) => Val::I64(*value),
Value::F32(value) => Val::F32(value.to_bits()),
Value::F64(value) => Val::F64(value.to_bits()),
_ => unreachable!("wasmtime: unsupported type: {:?}", value),
};
}
if should_terminate {
return Err(TrapCode::ExecutionHalted.into());
}
Ok(())
}