Skip to main content

wasmi/engine/
func_types.rs

1use super::{EngineIdx, Guarded};
2use crate::{
3    collections::arena::{ArenaIndex, DedupArena, GuardedEntity},
4    FuncType,
5};
6
7/// A raw index to a function signature entity.
8#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct DedupFuncTypeIdx(u32);
10
11impl ArenaIndex for DedupFuncTypeIdx {
12    fn into_usize(self) -> usize {
13        self.0 as _
14    }
15
16    fn from_usize(value: usize) -> Self {
17        let value = value.try_into().unwrap_or_else(|error| {
18            panic!("index {value} is out of bounds as dedup func type index: {error}")
19        });
20        Self(value)
21    }
22}
23
24/// A deduplicated Wasm [`FuncType`].
25///
26/// # Note
27///
28/// Advantages over a non-deduplicated [`FuncType`] are:
29///
30/// - Comparison for equality is as fast as an integer value comparison.
31///     - With this we can speed up indirect calls in the engine.
32/// - Requires a lot less memory footprint to be stored somewhere compared
33///   to a full fledged [`FuncType`].
34///
35/// Disadvantages compared to non-deduplicated [`FuncType`] are:
36///
37/// - Requires another indirection to acquire information such as parameter
38///   or result types of the underlying [`FuncType`].
39#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
40#[repr(transparent)]
41pub struct DedupFuncType(GuardedEntity<EngineIdx, DedupFuncTypeIdx>);
42
43impl DedupFuncType {
44    /// Creates a new function signature reference.
45    pub(super) fn from_inner(stored: GuardedEntity<EngineIdx, DedupFuncTypeIdx>) -> Self {
46        Self(stored)
47    }
48
49    /// Returns the underlying stored representation.
50    pub(super) fn into_inner(self) -> GuardedEntity<EngineIdx, DedupFuncTypeIdx> {
51        self.0
52    }
53}
54
55/// A [`FuncType`] registry that efficiently deduplicate stored function types.
56///
57/// Can also be used to later resolve deduplicated function types into their
58/// original [`FuncType`] for inspecting their parameter and result types.
59///
60/// The big advantage of deduplicated [`FuncType`] entities is that we can use
61/// this for indirect calls to speed up the signature checks since comparing
62/// deduplicated [`FuncType`] instances is as fast as comparing integer values.
63/// Also with respect to Wasmi bytecode deduplicated [`FuncType`] entities
64/// require a lot less space to be stored.
65#[derive(Debug)]
66pub struct FuncTypeRegistry {
67    /// A unique identifier for the associated engine.
68    ///
69    /// # Note
70    ///
71    /// This is used to guard against invalid entity indices.
72    engine_idx: EngineIdx,
73    /// Deduplicated function types.
74    ///
75    /// # Note
76    ///
77    /// The engine deduplicates function types to make the equality
78    /// comparison very fast. This helps to speed up indirect calls.
79    func_types: DedupArena<DedupFuncTypeIdx, FuncType>,
80}
81
82impl FuncTypeRegistry {
83    /// Creates a new [`FuncTypeRegistry`] using the given [`EngineIdx`].
84    pub(crate) fn new(engine_idx: EngineIdx) -> Self {
85        Self {
86            engine_idx,
87            func_types: DedupArena::default(),
88        }
89    }
90
91    /// Unpacks the entity and checks if it is owned by the engine.
92    ///
93    /// # Panics
94    ///
95    /// If the guarded entity is not owned by the engine.
96    fn unwrap_index<Idx>(&self, func_type: Guarded<Idx>) -> Idx
97    where
98        Idx: ArenaIndex,
99    {
100        func_type.entity_index(self.engine_idx).unwrap_or_else(|| {
101            panic!(
102                "encountered foreign entity in func type registry: {}",
103                self.engine_idx.into_usize()
104            )
105        })
106    }
107
108    /// Allocates a new function type to the engine.
109    pub(crate) fn alloc_func_type(&mut self, func_type: FuncType) -> DedupFuncType {
110        DedupFuncType::from_inner(Guarded::new(
111            self.engine_idx,
112            self.func_types.alloc(func_type),
113        ))
114    }
115
116    /// Resolves a deduplicated function type into a [`FuncType`] entity.
117    ///
118    /// # Panics
119    ///
120    /// - If the deduplicated function type is not owned by the engine.
121    /// - If the deduplicated function type cannot be resolved to its entity.
122    pub(crate) fn resolve_func_type(&self, func_type: &DedupFuncType) -> &FuncType {
123        let entity_index = self.unwrap_index(func_type.into_inner());
124        self.func_types
125            .get(entity_index)
126            .unwrap_or_else(|| panic!("failed to resolve stored function type: {entity_index:?}"))
127    }
128}