revm_interpreter/
table.rs1#![allow(clippy::wrong_self_convention)]
2
3use crate::{
4 instructions::{control, instruction},
5 interpreter::Interpreter,
6 interpreter_types::InterpreterTypes,
7 Host,
8};
9use std::boxed::Box;
10
11pub type Instruction<W, H> = for<'a> fn(&'a mut Interpreter<W>, &'a mut H);
13
14pub type InstructionTable<W, H> = [Instruction<W, H>; 256];
16
17pub type CustomInstructionTable<IT> = [IT; 256];
19
20pub trait CustomInstruction {
21 type Wire: InterpreterTypes;
22 type Host;
23
24 fn exec(&self, interpreter: &mut Interpreter<Self::Wire>, host: &mut Self::Host);
25
26 fn from_base(instruction: Instruction<Self::Wire, Self::Host>) -> Self;
27}
28
29pub enum InstructionTables<
33 W: InterpreterTypes,
34 H: ?Sized,
35 CI: CustomInstruction<Host = H, Wire = W>,
36> {
37 Plain(Box<InstructionTable<W, H>>),
38 Custom(Box<CustomInstructionTable<CI>>),
39}
40
41impl<WIRE, H, CI> InstructionTables<WIRE, H, CI>
42where
43 WIRE: InterpreterTypes,
44 H: Host + ?Sized,
45 CI: CustomInstruction<Host = H, Wire = WIRE>,
46{
47 #[inline]
49 pub fn insert(&mut self, opcode: u8, instruction: Instruction<WIRE, H>) {
50 match self {
51 Self::Plain(table) => table[opcode as usize] = instruction,
52 Self::Custom(table) => table[opcode as usize] = CI::from_base(instruction),
53 }
54 }
55
56 #[inline]
59 pub fn to_custom(&mut self) -> &mut CustomInstructionTable<CI> {
60 self.to_custom_with(|i| CI::from_base(i))
61 }
62
63 #[inline]
66 pub fn to_custom_with<F>(&mut self, f: F) -> &mut CustomInstructionTable<CI>
67 where
68 F: FnMut(Instruction<WIRE, H>) -> CI,
69 {
70 match self {
71 Self::Plain(_) => self.to_custom_with_slow(f),
72 Self::Custom(boxed) => boxed,
73 }
74 }
75
76 #[cold]
77 fn to_custom_with_slow<F>(&mut self, f: F) -> &mut CustomInstructionTable<CI>
78 where
79 F: FnMut(Instruction<WIRE, H>) -> CI,
80 {
81 let Self::Plain(table) = self else {
82 unreachable!()
83 };
84 *self = Self::Custom(Box::new(make_custom_instruction_table(table, f)));
85 let Self::Custom(boxed) = self else {
86 unreachable!()
87 };
88 boxed
89 }
90
91 #[inline]
93 pub fn get_custom(&mut self, opcode: u8) -> &mut CI {
94 &mut self.to_custom()[opcode as usize]
95 }
96
97 #[inline]
99 pub fn insert_custom(&mut self, opcode: u8, instruction: CI) {
100 *self.get_custom(opcode) = instruction;
101 }
102
103 #[inline]
106 pub fn replace_boxed(&mut self, opcode: u8, instruction: CI) -> CI {
107 core::mem::replace(self.get_custom(opcode), instruction)
108 }
109}
110
111#[inline]
113pub const fn make_instruction_table<WIRE: InterpreterTypes, H: Host + ?Sized>(
114) -> InstructionTable<WIRE, H> {
115 let mut table: InstructionTable<WIRE, H> = [control::unknown; 256];
116 let mut i = 0;
117 while i < 256 {
118 table[i] = instruction::<WIRE, H>(i as u8);
119 i += 1;
120 }
121 table
122}
123
124#[inline]
126pub fn make_custom_instruction_table<W, H, FN, CI: CustomInstruction<Wire = W, Host = H>>(
127 table: &InstructionTable<W, H>,
128 mut f: FN,
129) -> CustomInstructionTable<CI>
130where
131 W: InterpreterTypes,
132 H: Host + ?Sized,
133 FN: FnMut(Instruction<W, H>) -> CI,
134{
135 core::array::from_fn(|i| f(table[i]))
136}
137
138