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