use {
crate::{
code::{Code, UncompiledCode},
decode::{Decode, DecodeError, Decoder},
error::Error,
exec,
instance::Instance,
into_func::IntoFunc,
stack::StackGuard,
store::{Handle, InternedFuncType, Store, StoreId, UnguardedHandle},
val::{Val, ValType},
},
std::{error, fmt, mem, sync::Arc},
};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Func(pub(crate) Handle<FuncEntity>);
impl Func {
pub fn wrap<Ts, U>(store: &mut Store, f: impl IntoFunc<Ts, U>) -> Self {
let (type_, trampoline) = f.into_func();
let type_ = store.get_or_intern_type(&type_);
Self(store.insert_func(FuncEntity::Host(HostFuncEntity::new(type_, trampoline))))
}
pub fn type_(self, store: &Store) -> &FuncType {
store.resolve_type(self.0.as_ref(store).type_())
}
pub fn call(self, store: &mut Store, args: &[Val], results: &mut [Val]) -> Result<(), Error> {
let type_ = self.type_(store);
if args.len() != type_.params().len() {
return Err(FuncError::ParamCountMismatch)?;
}
if results.len() != type_.results().len() {
return Err(FuncError::ResultCountMismatch)?;
}
for (arg, param_type) in args.iter().zip(type_.params().iter().copied()) {
if arg.type_() != param_type {
return Err(FuncError::ParamTypeMismatch)?;
}
}
exec::exec(store, self, args, results)
}
pub(crate) fn new_wasm(
store: &mut Store,
type_: InternedFuncType,
instance: Instance,
code: UncompiledCode,
) -> Self {
Self(store.insert_func(FuncEntity::Wasm(WasmFuncEntity::new(type_, instance, code))))
}
pub(crate) unsafe fn from_unguarded(func: UnguardedFunc, store_id: StoreId) -> Self {
Self(Handle::from_unguarded(func, store_id))
}
pub(crate) fn to_unguarded(self, store_id: StoreId) -> UnguardedFunc {
self.0.to_unguarded(store_id)
}
pub(crate) fn compile(self, store: &mut Store) {
let FuncEntity::Wasm(func) = self.0.as_mut(store) else {
return;
};
let instance = func.instance().clone();
let code = match mem::replace(func.code_mut(), Code::Compiling) {
Code::Uncompiled(code) => {
let engine = store.engine().clone();
engine.compile(store, self, &instance, &code)
}
Code::Compiling => panic!("function is already being compiled"),
Code::Compiled(state) => state,
};
let FuncEntity::Wasm(func) = self.0.as_mut(store) else {
unreachable!();
};
*func.code_mut() = Code::Compiled(code);
}
}
pub(crate) type UnguardedFunc = UnguardedHandle<FuncEntity>;
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct FuncType {
params_results: Arc<[ValType]>,
param_count: usize,
}
impl FuncType {
pub fn new(
params: impl IntoIterator<Item = ValType>,
results: impl IntoIterator<Item = ValType>,
) -> Self {
let mut params_results = params.into_iter().collect::<Vec<_>>();
let param_count = params_results.len();
params_results.extend(results);
Self {
params_results: params_results.into(),
param_count,
}
}
pub fn params(&self) -> &[ValType] {
&self.params_results[..self.param_count]
}
pub fn results(&self) -> &[ValType] {
&self.params_results[self.param_count..]
}
pub(crate) fn from_val_type(type_: Option<ValType>) -> FuncType {
thread_local! {
static TYPES: [FuncType; 7] = [
FuncType::new(vec![], vec![]),
FuncType::new(vec![], vec![ValType::I32]),
FuncType::new(vec![], vec![ValType::I64]),
FuncType::new(vec![], vec![ValType::F32]),
FuncType::new(vec![], vec![ValType::F64]),
FuncType::new(vec![], vec![ValType::FuncRef]),
FuncType::new(vec![], vec![ValType::ExternRef]),
];
}
TYPES.with(|types| match type_ {
None => types[0].clone(),
Some(ValType::I32) => types[1].clone(),
Some(ValType::I64) => types[2].clone(),
Some(ValType::F32) => types[3].clone(),
Some(ValType::F64) => types[4].clone(),
Some(ValType::FuncRef) => types[5].clone(),
Some(ValType::ExternRef) => types[6].clone(),
})
}
pub(crate) fn call_frame_size(&self) -> usize {
self.params().len().max(self.results().len()) + 4
}
}
impl Decode for FuncType {
fn decode(decoder: &mut Decoder<'_>) -> Result<Self, DecodeError> {
if decoder.read_byte()? != 0x60 {
return Err(DecodeError::new("malformed function type"))?;
}
let mut param_result_types: Vec<_> = decoder.decode_iter()?.collect::<Result<_, _>>()?;
let param_count = param_result_types.len();
let result_types = decoder.decode_iter()?;
param_result_types.reserve(result_types.size_hint().0);
for result_type in result_types {
param_result_types.push(result_type?);
}
Ok(Self {
params_results: param_result_types.into(),
param_count,
})
}
}
#[derive(Clone, Copy, Debug)]
pub enum FuncError {
ParamCountMismatch,
ParamTypeMismatch,
ResultCountMismatch,
}
impl fmt::Display for FuncError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::ParamCountMismatch => write!(f, "function parameter count mismatch"),
Self::ParamTypeMismatch => write!(f, "function parameter type mismatch"),
Self::ResultCountMismatch => write!(f, "function result count mismatch"),
}
}
}
impl error::Error for FuncError {}
#[derive(Debug)]
pub enum FuncEntity {
Wasm(WasmFuncEntity),
Host(HostFuncEntity),
}
impl FuncEntity {
pub(crate) fn type_(&self) -> InternedFuncType {
match self {
Self::Wasm(func) => func.type_(),
Self::Host(func) => func.type_(),
}
}
}
#[derive(Debug)]
pub(crate) struct WasmFuncEntity {
type_: InternedFuncType,
instance: Instance,
code: Code,
}
impl WasmFuncEntity {
fn new(type_: InternedFuncType, instance: Instance, code: UncompiledCode) -> WasmFuncEntity {
WasmFuncEntity {
type_,
instance,
code: Code::Uncompiled(code),
}
}
pub(crate) fn type_(&self) -> InternedFuncType {
self.type_
}
pub(crate) fn instance(&self) -> &Instance {
&self.instance
}
pub(crate) fn code(&self) -> &Code {
&self.code
}
pub(crate) fn code_mut(&mut self) -> &mut Code {
&mut self.code
}
}
#[derive(Debug)]
pub struct HostFuncEntity {
type_: InternedFuncType,
trampoline: HostFuncTrampoline,
}
impl HostFuncEntity {
pub(crate) fn new(type_: InternedFuncType, trampoline: HostFuncTrampoline) -> Self {
Self { type_, trampoline }
}
pub(crate) fn type_(&self) -> InternedFuncType {
self.type_
}
pub(crate) fn trampoline(&self) -> &HostFuncTrampoline {
&self.trampoline
}
}
#[derive(Clone)]
pub struct HostFuncTrampoline {
inner: Arc<dyn Fn(&mut Store, StackGuard) -> Result<StackGuard, Error> + Send + Sync + 'static>,
}
impl HostFuncTrampoline {
pub fn new(
inner: impl Fn(&mut Store, StackGuard) -> Result<StackGuard, Error> + Send + Sync + 'static,
) -> Self {
Self {
inner: Arc::new(inner),
}
}
pub(crate) fn call(&self, store: &mut Store, stack: StackGuard) -> Result<StackGuard, Error> {
(self.inner)(store, stack)
}
}
impl fmt::Debug for HostFuncTrampoline {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("HostFuncTrampoline").finish()
}
}