wasmtime_environ/component/
intrinsic.rs

1//! Wasmtime compile-time intrinsic definitions.
2
3use core::str::FromStr;
4
5use anyhow::{Result, bail};
6use serde_derive::{Deserialize, Serialize};
7
8/// Invoke a macro for each of our unsafe intrinsics.
9#[macro_export]
10macro_rules! for_each_unsafe_intrinsic {
11    ($mac:ident) => {
12        $mac! {
13            "store-data-address" => StoreDataAddress : store_data_address() -> u64;
14
15            "u8-native-load" => U8NativeLoad : u8_native_load(address: u64) -> u8;
16            "u8-native-store" => U8NativeStore : u8_native_store(address: u64, value: u8);
17
18            "u16-native-load" => U16NativeLoad : u16_native_load(address: u64) -> u16;
19            "u16-native-store" => U16NativeStore : u16_native_store(address: u64, value: u16);
20
21            "u32-native-load" => U32NativeLoad : u32_native_load(address: u64) -> u32;
22            "u32-native-store" => U32NativeStore : u32_native_store(address: u64, value: u32);
23
24            "u64-native-load" => U64NativeLoad : u64_native_load(address: u64) -> u64;
25            "u64-native-store" => U64NativeStore : u64_native_store(address: u64, value: u64);
26        }
27    };
28}
29
30macro_rules! define_unsafe_intrinsics {
31    (
32        $(
33            $symbol:expr => $variant:ident : $ctor:ident ( $( $param:ident : $param_ty:ident ),* ) $( -> $result_ty:ident )? ;
34        )*
35    ) => {
36        /// An index type for Wasmtime's intrinsics available to compile-time
37        /// builtins.
38        #[repr(u32)]
39        #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
40        pub enum UnsafeIntrinsic {
41            $(
42                #[doc = concat!("The `", $symbol, "` intrinsic.")]
43                $variant,
44            )*
45        }
46
47        impl UnsafeIntrinsic {
48            /// Returns the total number of unsafe intrinsics.
49            pub const fn len() -> u32 {
50                let mut len = 0;
51                $(
52                    let _ = Self::$variant;
53                    len += 1;
54                )*
55                len
56            }
57
58            /// Construct an `UnsafeIntrinsic` from its `u32` index.
59            ///
60            /// Panics on invalid indices.
61            pub const fn from_u32(i: u32) -> Self {
62                assert!(i < Self::len());
63                $(
64                    if i == Self::$variant.index() {
65                        return Self::$variant;
66                    }
67                )*
68                unreachable!()
69            }
70
71            /// Get this intrinsic's index.
72            pub const fn index(&self) -> u32 {
73                *self as u32
74            }
75
76            /// Get this intrinsic's name.
77            pub const fn name(&self) -> &'static str {
78                match self {
79                    $(
80                        Self::$variant => $symbol,
81                    )*
82                }
83            }
84
85            /// Get this intrinsic's parameters, as core Wasm value types.
86            pub const fn core_params(&self) -> &'static [$crate::WasmValType] {
87                match self {
88                    $(
89                        Self::$variant => &[ $( define_unsafe_intrinsics!(@core_type $param_ty) ),* ],
90                    )*
91                }
92            }
93
94            /// Get this intrinsic's results, as core Wasm value types.
95            pub const fn core_results(&self) -> &'static [$crate::WasmValType] {
96                match self {
97                    $(
98                        Self::$variant => &[ $( define_unsafe_intrinsics!(@core_type $result_ty) )? ],
99                    )*
100                }
101            }
102
103            /// Get this intrinsic's parameters, as component model interface types.
104            pub const fn component_params(&self) -> &'static [$crate::component::InterfaceType] {
105                match self {
106                    $(
107                        Self::$variant => &[ $( define_unsafe_intrinsics!(@component_type $param_ty) ),* ],
108                    )*
109                }
110            }
111
112            /// Get this intrinsic's results, as component model interface types.
113            pub const fn component_results(&self) -> &'static [$crate::component::InterfaceType] {
114                match self {
115                    $(
116                        Self::$variant => &[ $( define_unsafe_intrinsics!(@component_type $result_ty) ),* ],
117                    )*
118                }
119            }
120        }
121
122        impl FromStr for UnsafeIntrinsic {
123            type Err = anyhow::Error;
124
125            fn from_str(s: &str) -> Result<Self> {
126                match s {
127                    $(
128                        $symbol => Ok(Self::$variant),
129                    )*
130                    _ => bail!("invalid unsafe intrinsic: {s:?}"),
131                }
132            }
133        }
134    };
135
136    (@core_type u8) => { $crate::WasmValType::I32 };
137    (@core_type u16) => { $crate::WasmValType::I32 };
138    (@core_type u32) => { $crate::WasmValType::I32 };
139    (@core_type u64) => { $crate::WasmValType::I64 };
140
141    (@component_type u8) => { $crate::component::InterfaceType::U8 };
142    (@component_type u16) => { $crate::component::InterfaceType::U16 };
143    (@component_type u32) => { $crate::component::InterfaceType::U32 };
144    (@component_type u64) => { $crate::component::InterfaceType::U64 };
145}
146
147for_each_unsafe_intrinsic!(define_unsafe_intrinsics);