wasmi/engine/translator/
utils.rs1use crate::{
2 core::{Typed, TypedVal, UntypedVal},
3 ir::{Const16, Op, Sign},
4 Error,
5 ExternRef,
6 Func,
7 Ref,
8 ValType,
9};
10use core::num::NonZero;
11
12impl Typed for ExternRef {
13 const TY: ValType = ValType::ExternRef;
14}
15
16macro_rules! impl_typed_for {
17 ( $( $ty:ty as $ident:ident ),* $(,)? ) => {
18 $(
19 impl Typed for $ty {
20 const TY: ValType = crate::ValType::$ident;
21 }
22
23 impl From<TypedVal> for $ty {
24 fn from(typed_value: TypedVal) -> Self {
25 debug_assert!(matches!(typed_value.ty(), <$ty as Typed>::TY));
32 Self::from(typed_value.untyped())
33 }
34 }
35 )*
36 };
37}
38impl_typed_for! {
39 Ref<Func> as FuncRef,
40 Ref<ExternRef> as ExternRef,
41}
42
43pub trait WasmInteger:
49 Copy
50 + Eq
51 + Typed
52 + From<TypedVal>
53 + Into<TypedVal>
54 + From<UntypedVal>
55 + Into<UntypedVal>
56 + TryInto<Const16<Self>>
57{
58 type NonZero: Copy + Into<Self> + TryInto<Const16<Self::NonZero>> + Into<UntypedVal>;
60
61 fn non_zero(self) -> Option<Self::NonZero>;
65
66 fn is_zero(self) -> bool;
68
69 fn wrapping_neg(self) -> Self;
71}
72
73macro_rules! impl_wasm_integer {
74 ($($ty:ty),*) => {
75 $(
76 impl WasmInteger for $ty {
77 type NonZero = NonZero<Self>;
78
79 fn non_zero(self) -> Option<Self::NonZero> {
80 Self::NonZero::new(self)
81 }
82
83 fn is_zero(self) -> bool {
84 self == 0
85 }
86
87 fn wrapping_neg(self) -> Self {
88 Self::wrapping_neg(self)
89 }
90 }
91 )*
92 };
93}
94impl_wasm_integer!(i32, u32, i64, u64);
95
96pub trait WasmFloat: Typed + Copy + Into<TypedVal> + From<TypedVal> {
102 fn sign(self) -> Sign<Self>;
104}
105
106impl WasmFloat for f32 {
107 fn sign(self) -> Sign<Self> {
108 Sign::from(self)
109 }
110}
111
112impl WasmFloat for f64 {
113 fn sign(self) -> Sign<Self> {
114 Sign::from(self)
115 }
116}
117
118pub trait Wrap<T> {
120 fn wrap(self) -> T;
122}
123
124impl<T> Wrap<T> for T {
125 #[inline]
126 fn wrap(self) -> T {
127 self
128 }
129}
130
131macro_rules! impl_wrap_for {
132 ( $($from_ty:ty => $to_ty:ty),* $(,)? ) => {
133 $(
134 impl Wrap<$to_ty> for $from_ty {
135 #[inline]
136 fn wrap(self) -> $to_ty { self as _ }
137 }
138 )*
139 };
140}
141impl_wrap_for! {
142 i16 => i8,
144 i32 => i8,
145 i32 => i16,
146 i64 => i8,
147 i64 => i16,
148 i64 => i32,
149 u16 => u8,
151 u32 => u8,
152 u32 => u16,
153 u64 => u8,
154 u64 => u16,
155 u64 => u32,
156}
157
158pub trait BumpFuelConsumption {
160 fn bump_fuel_consumption(&mut self, delta: u64) -> Result<(), Error>;
167}
168
169impl BumpFuelConsumption for Op {
170 fn bump_fuel_consumption(&mut self, delta: u64) -> Result<(), Error> {
171 match self {
172 Self::ConsumeFuel { block_fuel } => block_fuel.bump_by(delta).map_err(Error::from),
173 instr => panic!("expected `Op::ConsumeFuel` but found: {instr:?}"),
174 }
175 }
176}
177
178pub trait IsInstructionParameter {
180 fn is_instruction_parameter(&self) -> bool;
182}
183
184impl IsInstructionParameter for Op {
185 #[rustfmt::skip]
186 fn is_instruction_parameter(&self) -> bool {
187 matches!(self,
188 | Self::TableIndex { .. }
189 | Self::MemoryIndex { .. }
190 | Self::DataIndex { .. }
191 | Self::ElemIndex { .. }
192 | Self::Const32 { .. }
193 | Self::I64Const32 { .. }
194 | Self::F64Const32 { .. }
195 | Self::BranchTableTarget { .. }
196 | Self::Imm16AndImm32 { .. }
197 | Self::SlotAndImm32 { .. }
198 | Self::SlotSpan { .. }
199 | Self::Slot { .. }
200 | Self::Slot2 { .. }
201 | Self::Slot3 { .. }
202 | Self::SlotList { .. }
203 | Self::CallIndirectParams { .. }
204 | Self::CallIndirectParamsImm16 { .. }
205 )
206 }
207}
208
209#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
211pub struct Instr(u32);
212
213impl From<u32> for Instr {
214 fn from(index: u32) -> Self {
215 Self(index)
216 }
217}
218
219impl From<Instr> for u32 {
220 fn from(instr: Instr) -> Self {
221 instr.0
222 }
223}
224
225impl Instr {
226 pub fn from_usize(value: usize) -> Self {
236 let Ok(index) = u32::try_from(value) else {
237 panic!("out of bounds index {value} for `Instr`")
238 };
239 Self(index)
240 }
241
242 pub fn into_usize(self) -> usize {
244 match usize::try_from(self.0) {
245 Ok(index) => index,
246 Err(error) => {
247 panic!("out of bound index {} for `Instr`: {error}", self.0)
248 }
249 }
250 }
251
252 pub fn distance(self, other: Self) -> u32 {
258 self.0.abs_diff(other.0)
259 }
260}