1#[cfg(features = "std")]
2use crate::std::collections::HashMap as Map;
3#[cfg(not(features = "std"))]
4use crate::std::collections::BTreeMap as Map;
5
6use crate::std::num::NonZeroU32;
7use crate::std::str::FromStr;
8use crate::Instruction;
9
10pub struct UnknownInstruction;
11
12pub trait Rules {
14 fn instruction_cost(&self, instruction: &Instruction) -> Option<u32>;
20
21 fn memory_grow_cost(&self) -> Option<MemoryGrowCost>;
30}
31
32#[derive(Debug, PartialEq, Eq, Copy, Clone)]
34pub enum MemoryGrowCost {
35 Linear(NonZeroU32),
37}
38
39#[derive(Debug, PartialEq, Eq, Copy, Clone)]
40pub enum Metering {
41 Regular,
42 Forbidden,
43 Fixed(u32),
44}
45
46#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
47pub enum InstructionType {
48 Bit,
49 Add,
50 Mul,
51 Div,
52 Load,
53 Store,
54 Const,
55 FloatConst,
56 Local,
57 Global,
58 ControlFlow,
59 IntegerComparison,
60 FloatComparison,
61 Float,
62 Conversion,
63 FloatConversion,
64 Reinterpretation,
65 Unreachable,
66 Nop,
67 CurrentMemory,
68 GrowMemory,
69}
70
71impl FromStr for InstructionType {
72 type Err = UnknownInstruction;
73
74 fn from_str(s: &str) -> Result<Self, Self::Err> {
75 match s {
76 "bit" => Ok(InstructionType::Bit),
77 "add" => Ok(InstructionType::Add),
78 "mul" => Ok(InstructionType::Mul),
79 "div" => Ok(InstructionType::Div),
80 "load" => Ok(InstructionType::Load),
81 "store" => Ok(InstructionType::Store),
82 "const" => Ok(InstructionType::Const),
83 "local" => Ok(InstructionType::Local),
84 "global" => Ok(InstructionType::Global),
85 "flow" => Ok(InstructionType::ControlFlow),
86 "integer_comp" => Ok(InstructionType::IntegerComparison),
87 "float_comp" => Ok(InstructionType::FloatComparison),
88 "float" => Ok(InstructionType::Float),
89 "conversion" => Ok(InstructionType::Conversion),
90 "float_conversion" => Ok(InstructionType::FloatConversion),
91 "reinterpret" => Ok(InstructionType::Reinterpretation),
92 "unreachable" => Ok(InstructionType::Unreachable),
93 "nop" => Ok(InstructionType::Nop),
94 "current_mem" => Ok(InstructionType::CurrentMemory),
95 "grow_mem" => Ok(InstructionType::GrowMemory),
96 _ => Err(UnknownInstruction),
97 }
98 }
99}
100
101impl InstructionType {
102 pub fn op(instruction: &Instruction) -> Self {
103 use Instruction::*;
104
105 match *instruction {
106 Unreachable => InstructionType::Unreachable,
107 Nop => InstructionType::Nop,
108 Block(_) => InstructionType::ControlFlow,
109 Loop(_) => InstructionType::ControlFlow,
110 If(_) => InstructionType::ControlFlow,
111 Else => InstructionType::ControlFlow,
112 End => InstructionType::ControlFlow,
113 Br(_) => InstructionType::ControlFlow,
114 BrIf(_) => InstructionType::ControlFlow,
115 BrTable(_) => InstructionType::ControlFlow,
116 Return => InstructionType::ControlFlow,
117 Call(_) => InstructionType::ControlFlow,
118 CallIndirect(_, _) => InstructionType::ControlFlow,
119 Drop => InstructionType::ControlFlow,
120 Select => InstructionType::ControlFlow,
121
122 GetLocal(_) => InstructionType::Local,
123 SetLocal(_) => InstructionType::Local,
124 TeeLocal(_) => InstructionType::Local,
125 GetGlobal(_) => InstructionType::Global,
126 SetGlobal(_) => InstructionType::Global,
127
128 I32Load(_, _) => InstructionType::Load,
129 I64Load(_, _) => InstructionType::Load,
130 F32Load(_, _) => InstructionType::Load,
131 F64Load(_, _) => InstructionType::Load,
132 I32Load8S(_, _) => InstructionType::Load,
133 I32Load8U(_, _) => InstructionType::Load,
134 I32Load16S(_, _) => InstructionType::Load,
135 I32Load16U(_, _) => InstructionType::Load,
136 I64Load8S(_, _) => InstructionType::Load,
137 I64Load8U(_, _) => InstructionType::Load,
138 I64Load16S(_, _) => InstructionType::Load,
139 I64Load16U(_, _) => InstructionType::Load,
140 I64Load32S(_, _) => InstructionType::Load,
141 I64Load32U(_, _) => InstructionType::Load,
142
143 I32Store(_, _) => InstructionType::Store,
144 I64Store(_, _) => InstructionType::Store,
145 F32Store(_, _) => InstructionType::Store,
146 F64Store(_, _) => InstructionType::Store,
147 I32Store8(_, _) => InstructionType::Store,
148 I32Store16(_, _) => InstructionType::Store,
149 I64Store8(_, _) => InstructionType::Store,
150 I64Store16(_, _) => InstructionType::Store,
151 I64Store32(_, _) => InstructionType::Store,
152
153 CurrentMemory(_) => InstructionType::CurrentMemory,
154 GrowMemory(_) => InstructionType::GrowMemory,
155
156 I32Const(_) => InstructionType::Const,
157 I64Const(_) => InstructionType::Const,
158
159 F32Const(_) => InstructionType::FloatConst,
160 F64Const(_) => InstructionType::FloatConst,
161
162 I32Eqz => InstructionType::IntegerComparison,
163 I32Eq => InstructionType::IntegerComparison,
164 I32Ne => InstructionType::IntegerComparison,
165 I32LtS => InstructionType::IntegerComparison,
166 I32LtU => InstructionType::IntegerComparison,
167 I32GtS => InstructionType::IntegerComparison,
168 I32GtU => InstructionType::IntegerComparison,
169 I32LeS => InstructionType::IntegerComparison,
170 I32LeU => InstructionType::IntegerComparison,
171 I32GeS => InstructionType::IntegerComparison,
172 I32GeU => InstructionType::IntegerComparison,
173
174 I64Eqz => InstructionType::IntegerComparison,
175 I64Eq => InstructionType::IntegerComparison,
176 I64Ne => InstructionType::IntegerComparison,
177 I64LtS => InstructionType::IntegerComparison,
178 I64LtU => InstructionType::IntegerComparison,
179 I64GtS => InstructionType::IntegerComparison,
180 I64GtU => InstructionType::IntegerComparison,
181 I64LeS => InstructionType::IntegerComparison,
182 I64LeU => InstructionType::IntegerComparison,
183 I64GeS => InstructionType::IntegerComparison,
184 I64GeU => InstructionType::IntegerComparison,
185
186 F32Eq => InstructionType::FloatComparison,
187 F32Ne => InstructionType::FloatComparison,
188 F32Lt => InstructionType::FloatComparison,
189 F32Gt => InstructionType::FloatComparison,
190 F32Le => InstructionType::FloatComparison,
191 F32Ge => InstructionType::FloatComparison,
192
193 F64Eq => InstructionType::FloatComparison,
194 F64Ne => InstructionType::FloatComparison,
195 F64Lt => InstructionType::FloatComparison,
196 F64Gt => InstructionType::FloatComparison,
197 F64Le => InstructionType::FloatComparison,
198 F64Ge => InstructionType::FloatComparison,
199
200 I32Clz => InstructionType::Bit,
201 I32Ctz => InstructionType::Bit,
202 I32Popcnt => InstructionType::Bit,
203 I32Add => InstructionType::Add,
204 I32Sub => InstructionType::Add,
205 I32Mul => InstructionType::Mul,
206 I32DivS => InstructionType::Div,
207 I32DivU => InstructionType::Div,
208 I32RemS => InstructionType::Div,
209 I32RemU => InstructionType::Div,
210 I32And => InstructionType::Bit,
211 I32Or => InstructionType::Bit,
212 I32Xor => InstructionType::Bit,
213 I32Shl => InstructionType::Bit,
214 I32ShrS => InstructionType::Bit,
215 I32ShrU => InstructionType::Bit,
216 I32Rotl => InstructionType::Bit,
217 I32Rotr => InstructionType::Bit,
218
219 I64Clz => InstructionType::Bit,
220 I64Ctz => InstructionType::Bit,
221 I64Popcnt => InstructionType::Bit,
222 I64Add => InstructionType::Add,
223 I64Sub => InstructionType::Add,
224 I64Mul => InstructionType::Mul,
225 I64DivS => InstructionType::Div,
226 I64DivU => InstructionType::Div,
227 I64RemS => InstructionType::Div,
228 I64RemU => InstructionType::Div,
229 I64And => InstructionType::Bit,
230 I64Or => InstructionType::Bit,
231 I64Xor => InstructionType::Bit,
232 I64Shl => InstructionType::Bit,
233 I64ShrS => InstructionType::Bit,
234 I64ShrU => InstructionType::Bit,
235 I64Rotl => InstructionType::Bit,
236 I64Rotr => InstructionType::Bit,
237
238 F32Abs => InstructionType::Float,
239 F32Neg => InstructionType::Float,
240 F32Ceil => InstructionType::Float,
241 F32Floor => InstructionType::Float,
242 F32Trunc => InstructionType::Float,
243 F32Nearest => InstructionType::Float,
244 F32Sqrt => InstructionType::Float,
245 F32Add => InstructionType::Float,
246 F32Sub => InstructionType::Float,
247 F32Mul => InstructionType::Float,
248 F32Div => InstructionType::Float,
249 F32Min => InstructionType::Float,
250 F32Max => InstructionType::Float,
251 F32Copysign => InstructionType::Float,
252 F64Abs => InstructionType::Float,
253 F64Neg => InstructionType::Float,
254 F64Ceil => InstructionType::Float,
255 F64Floor => InstructionType::Float,
256 F64Trunc => InstructionType::Float,
257 F64Nearest => InstructionType::Float,
258 F64Sqrt => InstructionType::Float,
259 F64Add => InstructionType::Float,
260 F64Sub => InstructionType::Float,
261 F64Mul => InstructionType::Float,
262 F64Div => InstructionType::Float,
263 F64Min => InstructionType::Float,
264 F64Max => InstructionType::Float,
265 F64Copysign => InstructionType::Float,
266
267 I32WrapI64 => InstructionType::Conversion,
268 I64ExtendSI32 => InstructionType::Conversion,
269 I64ExtendUI32 => InstructionType::Conversion,
270
271 I32TruncSF32 => InstructionType::FloatConversion,
272 I32TruncUF32 => InstructionType::FloatConversion,
273 I32TruncSF64 => InstructionType::FloatConversion,
274 I32TruncUF64 => InstructionType::FloatConversion,
275 I64TruncSF32 => InstructionType::FloatConversion,
276 I64TruncUF32 => InstructionType::FloatConversion,
277 I64TruncSF64 => InstructionType::FloatConversion,
278 I64TruncUF64 => InstructionType::FloatConversion,
279 F32ConvertSI32 => InstructionType::FloatConversion,
280 F32ConvertUI32 => InstructionType::FloatConversion,
281 F32ConvertSI64 => InstructionType::FloatConversion,
282 F32ConvertUI64 => InstructionType::FloatConversion,
283 F32DemoteF64 => InstructionType::FloatConversion,
284 F64ConvertSI32 => InstructionType::FloatConversion,
285 F64ConvertUI32 => InstructionType::FloatConversion,
286 F64ConvertSI64 => InstructionType::FloatConversion,
287 F64ConvertUI64 => InstructionType::FloatConversion,
288 F64PromoteF32 => InstructionType::FloatConversion,
289
290 I32ReinterpretF32 => InstructionType::Reinterpretation,
291 I64ReinterpretF64 => InstructionType::Reinterpretation,
292 F32ReinterpretI32 => InstructionType::Reinterpretation,
293 F64ReinterpretI64 => InstructionType::Reinterpretation,
294 }
295 }
296}
297
298#[derive(Debug)]
299pub struct Set {
300 regular: u32,
301 entries: Map<InstructionType, Metering>,
302 grow: u32,
303}
304
305impl Default for Set {
306 fn default() -> Self {
307 Set {
308 regular: 1,
309 entries: Map::new(),
310 grow: 0,
311 }
312 }
313}
314
315impl Set {
316 pub fn new(regular: u32, entries: Map<InstructionType, Metering>) -> Self {
317 Set { regular, entries, grow: 0 }
318 }
319
320 pub fn grow_cost(&self) -> u32 {
321 self.grow
322 }
323
324 pub fn with_grow_cost(mut self, val: u32) -> Self {
325 self.grow = val;
326 self
327 }
328
329 pub fn with_forbidden_floats(mut self) -> Self {
330 self.entries.insert(InstructionType::Float, Metering::Forbidden);
331 self.entries.insert(InstructionType::FloatComparison, Metering::Forbidden);
332 self.entries.insert(InstructionType::FloatConst, Metering::Forbidden);
333 self.entries.insert(InstructionType::FloatConversion, Metering::Forbidden);
334 self
335 }
336}
337
338impl Rules for Set {
339 fn instruction_cost(&self, instruction: &Instruction) -> Option<u32> {
340 match self.entries.get(&InstructionType::op(instruction)) {
341 None | Some(Metering::Regular) => Some(self.regular),
342 Some(Metering::Fixed(val)) => Some(*val),
343 Some(Metering::Forbidden) => None,
344 }
345 }
346
347 fn memory_grow_cost(&self) -> Option<MemoryGrowCost> {
348 if let Some(val) = NonZeroU32::new(self.grow) {
349 Some(MemoryGrowCost::Linear(val))
350 } else {
351 None
352 }
353 }
354}