tinywasm 0.11.0-beta.0

A tiny WebAssembly interpreter
Documentation
use alloc::vec::Vec;
use core::ops::Range;
use tinywasm_types::*;

use crate::func::HostFunction;

#[cfg_attr(feature = "debug", derive(Debug))]
pub(crate) struct HostFunctionInstance {
    pub(crate) type_addr: TypeAddr,
    pub(crate) func: HostFunction,
}

#[cfg_attr(feature = "debug", derive(Debug))]
pub(crate) struct WasmFunctionInstance {
    pub(crate) type_addr: TypeAddr,
    pub(crate) func: Shared<WasmFunction>,
    pub(crate) owner: ModuleInstanceId,
}

#[derive(Default)]
pub(crate) struct Functions {
    wasm: Vec<WasmFunctionInstance>,
    host: Vec<HostFunctionInstance>,
}

impl Functions {
    const HOST_TAG: u32 = 1 << 29;
    const INDEX_MASK: u32 = Self::HOST_TAG - 1;
    const MAX_ADDR: u32 = Self::HOST_TAG | Self::INDEX_MASK;

    #[inline(always)]
    pub(crate) const fn is_host(&self, addr: FuncAddr) -> bool {
        addr & Self::HOST_TAG != 0
    }

    #[inline(always)]
    fn index(addr: FuncAddr) -> usize {
        (addr & Self::INDEX_MASK) as usize
    }

    pub(crate) fn extend_wasm(
        &mut self,
        funcs: impl ExactSizeIterator<Item = (TypeAddr, Shared<WasmFunction>)>,
        owner: ModuleInstanceId,
    ) -> Range<FuncAddr> {
        let start = self.wasm.len();
        let end = start.checked_add(funcs.len()).expect("too many Wasm functions");
        assert!(end <= Self::HOST_TAG as usize, "too many Wasm functions");
        self.wasm.reserve_exact(funcs.len());
        self.wasm.extend(funcs.map(|(type_addr, func)| WasmFunctionInstance { type_addr, func, owner }));
        start as FuncAddr..end as FuncAddr
    }

    pub(crate) fn push_host(&mut self, type_addr: TypeAddr, func: HostFunction) -> FuncAddr {
        let index = self.host.len();
        assert!(index <= Self::INDEX_MASK as usize, "too many host functions");
        self.host.push(HostFunctionInstance { type_addr, func });
        Self::HOST_TAG | index as FuncAddr
    }

    #[inline]
    pub(crate) fn type_addr(&self, addr: FuncAddr) -> TypeAddr {
        if self.is_host(addr) { self.host[Self::index(addr)].type_addr } else { self.wasm[Self::index(addr)].type_addr }
    }

    pub(crate) fn contains(&self, addr: FuncAddr) -> bool {
        if addr > Self::MAX_ADDR {
            return false;
        }
        if self.is_host(addr) { Self::index(addr) < self.host.len() } else { Self::index(addr) < self.wasm.len() }
    }

    #[inline]
    pub(crate) fn wasm(&self, addr: FuncAddr) -> &WasmFunctionInstance {
        debug_assert!(!self.is_host(addr), "host address used for a Wasm function");
        &self.wasm[Self::index(addr)]
    }

    #[inline]
    pub(crate) fn host(&self, addr: FuncAddr) -> &HostFunctionInstance {
        debug_assert!(self.is_host(addr), "Wasm address used for a host function");
        &self.host[Self::index(addr)]
    }
}