wasmtime_environ/
key.rs

1//! Keys for identifying functions during compilation, in call graphs, and when
2//! resolving relocations.
3
4#[cfg(feature = "component-model")]
5use crate::component;
6use crate::{
7    BuiltinFunctionIndex, DefinedFuncIndex, HostCall, ModuleInternedTypeIndex, StaticModuleIndex,
8};
9use core::cmp;
10use serde_derive::{Deserialize, Serialize};
11
12/// The kind of a function that is being compiled, linked, or otherwise
13/// referenced.
14///
15/// This is like a `FuncKey` but without any payload values.
16#[repr(u32)]
17#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
18pub enum FuncKeyKind {
19    /// A Wasm-defined function.
20    DefinedWasmFunction = FuncKey::new_kind(0b000),
21
22    /// A trampoline from an array-caller to the given Wasm-callee.
23    ArrayToWasmTrampoline = FuncKey::new_kind(0b001),
24
25    /// A trampoline from a Wasm-caller to an array-callee of the given type.
26    WasmToArrayTrampoline = FuncKey::new_kind(0b010),
27
28    /// A trampoline from a Wasm-caller to the given builtin.
29    WasmToBuiltinTrampoline = FuncKey::new_kind(0b011),
30
31    /// A Pulley-specific host call.
32    PulleyHostCall = FuncKey::new_kind(0b100),
33
34    /// A Wasm-caller to component builtin trampoline.
35    #[cfg(feature = "component-model")]
36    ComponentTrampoline = FuncKey::new_kind(0b101),
37
38    /// A Wasm-caller to array-callee `resource.drop` trampoline.
39    #[cfg(feature = "component-model")]
40    ResourceDropTrampoline = FuncKey::new_kind(0b110),
41}
42
43impl From<FuncKeyKind> for u32 {
44    fn from(kind: FuncKeyKind) -> Self {
45        kind as u32
46    }
47}
48
49impl FuncKeyKind {
50    /// Get this kind's raw representation.
51    pub fn into_raw(self) -> u32 {
52        self.into()
53    }
54
55    /// Construct a `FuncKind` from its raw representation.
56    ///
57    /// Panics when given invalid raw representations.
58    pub fn from_raw(raw: u32) -> Self {
59        match raw {
60            x if x == Self::DefinedWasmFunction.into() => Self::DefinedWasmFunction,
61            x if x == Self::ArrayToWasmTrampoline.into() => Self::ArrayToWasmTrampoline,
62            x if x == Self::WasmToArrayTrampoline.into() => Self::WasmToArrayTrampoline,
63            x if x == Self::WasmToBuiltinTrampoline.into() => Self::WasmToBuiltinTrampoline,
64            x if x == Self::PulleyHostCall.into() => Self::PulleyHostCall,
65
66            #[cfg(feature = "component-model")]
67            x if x == Self::ComponentTrampoline.into() => Self::ComponentTrampoline,
68            #[cfg(feature = "component-model")]
69            x if x == Self::ResourceDropTrampoline.into() => Self::ResourceDropTrampoline,
70
71            _ => panic!("invalid raw value passed to `FuncKind::from_raw`: {raw}"),
72        }
73    }
74}
75
76/// The namespace half of a `FuncKey`.
77///
78/// This is an opaque combination of the key's kind and module index, if any.
79#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
80pub struct FuncKeyNamespace(u32);
81
82impl From<FuncKeyNamespace> for u32 {
83    fn from(ns: FuncKeyNamespace) -> Self {
84        ns.0
85    }
86}
87
88impl FuncKeyNamespace {
89    /// Get this `FuncNamespace`'s raw representation.
90    pub fn into_raw(self) -> u32 {
91        self.0
92    }
93
94    /// Construct a `FuncNamespace` from its raw representation.
95    ///
96    /// Panics when given invalid raw representations.
97    pub fn from_raw(raw: u32) -> Self {
98        match FuncKeyKind::from_raw(raw & FuncKey::KIND_MASK) {
99            FuncKeyKind::DefinedWasmFunction | FuncKeyKind::ArrayToWasmTrampoline => Self(raw),
100            FuncKeyKind::WasmToArrayTrampoline
101            | FuncKeyKind::WasmToBuiltinTrampoline
102            | FuncKeyKind::PulleyHostCall => {
103                assert_eq!(raw & FuncKey::MODULE_MASK, 0);
104                Self(raw)
105            }
106
107            #[cfg(feature = "component-model")]
108            FuncKeyKind::ComponentTrampoline => {
109                let _ = Abi::from_raw(raw & FuncKey::MODULE_MASK);
110                Self(raw)
111            }
112
113            #[cfg(feature = "component-model")]
114            FuncKeyKind::ResourceDropTrampoline => {
115                assert_eq!(raw & FuncKey::MODULE_MASK, 0);
116                Self(raw)
117            }
118        }
119    }
120
121    /// Get this `FuncNamespace`'s kind.
122    pub fn kind(&self) -> FuncKeyKind {
123        let raw = self.0 & FuncKey::KIND_MASK;
124        FuncKeyKind::from_raw(raw)
125    }
126}
127
128/// The index half of a `FuncKey`.
129#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
130pub struct FuncKeyIndex(u32);
131
132impl From<FuncKeyIndex> for u32 {
133    fn from(index: FuncKeyIndex) -> Self {
134        index.0
135    }
136}
137
138impl FuncKeyIndex {
139    /// Get this index's raw representation.
140    pub fn into_raw(self) -> u32 {
141        self.0
142    }
143
144    /// Construct a `FuncKeyIndex` from its raw representation.
145    ///
146    /// Invalid raw representations will not be caught eagerly, but will cause
147    /// panics when paired with a `FuncKeyNamespace` to create a whole
148    /// `FuncKey`.
149    pub fn from_raw(raw: u32) -> Self {
150        FuncKeyIndex(raw)
151    }
152}
153
154/// ABI signature of functions that are generated here.
155#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
156pub enum Abi {
157    /// The "wasm" ABI, or suitable to be a `wasm_call` field of a `VMFuncRef`.
158    Wasm = 0,
159    /// The "array" ABI, or suitable to be an `array_call` field.
160    Array = 1,
161}
162
163#[cfg(feature = "component-model")]
164impl Abi {
165    fn from_raw(raw: u32) -> Self {
166        match raw {
167            x if x == Self::Wasm.into_raw() => Self::Wasm,
168            x if x == Self::Array.into_raw() => Self::Array,
169            _ => panic!("invalid raw representation passed to `Abi::from_raw`: {raw}"),
170        }
171    }
172
173    fn into_raw(self) -> u32 {
174        (self as u8).into()
175    }
176}
177
178/// A sortable, comparable function key for compilation output, call graph
179/// edges, and relocations.
180#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
181pub enum FuncKey {
182    /// A Wasm-defined function.
183    DefinedWasmFunction(StaticModuleIndex, DefinedFuncIndex),
184
185    /// A trampoline from an array-caller to the given Wasm-callee.
186    ArrayToWasmTrampoline(StaticModuleIndex, DefinedFuncIndex),
187
188    /// A trampoline from a Wasm-caller to an array-callee of the given type.
189    WasmToArrayTrampoline(ModuleInternedTypeIndex),
190
191    /// A trampoline from a Wasm-caller to the given builtin.
192    WasmToBuiltinTrampoline(BuiltinFunctionIndex),
193
194    /// A Pulley-specific host call.
195    PulleyHostCall(HostCall),
196
197    /// A Wasm-caller to component builtin trampoline.
198    #[cfg(feature = "component-model")]
199    ComponentTrampoline(Abi, component::TrampolineIndex),
200
201    /// A Wasm-caller to array-callee `resource.drop` trampoline.
202    #[cfg(feature = "component-model")]
203    ResourceDropTrampoline,
204}
205
206impl Ord for FuncKey {
207    fn cmp(&self, other: &Self) -> cmp::Ordering {
208        // Make sure to sort by our raw parts, because `CompiledFunctionsTable`
209        // relies on this for its binary search tables.
210        let raw_self = self.into_raw_parts();
211        let raw_other = other.into_raw_parts();
212        raw_self.cmp(&raw_other)
213    }
214}
215
216impl PartialOrd for FuncKey {
217    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
218        Some(self.cmp(other))
219    }
220}
221
222impl FuncKey {
223    const KIND_BITS: u32 = 3;
224    const KIND_OFFSET: u32 = 32 - Self::KIND_BITS;
225    const KIND_MASK: u32 = ((1 << Self::KIND_BITS) - 1) << Self::KIND_OFFSET;
226    const MODULE_MASK: u32 = !Self::KIND_MASK;
227
228    const fn new_kind(kind: u32) -> u32 {
229        assert!(kind < (1 << Self::KIND_BITS));
230        kind << Self::KIND_OFFSET
231    }
232
233    /// Split this key into its namespace and index halves.
234    #[inline]
235    pub fn into_parts(self) -> (FuncKeyNamespace, FuncKeyIndex) {
236        let (namespace, index) = match self {
237            FuncKey::DefinedWasmFunction(module, def_func) => {
238                assert_eq!(module.as_u32() & Self::KIND_MASK, 0);
239                let namespace = FuncKeyKind::DefinedWasmFunction.into_raw() | module.as_u32();
240                let index = def_func.as_u32();
241                (namespace, index)
242            }
243            FuncKey::ArrayToWasmTrampoline(module, def_func) => {
244                assert_eq!(module.as_u32() & Self::KIND_MASK, 0);
245                let namespace = FuncKeyKind::ArrayToWasmTrampoline.into_raw() | module.as_u32();
246                let index = def_func.as_u32();
247                (namespace, index)
248            }
249            FuncKey::WasmToArrayTrampoline(ty) => {
250                let namespace = FuncKeyKind::WasmToArrayTrampoline.into_raw();
251                let index = ty.as_u32();
252                (namespace, index)
253            }
254            FuncKey::WasmToBuiltinTrampoline(builtin) => {
255                let namespace = FuncKeyKind::WasmToBuiltinTrampoline.into_raw();
256                let index = builtin.index();
257                (namespace, index)
258            }
259            FuncKey::PulleyHostCall(host_call) => {
260                let namespace = FuncKeyKind::PulleyHostCall.into_raw();
261                let index = host_call.index();
262                (namespace, index)
263            }
264
265            #[cfg(feature = "component-model")]
266            FuncKey::ComponentTrampoline(abi, trampoline) => {
267                let abi = abi.into_raw();
268                assert_eq!(abi & Self::KIND_MASK, 0);
269                let namespace = FuncKeyKind::ComponentTrampoline.into_raw() | abi;
270                let index = trampoline.as_u32();
271                (namespace, index)
272            }
273            #[cfg(feature = "component-model")]
274            FuncKey::ResourceDropTrampoline => {
275                let namespace = FuncKeyKind::ResourceDropTrampoline.into_raw();
276                let index = 0;
277                (namespace, index)
278            }
279        };
280        (FuncKeyNamespace(namespace), FuncKeyIndex(index))
281    }
282
283    /// Get this key's kind.
284    pub fn kind(self) -> FuncKeyKind {
285        self.namespace().kind()
286    }
287
288    /// Get this key's namespace.
289    pub fn namespace(self) -> FuncKeyNamespace {
290        self.into_parts().0
291    }
292
293    /// Get this key's index.
294    pub fn index(self) -> FuncKeyIndex {
295        self.into_parts().1
296    }
297
298    /// Get the raw, underlying `(namespace, index)` representation of this
299    /// compilation key.
300    ///
301    /// The resulting values should only be used for (eventually) calling
302    /// `FuncKey::from_raw_parts` or `FuncKey{Namespace,Index}::from_raw`.
303    //
304    // NB: We use two `u32`s to exactly match
305    // `cranelift_codegen::ir::UserExternalName` and ensure that we can map
306    // one-to-one between that and `FuncKey`.
307    pub fn into_raw_parts(self) -> (u32, u32) {
308        let (ns, index) = self.into_parts();
309        (ns.into_raw(), index.into_raw())
310    }
311
312    /// Create a key from its namespace and index parts.
313    ///
314    /// Should only be called with namespaces and indices that are ultimately
315    /// derived from the same key. For example, if you attempt to pair an index
316    /// and namespace that come from different keys, that may panic. If it
317    /// happens not to panic, you'll end up with a valid key that names an
318    /// arbitrary function in the given namespace, but that function probably
319    /// does not actually exist in the compilation artifact.
320    pub fn from_parts(namespace: FuncKeyNamespace, index: FuncKeyIndex) -> Self {
321        Self::from_raw_parts(namespace.into_raw(), index.into_raw())
322    }
323
324    /// Create a key from its raw, underlying representation.
325    ///
326    /// Should only be given the results of a previous call to
327    /// `FuncKey::into_raw_parts`.
328    ///
329    /// Panics when given invalid raw parts.
330    pub fn from_raw_parts(a: u32, b: u32) -> Self {
331        match FuncKeyKind::from_raw(a & Self::KIND_MASK) {
332            FuncKeyKind::DefinedWasmFunction => {
333                let module = StaticModuleIndex::from_u32(a & Self::MODULE_MASK);
334                let def_func = DefinedFuncIndex::from_u32(b);
335                Self::DefinedWasmFunction(module, def_func)
336            }
337            FuncKeyKind::ArrayToWasmTrampoline => {
338                let module = StaticModuleIndex::from_u32(a & Self::MODULE_MASK);
339                let def_func = DefinedFuncIndex::from_u32(b);
340                Self::ArrayToWasmTrampoline(module, def_func)
341            }
342            FuncKeyKind::WasmToArrayTrampoline => {
343                assert_eq!(a & Self::MODULE_MASK, 0);
344                let ty = ModuleInternedTypeIndex::from_u32(b);
345                Self::WasmToArrayTrampoline(ty)
346            }
347            FuncKeyKind::WasmToBuiltinTrampoline => {
348                assert_eq!(a & Self::MODULE_MASK, 0);
349                let builtin = BuiltinFunctionIndex::from_u32(b);
350                Self::WasmToBuiltinTrampoline(builtin)
351            }
352            FuncKeyKind::PulleyHostCall => {
353                assert_eq!(a & Self::MODULE_MASK, 0);
354                let host_call = HostCall::from_index(b);
355                Self::PulleyHostCall(host_call)
356            }
357
358            #[cfg(feature = "component-model")]
359            FuncKeyKind::ComponentTrampoline => {
360                let abi = Abi::from_raw(a & Self::MODULE_MASK);
361                let trampoline = component::TrampolineIndex::from_u32(b);
362                Self::ComponentTrampoline(abi, trampoline)
363            }
364            #[cfg(feature = "component-model")]
365            FuncKeyKind::ResourceDropTrampoline => {
366                assert_eq!(a & Self::MODULE_MASK, 0);
367                assert_eq!(b, 0);
368                Self::ResourceDropTrampoline
369            }
370        }
371    }
372
373    /// Unwrap a `FuncKey::DefinedWasmFunction` or else panic.
374    pub fn unwrap_defined_wasm_function(self) -> (StaticModuleIndex, DefinedFuncIndex) {
375        match self {
376            Self::DefinedWasmFunction(module, def_func) => (module, def_func),
377            _ => panic!("`FuncKey::unwrap_defined_wasm_function` called on {self:?}"),
378        }
379    }
380
381    /// Unwrap a `FuncKey::ArrayToWasmTrampoline` or else panic.
382    pub fn unwrap_array_to_wasm_trampoline(self) -> (StaticModuleIndex, DefinedFuncIndex) {
383        match self {
384            Self::ArrayToWasmTrampoline(module, def_func) => (module, def_func),
385            _ => panic!("`FuncKey::unwrap_array_to_wasm_trampoline` called on {self:?}"),
386        }
387    }
388
389    /// Unwrap a `FuncKey::WasmToArrayTrampoline` or else panic.
390    pub fn unwrap_wasm_to_array_trampoline(self) -> ModuleInternedTypeIndex {
391        match self {
392            Self::WasmToArrayTrampoline(ty) => ty,
393            _ => panic!("`FuncKey::unwrap_wasm_to_array_trampoline` called on {self:?}"),
394        }
395    }
396
397    /// Unwrap a `FuncKey::WasmToBuiltinTrampoline` or else panic.
398    pub fn unwrap_wasm_to_builtin_trampoline(self) -> BuiltinFunctionIndex {
399        match self {
400            Self::WasmToBuiltinTrampoline(builtin) => builtin,
401            _ => panic!("`FuncKey::unwrap_wasm_to_builtin_trampoline` called on {self:?}"),
402        }
403    }
404
405    /// Unwrap a `FuncKey::PulleyHostCall` or else panic.
406    pub fn unwrap_pulley_host_call(self) -> HostCall {
407        match self {
408            Self::PulleyHostCall(host_call) => host_call,
409            _ => panic!("`FuncKey::unwrap_pulley_host_call` called on {self:?}"),
410        }
411    }
412
413    /// Unwrap a `FuncKey::ComponentTrampoline` or else panic.
414    #[cfg(feature = "component-model")]
415    pub fn unwrap_component_trampoline(self) -> (crate::Abi, component::TrampolineIndex) {
416        match self {
417            Self::ComponentTrampoline(abi, trampoline) => (abi, trampoline),
418            _ => panic!("`FuncKey::unwrap_component_trampoline` called on {self:?}"),
419        }
420    }
421
422    /// Unwrap a `FuncKey::ResourceDropTrampoline` or else panic.
423    #[cfg(feature = "component-model")]
424    pub fn unwrap_resource_drop_trampoline(self) {
425        match self {
426            Self::ResourceDropTrampoline => {}
427            _ => panic!("`FuncKey::unwrap_resource_drop_trampoline` called on {self:?}"),
428        }
429    }
430}