Skip to content

Commit

Permalink
perf(interpreter): evaluate instruction table constructor at compile …
Browse files Browse the repository at this point in the history
…time (bluealloy#1140)

Ideally this would also return `&'static` but since `InstructionTable` is
generic over `H`, `&'static InstructionTable<H>` requires `H: 'static`, for
which I haven't yet found a work-around.
  • Loading branch information
DaniPopes authored and fubuloubu committed Apr 11, 2024
1 parent 04e17a6 commit 4d1e0b7
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 38 deletions.
69 changes: 46 additions & 23 deletions crates/interpreter/src/instructions/opcode.rs
Expand Up @@ -28,11 +28,55 @@ pub type BoxedInstructionTable<'a, H> = [BoxedInstruction<'a, H>; 256];
/// Note that `Plain` variant gives us 10-20% faster Interpreter execution.
///
/// Boxed variant can be used to wrap plain function pointer with closure.
pub enum InstructionTables<'a, H: Host> {
pub enum InstructionTables<'a, H> {
Plain(InstructionTable<H>),
Boxed(BoxedInstructionTable<'a, H>),
}

impl<H: Host> InstructionTables<'_, H> {
/// Creates a plain instruction table for the given spec.
#[inline]
pub const fn new_plain<SPEC: Spec>() -> Self {
Self::Plain(make_instruction_table::<H, SPEC>())
}
}

/// Make instruction table.
#[inline]
pub const fn make_instruction_table<H: Host, SPEC: Spec>() -> InstructionTable<H> {
// Force const-eval of the table creation, making this function trivial.
// TODO: Replace this with a `const {}` block once it is stable.
struct ConstTable<H: Host, SPEC: Spec> {
_phantom: core::marker::PhantomData<(H, SPEC)>,
}
impl<H: Host, SPEC: Spec> ConstTable<H, SPEC> {
const NEW: InstructionTable<H> = {
let mut tables: InstructionTable<H> = [control::unknown; 256];
let mut i = 0;
while i < 256 {
tables[i] = instruction::<H, SPEC>(i as u8);
i += 1;
}
tables
};
}
ConstTable::<H, SPEC>::NEW
}

/// Make boxed instruction table that calls `outer` closure for every instruction.
#[inline]
pub fn make_boxed_instruction_table<'a, H, SPEC, FN>(
table: InstructionTable<H>,
mut outer: FN,
) -> BoxedInstructionTable<'a, H>
where
H: Host,
SPEC: Spec + 'a,
FN: FnMut(Instruction<H>) -> BoxedInstruction<'a, H>,
{
core::array::from_fn(|i| outer(table[i]))
}

macro_rules! opcodes {
($($val:literal => $name:ident => $f:expr),* $(,)?) => {
// Constants for each opcode. This also takes care of duplicate names.
Expand All @@ -56,7 +100,7 @@ macro_rules! opcodes {
};

/// Returns the instruction function for the given opcode and spec.
pub fn instruction<H: Host, SPEC: Spec>(opcode: u8) -> Instruction<H> {
pub const fn instruction<H: Host, SPEC: Spec>(opcode: u8) -> Instruction<H> {
match opcode {
$($name => $f,)*
_ => control::unknown,
Expand All @@ -65,27 +109,6 @@ macro_rules! opcodes {
};
}

/// Make instruction table.
pub fn make_instruction_table<H: Host, SPEC: Spec>() -> InstructionTable<H> {
core::array::from_fn(|i| {
debug_assert!(i <= u8::MAX as usize);
instruction::<H, SPEC>(i as u8)
})
}

/// Make boxed instruction table that calls `outer` closure for every instruction.
pub fn make_boxed_instruction_table<'a, H, SPEC, FN>(
table: InstructionTable<H>,
mut outer: FN,
) -> BoxedInstructionTable<'a, H>
where
H: Host,
SPEC: Spec + 'static,
FN: FnMut(Instruction<H>) -> BoxedInstruction<'a, H>,
{
core::array::from_fn(|i| outer(table[i]))
}

// When adding new opcodes:
// 1. add the opcode to the list below; make sure it's sorted by opcode value
// 2. add its gas info in the `opcode_gas_info` function below
Expand Down
2 changes: 1 addition & 1 deletion crates/primitives/src/env/handler_cfg.rs
Expand Up @@ -41,7 +41,7 @@ impl HandlerCfg {
}
}

/// Returns true if the optimism feature is enabled and flag is set to true.
/// Returns `true` if the optimism feature is enabled and flag is set to `true`.
pub fn is_optimism(&self) -> bool {
cfg_if::cfg_if! {
if #[cfg(feature = "optimism")] {
Expand Down
2 changes: 1 addition & 1 deletion crates/primitives/src/specification.rs
Expand Up @@ -110,7 +110,7 @@ impl From<&str> for SpecId {
}
}

pub trait Spec: Sized {
pub trait Spec: Sized + 'static {
/// The specification ID.
const SPEC_ID: SpecId;

Expand Down
21 changes: 8 additions & 13 deletions crates/revm/src/handler.rs
Expand Up @@ -8,10 +8,7 @@ pub use handle_types::*;

// Includes.
use crate::{
interpreter::{
opcode::{make_instruction_table, InstructionTables},
Host,
},
interpreter::{opcode::InstructionTables, Host},
primitives::{db::Database, spec_to_generic, HandlerCfg, Spec, SpecId},
Evm,
};
Expand Down Expand Up @@ -58,14 +55,12 @@ impl<'a, EXT, DB: Database> EvmHandler<'a, EXT, DB> {
}
}
}
/// Handler for the mainnet
pub fn mainnet<SPEC: Spec + 'static>() -> Self {

/// Default handler for Ethereum mainnet.
pub fn mainnet<SPEC: Spec>() -> Self {
Self {
cfg: HandlerCfg::new(SPEC::SPEC_ID),
instruction_table: Some(InstructionTables::Plain(make_instruction_table::<
Evm<'a, EXT, DB>,
SPEC,
>())),
instruction_table: Some(InstructionTables::new_plain::<SPEC>()),
registers: Vec::new(),
validation: ValidationHandler::new::<SPEC>(),
pre_execution: PreExecutionHandler::new::<SPEC>(),
Expand All @@ -74,14 +69,14 @@ impl<'a, EXT, DB: Database> EvmHandler<'a, EXT, DB> {
}
}

/// Is optimism enabled.
/// Returns `true` if the optimism feature is enabled and flag is set to `true`.
pub fn is_optimism(&self) -> bool {
self.cfg.is_optimism()
}

/// Handler for optimism
#[cfg(feature = "optimism")]
pub fn optimism<SPEC: Spec + 'static>() -> Self {
pub fn optimism<SPEC: Spec>() -> Self {
let mut handler = Self::mainnet::<SPEC>();
handler.cfg.is_optimism = true;
handler.append_handler_register(HandleRegisters::Plain(
Expand Down Expand Up @@ -171,7 +166,7 @@ impl<'a, EXT, DB: Database> EvmHandler<'a, EXT, DB> {
}

/// Creates the Handler with Generic Spec.
pub fn create_handle_generic<SPEC: Spec + 'static>(&mut self) -> EvmHandler<'a, EXT, DB> {
pub fn create_handle_generic<SPEC: Spec>(&mut self) -> EvmHandler<'a, EXT, DB> {
let registers = core::mem::take(&mut self.registers);
let mut base_handler = Handler::mainnet::<SPEC>();
// apply all registers to default handeler and raw mainnet instruction table.
Expand Down

0 comments on commit 4d1e0b7

Please sign in to comment.