revm_interpreter/
table.rs#![allow(clippy::wrong_self_convention)]
use crate::{
instructions::{control, instruction},
interpreter::Interpreter,
interpreter_types::InterpreterTypes,
Host,
};
use std::boxed::Box;
pub type Instruction<W, H> = for<'a> fn(&'a mut Interpreter<W>, &'a mut H);
pub type InstructionTable<W, H> = [Instruction<W, H>; 256];
pub type DynInstruction<W, H> = dyn Fn(&mut Interpreter<W>, &mut H);
pub type CustomInstructionTable<IT> = [IT; 256];
pub trait CustomInstruction {
type Wire: InterpreterTypes;
type Host;
fn exec(&self, interpreter: &mut Interpreter<Self::Wire>, host: &mut Self::Host);
fn from_base(instruction: Instruction<Self::Wire, Self::Host>) -> Self;
}
pub enum InstructionTables<
W: InterpreterTypes,
H: ?Sized,
CI: CustomInstruction<Host = H, Wire = W>,
> {
Plain(Box<InstructionTable<W, H>>),
Custom(Box<CustomInstructionTable<CI>>),
}
impl<WIRE, H, CI> InstructionTables<WIRE, H, CI>
where
WIRE: InterpreterTypes,
H: Host + ?Sized,
CI: CustomInstruction<Host = H, Wire = WIRE>,
{
#[inline]
pub fn insert(&mut self, opcode: u8, instruction: Instruction<WIRE, H>) {
match self {
Self::Plain(table) => table[opcode as usize] = instruction,
Self::Custom(table) => table[opcode as usize] = CI::from_base(instruction),
}
}
#[inline]
pub fn to_custom(&mut self) -> &mut CustomInstructionTable<CI> {
self.to_custom_with(|i| CI::from_base(i))
}
#[inline]
pub fn to_custom_with<F>(&mut self, f: F) -> &mut CustomInstructionTable<CI>
where
F: FnMut(Instruction<WIRE, H>) -> CI,
{
match self {
Self::Plain(_) => self.to_custom_with_slow(f),
Self::Custom(boxed) => boxed,
}
}
#[cold]
fn to_custom_with_slow<F>(&mut self, f: F) -> &mut CustomInstructionTable<CI>
where
F: FnMut(Instruction<WIRE, H>) -> CI,
{
let Self::Plain(table) = self else {
unreachable!()
};
*self = Self::Custom(Box::new(make_custom_instruction_table(table, f)));
let Self::Custom(boxed) = self else {
unreachable!()
};
boxed
}
#[inline]
pub fn get_custom(&mut self, opcode: u8) -> &mut CI {
&mut self.to_custom()[opcode as usize]
}
#[inline]
pub fn insert_custom(&mut self, opcode: u8, instruction: CI) {
*self.get_custom(opcode) = instruction;
}
#[inline]
pub fn replace_boxed(&mut self, opcode: u8, instruction: CI) -> CI {
core::mem::replace(self.get_custom(opcode), instruction)
}
}
#[inline]
pub const fn make_instruction_table<WIRE: InterpreterTypes, H: Host + ?Sized>(
) -> InstructionTable<WIRE, H> {
const {
let mut tables: InstructionTable<WIRE, H> = [control::unknown; 256];
let mut i = 0;
while i < 256 {
tables[i] = instruction::<WIRE, H>(i as u8);
i += 1;
}
tables
}
}
#[inline]
pub fn make_custom_instruction_table<W, H, FN, CI: CustomInstruction<Wire = W, Host = H>>(
table: &InstructionTable<W, H>,
mut f: FN,
) -> CustomInstructionTable<CI>
where
W: InterpreterTypes,
H: Host + ?Sized,
FN: FnMut(Instruction<W, H>) -> CI,
{
core::array::from_fn(|i| f(table[i]))
}