Skip to main content

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, fmt};
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)]
18#[cfg_attr(test, derive(arbitrary::Arbitrary))]
19pub enum FuncKeyKind {
20    /// A Wasm-defined function.
21    DefinedWasmFunction = FuncKey::new_kind(0b0000),
22
23    /// A trampoline from an array-caller to the given Wasm-callee.
24    ArrayToWasmTrampoline = FuncKey::new_kind(0b0001),
25
26    /// A trampoline from a Wasm-caller to an array-callee of the given type.
27    WasmToArrayTrampoline = FuncKey::new_kind(0b0010),
28
29    /// A trampoline from a Wasm-caller to the given builtin.
30    WasmToBuiltinTrampoline = FuncKey::new_kind(0b0011),
31
32    /// A trampoline from the patchable ABI to the given builtin.
33    PatchableToBuiltinTrampoline = FuncKey::new_kind(0b0100),
34
35    /// A Pulley-specific host call.
36    PulleyHostCall = FuncKey::new_kind(0b0101),
37
38    /// A Wasm-caller to component builtin trampoline.
39    #[cfg(feature = "component-model")]
40    ComponentTrampoline = FuncKey::new_kind(0b0110),
41
42    /// A Wasm-caller to array-callee `resource.drop` trampoline.
43    #[cfg(feature = "component-model")]
44    ResourceDropTrampoline = FuncKey::new_kind(0b0111),
45
46    /// A Wasmtime unsafe intrinsic function.
47    #[cfg(feature = "component-model")]
48    UnsafeIntrinsic = FuncKey::new_kind(0b1000),
49
50    /// Initialization function for a module, such as initializing "complicated"
51    /// globals and passive element segments.
52    ModuleStartup = FuncKey::new_kind(0b1001),
53}
54
55impl From<FuncKeyKind> for u32 {
56    fn from(kind: FuncKeyKind) -> Self {
57        kind as u32
58    }
59}
60
61impl FuncKeyKind {
62    /// Get this kind's raw representation.
63    pub fn into_raw(self) -> u32 {
64        self.into()
65    }
66
67    /// Construct a `FuncKind` from its raw representation.
68    ///
69    /// Panics when given invalid raw representations.
70    pub fn from_raw(raw: u32) -> Self {
71        match raw {
72            x if x == Self::DefinedWasmFunction.into() => Self::DefinedWasmFunction,
73            x if x == Self::ArrayToWasmTrampoline.into() => Self::ArrayToWasmTrampoline,
74            x if x == Self::WasmToArrayTrampoline.into() => Self::WasmToArrayTrampoline,
75            x if x == Self::WasmToBuiltinTrampoline.into() => Self::WasmToBuiltinTrampoline,
76            x if x == Self::PatchableToBuiltinTrampoline.into() => {
77                Self::PatchableToBuiltinTrampoline
78            }
79            x if x == Self::PulleyHostCall.into() => Self::PulleyHostCall,
80            x if x == Self::ModuleStartup.into() => Self::ModuleStartup,
81
82            #[cfg(feature = "component-model")]
83            x if x == Self::ComponentTrampoline.into() => Self::ComponentTrampoline,
84            #[cfg(feature = "component-model")]
85            x if x == Self::ResourceDropTrampoline.into() => Self::ResourceDropTrampoline,
86            #[cfg(feature = "component-model")]
87            x if x == Self::UnsafeIntrinsic.into() => Self::UnsafeIntrinsic,
88
89            _ => panic!("invalid raw value passed to `FuncKind::from_raw`: {raw}"),
90        }
91    }
92}
93
94/// The namespace half of a `FuncKey`.
95///
96/// This is an opaque combination of the key's kind and module index, if any.
97#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
98pub struct FuncKeyNamespace(u32);
99
100impl fmt::Debug for FuncKeyNamespace {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        struct Hex<T: fmt::LowerHex>(T);
103        impl<T: fmt::LowerHex> fmt::Debug for Hex<T> {
104            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105                write!(f, "{:#x}", self.0)
106            }
107        }
108        f.debug_struct("FuncKeyNamespace")
109            .field("raw", &Hex(self.0))
110            .field("kind", &self.kind())
111            .field("module", &self.module())
112            .finish()
113    }
114}
115
116impl From<FuncKeyNamespace> for u32 {
117    fn from(ns: FuncKeyNamespace) -> Self {
118        ns.0
119    }
120}
121
122impl FuncKeyNamespace {
123    /// Get this `FuncNamespace`'s raw representation.
124    pub fn into_raw(self) -> u32 {
125        self.0
126    }
127
128    /// Construct a `FuncNamespace` from its raw representation.
129    ///
130    /// Panics when given invalid raw representations.
131    pub fn from_raw(raw: u32) -> Self {
132        match FuncKeyKind::from_raw(raw & FuncKey::KIND_MASK) {
133            FuncKeyKind::DefinedWasmFunction
134            | FuncKeyKind::ArrayToWasmTrampoline
135            | FuncKeyKind::ModuleStartup => Self(raw),
136            FuncKeyKind::WasmToArrayTrampoline
137            | FuncKeyKind::WasmToBuiltinTrampoline
138            | FuncKeyKind::PatchableToBuiltinTrampoline
139            | FuncKeyKind::PulleyHostCall => {
140                assert_eq!(raw & FuncKey::MODULE_MASK, 0);
141                Self(raw)
142            }
143
144            #[cfg(feature = "component-model")]
145            FuncKeyKind::ComponentTrampoline => {
146                let _ = Abi::from_raw(raw & FuncKey::MODULE_MASK);
147                Self(raw)
148            }
149
150            #[cfg(feature = "component-model")]
151            FuncKeyKind::ResourceDropTrampoline => {
152                assert_eq!(raw & FuncKey::MODULE_MASK, 0);
153                Self(raw)
154            }
155
156            #[cfg(feature = "component-model")]
157            FuncKeyKind::UnsafeIntrinsic => {
158                let _ = Abi::from_raw(raw & FuncKey::MODULE_MASK);
159                Self(raw)
160            }
161        }
162    }
163
164    /// Get this `FuncNamespace`'s kind.
165    pub fn kind(&self) -> FuncKeyKind {
166        let raw = self.0 & FuncKey::KIND_MASK;
167        FuncKeyKind::from_raw(raw)
168    }
169
170    fn module(&self) -> u32 {
171        self.0 & FuncKey::MODULE_MASK
172    }
173}
174
175/// The index half of a `FuncKey`.
176#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
177pub struct FuncKeyIndex(u32);
178
179impl From<FuncKeyIndex> for u32 {
180    fn from(index: FuncKeyIndex) -> Self {
181        index.0
182    }
183}
184
185impl FuncKeyIndex {
186    /// Get this index's raw representation.
187    pub fn into_raw(self) -> u32 {
188        self.0
189    }
190
191    /// Construct a `FuncKeyIndex` from its raw representation.
192    ///
193    /// Invalid raw representations will not be caught eagerly, but will cause
194    /// panics when paired with a `FuncKeyNamespace` to create a whole
195    /// `FuncKey`.
196    pub fn from_raw(raw: u32) -> Self {
197        FuncKeyIndex(raw)
198    }
199}
200
201/// ABI signature of functions that are generated here.
202#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
203#[cfg_attr(test, derive(arbitrary::Arbitrary))]
204pub enum Abi {
205    /// The "wasm" ABI, or suitable to be a `wasm_call` field of a `VMFuncRef`.
206    Wasm = 0,
207    /// The "array" ABI, or suitable to be an `array_call` field.
208    Array = 1,
209    /// The "patchable" ABI. Signature same as Wasm ABI, but
210    /// Cranelift-level (machine-level) ABI is different (no
211    /// clobbers).
212    Patchable = 2,
213}
214
215impl Abi {
216    fn from_raw(raw: u32) -> Self {
217        match raw {
218            x if x == Self::Wasm.into_raw() => Self::Wasm,
219            x if x == Self::Array.into_raw() => Self::Array,
220            x if x == Self::Patchable.into_raw() => Self::Patchable,
221            _ => panic!("invalid raw representation passed to `Abi::from_raw`: {raw}"),
222        }
223    }
224
225    fn into_raw(self) -> u32 {
226        (self as u8).into()
227    }
228}
229
230/// A sortable, comparable function key for compilation output, call graph
231/// edges, and relocations.
232#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
233pub enum FuncKey {
234    /// A Wasm-defined function.
235    DefinedWasmFunction(StaticModuleIndex, DefinedFuncIndex),
236
237    /// A trampoline from an array-caller to the given Wasm-callee.
238    ArrayToWasmTrampoline(StaticModuleIndex, DefinedFuncIndex),
239
240    /// A trampoline from a Wasm-caller to an array-callee of the given type.
241    WasmToArrayTrampoline(ModuleInternedTypeIndex),
242
243    /// A trampoline from a Wasm-caller to the given builtin.
244    WasmToBuiltinTrampoline(BuiltinFunctionIndex),
245
246    /// A Pulley-specific host call.
247    PulleyHostCall(HostCall),
248
249    /// A trampoline from the patchable ABI to the given builtin.
250    PatchableToBuiltinTrampoline(BuiltinFunctionIndex),
251
252    /// A Wasm-caller to component builtin trampoline.
253    #[cfg(feature = "component-model")]
254    ComponentTrampoline(Abi, component::TrampolineIndex),
255
256    /// A Wasm-caller to array-callee `resource.drop` trampoline.
257    #[cfg(feature = "component-model")]
258    ResourceDropTrampoline,
259
260    /// A Wasmtime intrinsic function.
261    #[cfg(feature = "component-model")]
262    UnsafeIntrinsic(Abi, component::UnsafeIntrinsic),
263
264    /// Initialization function for a module, such as initializing "complicated"
265    /// globals and passive element segments.
266    ///
267    /// This function has the `Abi` specified and will initialize the module
268    /// specified.
269    ModuleStartup(Abi, StaticModuleIndex),
270}
271
272impl Ord for FuncKey {
273    fn cmp(&self, other: &Self) -> cmp::Ordering {
274        // Make sure to sort by our raw parts, because `CompiledFunctionsTable`
275        // relies on this for its binary search tables.
276        let raw_self = self.into_raw_parts();
277        let raw_other = other.into_raw_parts();
278        raw_self.cmp(&raw_other)
279    }
280}
281
282impl PartialOrd for FuncKey {
283    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
284        Some(self.cmp(other))
285    }
286}
287
288impl FuncKey {
289    const KIND_BITS: u32 = 4;
290    const KIND_OFFSET: u32 = 32 - Self::KIND_BITS;
291    const KIND_MASK: u32 = ((1 << Self::KIND_BITS) - 1) << Self::KIND_OFFSET;
292    const MODULE_MASK: u32 = !Self::KIND_MASK;
293
294    const fn new_kind(kind: u32) -> u32 {
295        assert!(kind < (1 << Self::KIND_BITS));
296        kind << Self::KIND_OFFSET
297    }
298
299    /// Split this key into its namespace and index halves.
300    #[inline]
301    pub fn into_parts(self) -> (FuncKeyNamespace, FuncKeyIndex) {
302        let (namespace, index) = match self {
303            FuncKey::DefinedWasmFunction(module, def_func) => {
304                assert_eq!(module.as_u32() & Self::KIND_MASK, 0);
305                let namespace = FuncKeyKind::DefinedWasmFunction.into_raw() | module.as_u32();
306                let index = def_func.as_u32();
307                (namespace, index)
308            }
309            FuncKey::ArrayToWasmTrampoline(module, def_func) => {
310                assert_eq!(module.as_u32() & Self::KIND_MASK, 0);
311                let namespace = FuncKeyKind::ArrayToWasmTrampoline.into_raw() | module.as_u32();
312                let index = def_func.as_u32();
313                (namespace, index)
314            }
315            FuncKey::WasmToArrayTrampoline(ty) => {
316                let namespace = FuncKeyKind::WasmToArrayTrampoline.into_raw();
317                let index = ty.as_u32();
318                (namespace, index)
319            }
320            FuncKey::WasmToBuiltinTrampoline(builtin) => {
321                let namespace = FuncKeyKind::WasmToBuiltinTrampoline.into_raw();
322                let index = builtin.index();
323                (namespace, index)
324            }
325            FuncKey::PatchableToBuiltinTrampoline(builtin) => {
326                let namespace = FuncKeyKind::PatchableToBuiltinTrampoline.into_raw();
327                let index = builtin.index();
328                (namespace, index)
329            }
330            FuncKey::PulleyHostCall(host_call) => {
331                let namespace = FuncKeyKind::PulleyHostCall.into_raw();
332                let index = host_call.index();
333                (namespace, index)
334            }
335
336            #[cfg(feature = "component-model")]
337            FuncKey::ComponentTrampoline(abi, trampoline) => {
338                let abi = abi.into_raw();
339                assert_eq!(abi & Self::KIND_MASK, 0);
340                let namespace = FuncKeyKind::ComponentTrampoline.into_raw() | abi;
341                let index = trampoline.as_u32();
342                (namespace, index)
343            }
344            #[cfg(feature = "component-model")]
345            FuncKey::ResourceDropTrampoline => {
346                let namespace = FuncKeyKind::ResourceDropTrampoline.into_raw();
347                let index = 0;
348                (namespace, index)
349            }
350            #[cfg(feature = "component-model")]
351            FuncKey::UnsafeIntrinsic(abi, intrinsic) => {
352                let abi = abi.into_raw();
353                assert_eq!(abi & Self::KIND_MASK, 0);
354                let namespace = FuncKeyKind::UnsafeIntrinsic.into_raw() | abi;
355                let index = intrinsic.index();
356                (namespace, index)
357            }
358
359            FuncKey::ModuleStartup(abi, module) => {
360                assert_eq!(module.as_u32() & Self::KIND_MASK, 0);
361                let namespace = FuncKeyKind::ModuleStartup.into_raw() | module.as_u32();
362                let index = abi.into_raw();
363                (namespace, index)
364            }
365        };
366        (FuncKeyNamespace(namespace), FuncKeyIndex(index))
367    }
368
369    /// Get this key's kind.
370    pub fn kind(self) -> FuncKeyKind {
371        self.namespace().kind()
372    }
373
374    /// Get this key's namespace.
375    pub fn namespace(self) -> FuncKeyNamespace {
376        self.into_parts().0
377    }
378
379    /// Get this key's index.
380    pub fn index(self) -> FuncKeyIndex {
381        self.into_parts().1
382    }
383
384    /// Get ABI of the function that this key is defining.
385    pub fn abi(self) -> Abi {
386        match self {
387            FuncKey::DefinedWasmFunction(_, _) => Abi::Wasm,
388            FuncKey::ArrayToWasmTrampoline(_, _) => Abi::Array,
389            FuncKey::WasmToArrayTrampoline(_) => Abi::Wasm,
390            FuncKey::WasmToBuiltinTrampoline(_) => Abi::Wasm,
391            FuncKey::PatchableToBuiltinTrampoline(_) => Abi::Patchable,
392            FuncKey::PulleyHostCall(_) => Abi::Wasm,
393            #[cfg(feature = "component-model")]
394            FuncKey::ComponentTrampoline(abi, _) => abi,
395            #[cfg(feature = "component-model")]
396            FuncKey::ResourceDropTrampoline => Abi::Wasm,
397            #[cfg(feature = "component-model")]
398            FuncKey::UnsafeIntrinsic(abi, _) => abi,
399            FuncKey::ModuleStartup(abi, _) => abi,
400        }
401    }
402
403    /// Get the raw, underlying `(namespace, index)` representation of this
404    /// compilation key.
405    ///
406    /// The resulting values should only be used for (eventually) calling
407    /// `FuncKey::from_raw_parts` or `FuncKey{Namespace,Index}::from_raw`.
408    //
409    // NB: We use two `u32`s to exactly match
410    // `cranelift_codegen::ir::UserExternalName` and ensure that we can map
411    // one-to-one between that and `FuncKey`.
412    pub fn into_raw_parts(self) -> (u32, u32) {
413        let (ns, index) = self.into_parts();
414        (ns.into_raw(), index.into_raw())
415    }
416
417    /// Create a key from its namespace and index parts.
418    ///
419    /// Should only be called with namespaces and indices that are ultimately
420    /// derived from the same key. For example, if you attempt to pair an index
421    /// and namespace that come from different keys, that may panic. If it
422    /// happens not to panic, you'll end up with a valid key that names an
423    /// arbitrary function in the given namespace, but that function probably
424    /// does not actually exist in the compilation artifact.
425    pub fn from_parts(namespace: FuncKeyNamespace, index: FuncKeyIndex) -> Self {
426        Self::from_raw_parts(namespace.into_raw(), index.into_raw())
427    }
428
429    /// Create a key from its raw, underlying representation.
430    ///
431    /// Should only be given the results of a previous call to
432    /// `FuncKey::into_raw_parts`.
433    ///
434    /// Panics when given invalid raw parts.
435    pub fn from_raw_parts(a: u32, b: u32) -> Self {
436        match FuncKeyKind::from_raw(a & Self::KIND_MASK) {
437            FuncKeyKind::DefinedWasmFunction => {
438                let module = StaticModuleIndex::from_u32(a & Self::MODULE_MASK);
439                let def_func = DefinedFuncIndex::from_u32(b);
440                Self::DefinedWasmFunction(module, def_func)
441            }
442            FuncKeyKind::ArrayToWasmTrampoline => {
443                let module = StaticModuleIndex::from_u32(a & Self::MODULE_MASK);
444                let def_func = DefinedFuncIndex::from_u32(b);
445                Self::ArrayToWasmTrampoline(module, def_func)
446            }
447            FuncKeyKind::WasmToArrayTrampoline => {
448                assert_eq!(a & Self::MODULE_MASK, 0);
449                let ty = ModuleInternedTypeIndex::from_u32(b);
450                Self::WasmToArrayTrampoline(ty)
451            }
452            FuncKeyKind::WasmToBuiltinTrampoline => {
453                assert_eq!(a & Self::MODULE_MASK, 0);
454                let builtin = BuiltinFunctionIndex::from_u32(b);
455                Self::WasmToBuiltinTrampoline(builtin)
456            }
457            FuncKeyKind::PatchableToBuiltinTrampoline => {
458                assert_eq!(a & Self::MODULE_MASK, 0);
459                let builtin = BuiltinFunctionIndex::from_u32(b);
460                Self::PatchableToBuiltinTrampoline(builtin)
461            }
462            FuncKeyKind::PulleyHostCall => {
463                assert_eq!(a & Self::MODULE_MASK, 0);
464                let host_call = HostCall::from_index(b);
465                Self::PulleyHostCall(host_call)
466            }
467
468            #[cfg(feature = "component-model")]
469            FuncKeyKind::ComponentTrampoline => {
470                let abi = Abi::from_raw(a & Self::MODULE_MASK);
471                let trampoline = component::TrampolineIndex::from_u32(b);
472                Self::ComponentTrampoline(abi, trampoline)
473            }
474            #[cfg(feature = "component-model")]
475            FuncKeyKind::ResourceDropTrampoline => {
476                assert_eq!(a & Self::MODULE_MASK, 0);
477                assert_eq!(b, 0);
478                Self::ResourceDropTrampoline
479            }
480            #[cfg(feature = "component-model")]
481            FuncKeyKind::UnsafeIntrinsic => {
482                let abi = Abi::from_raw(a & Self::MODULE_MASK);
483                let intrinsic = component::UnsafeIntrinsic::from_u32(b);
484                Self::UnsafeIntrinsic(abi, intrinsic)
485            }
486
487            FuncKeyKind::ModuleStartup => {
488                let module = StaticModuleIndex::from_u32(a & Self::MODULE_MASK);
489                let abi = Abi::from_raw(b);
490                Self::ModuleStartup(abi, module)
491            }
492        }
493    }
494
495    /// Create a key from a raw packed `u64` representation.
496    ///
497    /// Should only be given a value produced by `into_raw_u64()`.
498    ///
499    /// Panics when given an invalid value.
500    pub fn from_raw_u64(value: u64) -> Self {
501        let hi = u32::try_from(value >> 32).unwrap();
502        let lo = u32::try_from(value & 0xffff_ffff).unwrap();
503        FuncKey::from_raw_parts(hi, lo)
504    }
505
506    /// Produce a packed `u64` representation of this key.
507    ///
508    /// May be used with `from_raw_64()` to reconstruct this key.
509    pub fn into_raw_u64(&self) -> u64 {
510        let (hi, lo) = self.into_raw_parts();
511        (u64::from(hi) << 32) | u64::from(lo)
512    }
513
514    /// Unwrap a `FuncKey::DefinedWasmFunction` or else panic.
515    pub fn unwrap_defined_wasm_function(self) -> (StaticModuleIndex, DefinedFuncIndex) {
516        match self {
517            Self::DefinedWasmFunction(module, def_func) => (module, def_func),
518            _ => panic!("`FuncKey::unwrap_defined_wasm_function` called on {self:?}"),
519        }
520    }
521
522    /// Unwrap a `FuncKey::ArrayToWasmTrampoline` or else panic.
523    pub fn unwrap_array_to_wasm_trampoline(self) -> (StaticModuleIndex, DefinedFuncIndex) {
524        match self {
525            Self::ArrayToWasmTrampoline(module, def_func) => (module, def_func),
526            _ => panic!("`FuncKey::unwrap_array_to_wasm_trampoline` called on {self:?}"),
527        }
528    }
529
530    /// Unwrap a `FuncKey::WasmToArrayTrampoline` or else panic.
531    pub fn unwrap_wasm_to_array_trampoline(self) -> ModuleInternedTypeIndex {
532        match self {
533            Self::WasmToArrayTrampoline(ty) => ty,
534            _ => panic!("`FuncKey::unwrap_wasm_to_array_trampoline` called on {self:?}"),
535        }
536    }
537
538    /// Unwrap a `FuncKey::WasmToBuiltinTrampoline` or else panic.
539    pub fn unwrap_wasm_to_builtin_trampoline(self) -> BuiltinFunctionIndex {
540        match self {
541            Self::WasmToBuiltinTrampoline(builtin) => builtin,
542            _ => panic!("`FuncKey::unwrap_wasm_to_builtin_trampoline` called on {self:?}"),
543        }
544    }
545
546    /// Unwrap a `FuncKey::PulleyHostCall` or else panic.
547    pub fn unwrap_pulley_host_call(self) -> HostCall {
548        match self {
549            Self::PulleyHostCall(host_call) => host_call,
550            _ => panic!("`FuncKey::unwrap_pulley_host_call` called on {self:?}"),
551        }
552    }
553
554    /// Unwrap a `FuncKey::ComponentTrampoline` or else panic.
555    #[cfg(feature = "component-model")]
556    pub fn unwrap_component_trampoline(self) -> (crate::Abi, component::TrampolineIndex) {
557        match self {
558            Self::ComponentTrampoline(abi, trampoline) => (abi, trampoline),
559            _ => panic!("`FuncKey::unwrap_component_trampoline` called on {self:?}"),
560        }
561    }
562
563    /// Unwrap a `FuncKey::ResourceDropTrampoline` or else panic.
564    #[cfg(feature = "component-model")]
565    pub fn unwrap_resource_drop_trampoline(self) {
566        match self {
567            Self::ResourceDropTrampoline => {}
568            _ => panic!("`FuncKey::unwrap_resource_drop_trampoline` called on {self:?}"),
569        }
570    }
571
572    /// Is this "Store-invariant"? This allows us to execute
573    /// EngineCode directly rather than StoreCode.
574    ///
575    /// Any function that is either directly from Wasm code, or calls
576    /// it directly (not indirected through a runtime-provided
577    /// function pointer), is "store-variant": we need to use a
578    /// StoreCode-specific version of the code to hit any patching
579    /// that our specific instantiations may have (due to debugging
580    /// breakpoints, etc). Trampolines into the runtime cannot be
581    /// patched and so can use EngineCode instead. This allows for
582    /// less complex plumbing in some places where we can avoid
583    /// looking up the StoreCode (or having access to the Store).
584    pub fn is_store_invariant(&self) -> bool {
585        match self {
586            Self::DefinedWasmFunction(..)
587            | Self::ArrayToWasmTrampoline(..)
588            | Self::ModuleStartup(..) => false,
589            Self::WasmToArrayTrampoline(..)
590            | Self::WasmToBuiltinTrampoline(..)
591            | Self::PatchableToBuiltinTrampoline(..)
592            | Self::PulleyHostCall(..) => true,
593            #[cfg(feature = "component-model")]
594            Self::ComponentTrampoline(..)
595            | Self::ResourceDropTrampoline
596            | Self::UnsafeIntrinsic(..) => true,
597        }
598    }
599}