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