1 use crate::BuiltinFunctionIndex;
2 #[cfg(feature = "component-model")]
3 use crate::component::ComponentBuiltinFunctionIndex;
4 
5 /// Enumeration of all possible ways that wasm may execute code in the
6 /// host.
7 ///
8 /// This type is intended to be serialized into a 32-bit index (or smaller) and
9 /// is used by Pulley for example to identify how transitions from the guest to
10 /// the host are performed.
11 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
12 #[cfg_attr(test, derive(arbitrary::Arbitrary))]
13 pub enum HostCall {
14     /// An "array call" is being done which means that the wasm is calling the
15     /// host using the array calling convention (e.g. `VMArrayCallNative`).
16     ArrayCall,
17 
18     /// A builtin function, e.g. for `memory.grow`, is being called. Each
19     /// builtin has its own ABI.
20     Builtin(BuiltinFunctionIndex),
21 
22     /// A lowered component function is being called. This is done by a
23     /// trampoline generated by Cranelift and is distinct from the array calling
24     /// convention.
25     ///
26     /// This correspond to `VMLoweringCallee`.
27     #[cfg(feature = "component-model")]
28     ComponentLowerImport,
29 
30     /// A builtin function, but specifically for components. For example string
31     /// transcoders.
32     #[cfg(feature = "component-model")]
33     ComponentBuiltin(ComponentBuiltinFunctionIndex),
34 }
35 
36 impl HostCall {
37     /// Returns a 32-bit index for this hostcall.
index(&self) -> u3238     pub const fn index(&self) -> u32 {
39         match self {
40             HostCall::ArrayCall => 0,
41             HostCall::Builtin(i) => 1 + i.index(),
42             #[cfg(feature = "component-model")]
43             HostCall::ComponentLowerImport => 1 + BuiltinFunctionIndex::len(),
44             #[cfg(feature = "component-model")]
45             HostCall::ComponentBuiltin(i) => 2 + BuiltinFunctionIndex::len() + i.index(),
46         }
47     }
48 
49     /// Create a `HostCall` from the result of an earlier call to
50     /// `HostCall::index`.
from_index(index: u32) -> Self51     pub fn from_index(index: u32) -> Self {
52         let host_call = match index {
53             0 => Self::ArrayCall,
54             _ if index < 1 + BuiltinFunctionIndex::len() => {
55                 Self::Builtin(BuiltinFunctionIndex::from_u32(index - 1))
56             }
57             #[cfg(feature = "component-model")]
58             _ if index == 1 + BuiltinFunctionIndex::len() => Self::ComponentLowerImport,
59             #[cfg(feature = "component-model")]
60             _ if index < 2 + BuiltinFunctionIndex::len() + ComponentBuiltinFunctionIndex::len() => {
61                 Self::ComponentBuiltin(ComponentBuiltinFunctionIndex::from_u32(
62                     index - 2 - BuiltinFunctionIndex::len(),
63                 ))
64             }
65             _ => panic!("bad host call index: {index}"),
66         };
67         debug_assert_eq!(index, host_call.index());
68         host_call
69     }
70 }
71 
72 impl From<BuiltinFunctionIndex> for HostCall {
from(idx: BuiltinFunctionIndex) -> HostCall73     fn from(idx: BuiltinFunctionIndex) -> HostCall {
74         HostCall::Builtin(idx)
75     }
76 }
77 
78 #[cfg(feature = "component-model")]
79 impl From<ComponentBuiltinFunctionIndex> for HostCall {
from(idx: ComponentBuiltinFunctionIndex) -> HostCall80     fn from(idx: ComponentBuiltinFunctionIndex) -> HostCall {
81         HostCall::ComponentBuiltin(idx)
82     }
83 }
84