From 16b3f21a142dcc1e60c8e1a52c36f50c09bd0bb5 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:49:55 +0200 Subject: [PATCH] refactor: shrink OpCodeInfo and add more methods (#1307) * refactor: shrink OpCodeInfo and add more methods * review * Update crates/interpreter/src/opcode.rs * Update crates/interpreter/src/opcode.rs --- .../interpreter/src/interpreter/analysis.rs | 14 +- crates/interpreter/src/opcode.rs | 599 ++++++++++-------- crates/interpreter/src/opcode/eof_printer.rs | 12 +- .../src/bytecode/eof/types_section.rs | 4 +- crates/revm/src/inspector/eip3155.rs | 2 +- 5 files changed, 364 insertions(+), 267 deletions(-) diff --git a/crates/interpreter/src/interpreter/analysis.rs b/crates/interpreter/src/interpreter/analysis.rs index bc2d96d2f5..2b2d89f796 100644 --- a/crates/interpreter/src/interpreter/analysis.rs +++ b/crates/interpreter/src/interpreter/analysis.rs @@ -304,7 +304,7 @@ pub fn validate_eof_code( return Err(EofValidationError::UnknownOpcode); }; - if !opcode.is_eof { + if opcode.is_disabled_in_eof() { // Opcode is disabled in EOF return Err(EofValidationError::OpcodeDisabled); } @@ -324,18 +324,18 @@ pub fn validate_eof_code( // opcode after termination was not accessed. return Err(EofValidationError::InstructionNotForwardAccessed); } - is_after_termination = opcode.is_terminating_opcode; + is_after_termination = opcode.is_terminating(); // mark immediate as non-jumpable. RJUMPV is special case covered later. - if opcode.immediate_size != 0 { + if opcode.immediate_size() != 0 { // check if the opcode immediate are within the bounds of the code - if i + opcode.immediate_size as usize >= code.len() { + if i + opcode.immediate_size() as usize >= code.len() { // Malfunctional code return Err(EofValidationError::MissingImmediateBytes); } // mark immediate bytes as non-jumpable. - for imm in 1..opcode.immediate_size as usize + 1 { + for imm in 1..opcode.immediate_size() as usize + 1 { // SAFETY: immediate size is checked above. jumps[i + imm].mark_as_immediate()?; } @@ -343,7 +343,7 @@ pub fn validate_eof_code( // IO diff used to generate next instruction smallest/biggest value. let mut stack_io_diff = opcode.io_diff() as i32; // how many stack items are required for this opcode. - let mut stack_requirement = opcode.inputs as i32; + let mut stack_requirement = opcode.inputs() as i32; // additional immediate bytes for RJUMPV, it has dynamic vtable. let mut rjumpv_additional_immediates = 0; // If opcodes is RJUMP, RJUMPI or RJUMPV then this will have absolute jumpdest. @@ -534,7 +534,7 @@ pub fn validate_eof_code( } // additional immediate are from RJUMPV vtable. - i += 1 + opcode.immediate_size as usize + rjumpv_additional_immediates; + i += 1 + opcode.immediate_size() as usize + rjumpv_additional_immediates; } // last opcode should be terminating diff --git a/crates/interpreter/src/opcode.rs b/crates/interpreter/src/opcode.rs index 883ceed7ce..eb4ff27363 100644 --- a/crates/interpreter/src/opcode.rs +++ b/crates/interpreter/src/opcode.rs @@ -3,7 +3,7 @@ pub mod eof_printer; use crate::{instructions::*, primitives::Spec, Host, Interpreter}; -use core::fmt; +use core::{fmt, ptr::NonNull}; use std::boxed::Box; /// EVM opcode function signature. @@ -137,7 +137,7 @@ impl fmt::Display for OpCode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let n = self.get(); if let Some(val) = OPCODE_INFO_JUMPTABLE[n as usize] { - f.write_str(val.name) + f.write_str(val.name()) } else { write!(f, "UNKNOWN(0x{n:02X})") } @@ -186,7 +186,7 @@ impl OpCode { } } - /// Returns true if the opcode is a push instruction. + /// Returns true if the opcode is a `PUSH` instruction. #[inline] pub const fn is_push(self) -> bool { self.0 >= PUSH1 && self.0 <= PUSH32 @@ -214,9 +214,10 @@ impl OpCode { } /// Returns the opcode as a string. + #[doc(alias = "name")] #[inline] pub const fn as_str(self) -> &'static str { - self.info().name + self.info().name() } /// Returns the opcode name. @@ -229,21 +230,26 @@ impl OpCode { } } - /// Returns inputs for the given opcode. + /// Returns the number of input stack elements. + #[inline] pub const fn inputs(&self) -> u8 { - self.info().inputs + self.info().inputs() } - /// Returns outputs for the given opcode. + /// Returns the number of output stack elements. + #[inline] pub const fn outputs(&self) -> u8 { - self.info().outputs + self.info().outputs() } - /// Returns a difference between input and output. + /// Calculates the difference between the number of input and output stack elements. + #[inline] pub const fn io_diff(&self) -> i16 { self.info().io_diff() } + /// Returns the opcode information for the given opcode. + #[inline] pub const fn info_by_op(opcode: u8) -> Option { if let Some(opcode) = Self::new(opcode) { Some(opcode.info()) @@ -252,16 +258,18 @@ impl OpCode { } } + /// Returns the opcode information. #[inline] pub const fn info(&self) -> OpCodeInfo { if let Some(t) = OPCODE_INFO_JUMPTABLE[self.0 as usize] { t } else { - panic!("unreachable, all opcodes are defined") + panic!("opcode not found") } } - /// Returns a tuple of input and output. + /// Returns the number of both input and output stack elements. + /// /// Can be slightly faster that calling `inputs` and `outputs` separately. pub const fn input_output(&self) -> (u8, u8) { let info = self.info(); @@ -276,43 +284,140 @@ impl OpCode { } /// Information about opcode, such as name, and stack inputs and outputs. -#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct OpCodeInfo { - pub name: &'static str, - pub inputs: u8, - pub outputs: u8, - // TODO make this a bitfield - pub is_eof: bool, - // If the opcode is return from execution. aka STOP,RETURN, .. - pub is_terminating_opcode: bool, - /// Size of opcode with its intermediate bytes. + /// Invariant: `(name_ptr, name_len)` is a `&'static str`. It is a shorted variant of `str` as + /// the name length is always less than 256 characters. + name_ptr: NonNull, + name_len: u8, + /// Stack inputs. + inputs: u8, + /// Stack outputs. + outputs: u8, + /// Number of intermediate bytes. /// - /// RJUMPV is special case where the bytes len is depending on bytecode value, - /// for RJUMV size will be set to one byte while minimum is two. - pub immediate_size: u8, + /// RJUMPV is a special case where the bytes len depends on bytecode value, + /// for RJUMV size will be set to one byte as it is the minimum immediate size. + immediate_size: u8, + /// Used by EOF verification. All not EOF opcodes are marked false. + not_eof: bool, + /// If the opcode stops execution. aka STOP, RETURN, .. + terminating: bool, +} + +impl fmt::Debug for OpCodeInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OpCodeInfo") + .field("name", &self.name()) + .field("inputs", &self.inputs()) + .field("outputs", &self.outputs()) + .field("not_eof", &self.is_disabled_in_eof()) + .field("terminating", &self.is_terminating()) + .field("immediate_size", &self.immediate_size()) + .finish() + } } impl OpCodeInfo { + /// Creates a new opcode info with the given name and default values. pub const fn new(name: &'static str) -> Self { + assert!(name.len() < 256, "opcode name is too long"); Self { - name, + name_ptr: unsafe { NonNull::new_unchecked(name.as_ptr().cast_mut()) }, + name_len: name.len() as u8, inputs: 0, outputs: 0, - is_eof: true, - is_terminating_opcode: false, + not_eof: false, + terminating: false, immediate_size: 0, } } + /// Returns the opcode name. + #[inline] + pub const fn name(&self) -> &'static str { + // SAFETY: `self.name_*` can only be initialized with a valid `&'static str`. + unsafe { + // TODO: Use `str::from_raw_parts` when it's stable. + let slice = core::slice::from_raw_parts(self.name_ptr.as_ptr(), self.name_len as usize); + core::str::from_utf8_unchecked(slice) + } + } + + /// Calculates the difference between the number of input and output stack elements. + #[inline] pub const fn io_diff(&self) -> i16 { self.outputs as i16 - self.inputs as i16 } + + /// Returns the number of input stack elements. + #[inline] + pub const fn inputs(&self) -> u8 { + self.inputs + } + + /// Returns the number of output stack elements. + #[inline] + pub const fn outputs(&self) -> u8 { + self.outputs + } + + /// Returns whether this opcode is disabled in EOF bytecode. + #[inline] + pub const fn is_disabled_in_eof(&self) -> bool { + self.not_eof + } + + /// Returns whether this opcode terminates execution, e.g. `STOP`, `RETURN`, etc. + #[inline] + pub const fn is_terminating(&self) -> bool { + self.terminating + } + + /// Returns the size of the immediate value in bytes. + #[inline] + pub const fn immediate_size(&self) -> u8 { + self.immediate_size + } +} + +/// Sets the EOF flag to false. +#[inline] +pub const fn not_eof(mut op: OpCodeInfo) -> OpCodeInfo { + op.not_eof = true; + op +} + +/// Sets the immediate bytes number. +/// +/// RJUMPV is special case where the bytes len is depending on bytecode value, +/// for RJUMPV size will be set to one byte while minimum is two. +#[inline] +pub const fn immediate_size(mut op: OpCodeInfo, n: u8) -> OpCodeInfo { + op.immediate_size = n; + op +} + +/// Sets the terminating flag to true. +#[inline] +pub const fn terminating(mut op: OpCodeInfo) -> OpCodeInfo { + op.terminating = true; + op +} + +/// Sets the number of stack inputs and outputs. +#[inline] +pub const fn stack_io(mut op: OpCodeInfo, inputs: u8, outputs: u8) -> OpCodeInfo { + op.inputs = inputs; + op.outputs = outputs; + op } +/// Alias for the [`JUMPDEST`] opcode. pub const NOP: u8 = JUMPDEST; macro_rules! opcodes { - ($($val:literal => $name:ident => $f:expr => $($modifier:ident $(< $($modifier_num:literal),* >)?),*);* $(;)?) => { + ($($val:literal => $name:ident => $f:expr => $($modifier:ident $(( $($modifier_arg:expr),* ))?),*);* $(;)?) => { // Constants for each opcode. This also takes care of duplicate names. $( #[doc = concat!("The `", stringify!($val), "` (\"", stringify!($name),"\") opcode.")] @@ -331,9 +436,11 @@ macro_rules! opcodes { let val: u8 = $val; assert!(val == 0 || val > prev, "opcodes must be sorted in ascending order"); prev = val; - let opcode = OpCodeInfo::new(stringify!($name)); - $( let opcode = $modifier$(::< $( $modifier_num ),+ >)? (opcode);)* - map[$val] = Some(opcode); + let info = OpCodeInfo::new(stringify!($name)); + $( + let info = $modifier(info, $($($modifier_arg),*)?); + )* + map[$val] = Some(info); )* let _ = prev; map @@ -349,68 +456,45 @@ macro_rules! opcodes { }; } -pub const fn not_eof(mut opcode: OpCodeInfo) -> OpCodeInfo { - opcode.is_eof = false; - opcode -} - -/// Immediate bytes after opcode. -pub const fn imm_size(mut opcode: OpCodeInfo) -> OpCodeInfo { - opcode.immediate_size = N; - opcode -} - -pub const fn terminating(mut opcode: OpCodeInfo) -> OpCodeInfo { - opcode.is_terminating_opcode = true; - opcode -} - -pub const fn stack_io(mut opcode: OpCodeInfo) -> OpCodeInfo { - opcode.inputs = I; - opcode.outputs = O; - opcode -} - // 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 -// 3. implement the opcode in the corresponding module; +// 2. implement the opcode in the corresponding module; // the function signature must be the exact same as the others opcodes! { - 0x00 => STOP => control::stop => stack_io<0,0>, terminating; - - 0x01 => ADD => arithmetic::add => stack_io<2, 1>; - 0x02 => MUL => arithmetic::mul => stack_io<2, 1>; - 0x03 => SUB => arithmetic::sub => stack_io<2, 1>; - 0x04 => DIV => arithmetic::div => stack_io<2, 1>; - 0x05 => SDIV => arithmetic::sdiv => stack_io<2, 1>; - 0x06 => MOD => arithmetic::rem => stack_io<2, 1>; - 0x07 => SMOD => arithmetic::smod => stack_io<2, 1>; - 0x08 => ADDMOD => arithmetic::addmod => stack_io<3, 1>; - 0x09 => MULMOD => arithmetic::mulmod => stack_io<3, 1>; - 0x0A => EXP => arithmetic::exp:: => stack_io<2, 1>; - 0x0B => SIGNEXTEND => arithmetic::signextend => stack_io<2, 1>; + 0x00 => STOP => control::stop => stack_io(0, 0), terminating; + + 0x01 => ADD => arithmetic::add => stack_io(2, 1); + 0x02 => MUL => arithmetic::mul => stack_io(2, 1); + 0x03 => SUB => arithmetic::sub => stack_io(2, 1); + 0x04 => DIV => arithmetic::div => stack_io(2, 1); + 0x05 => SDIV => arithmetic::sdiv => stack_io(2, 1); + 0x06 => MOD => arithmetic::rem => stack_io(2, 1); + 0x07 => SMOD => arithmetic::smod => stack_io(2, 1); + 0x08 => ADDMOD => arithmetic::addmod => stack_io(3, 1); + 0x09 => MULMOD => arithmetic::mulmod => stack_io(3, 1); + 0x0A => EXP => arithmetic::exp:: => stack_io(2, 1); + 0x0B => SIGNEXTEND => arithmetic::signextend => stack_io(2, 1); // 0x0C // 0x0D // 0x0E // 0x0F - 0x10 => LT => bitwise::lt => stack_io<2, 1>; - 0x11 => GT => bitwise::gt => stack_io<2, 1>; - 0x12 => SLT => bitwise::slt => stack_io<2, 1>; - 0x13 => SGT => bitwise::sgt => stack_io<2, 1>; - 0x14 => EQ => bitwise::eq => stack_io<2, 1>; - 0x15 => ISZERO => bitwise::iszero => stack_io<1, 1>; - 0x16 => AND => bitwise::bitand => stack_io<2, 1>; - 0x17 => OR => bitwise::bitor => stack_io<2, 1>; - 0x18 => XOR => bitwise::bitxor => stack_io<2, 1>; - 0x19 => NOT => bitwise::not => stack_io<1, 1>; - 0x1A => BYTE => bitwise::byte => stack_io<2, 1>; - 0x1B => SHL => bitwise::shl:: => stack_io<2, 1>; - 0x1C => SHR => bitwise::shr:: => stack_io<2, 1>; - 0x1D => SAR => bitwise::sar:: => stack_io<2, 1>; + 0x10 => LT => bitwise::lt => stack_io(2, 1); + 0x11 => GT => bitwise::gt => stack_io(2, 1); + 0x12 => SLT => bitwise::slt => stack_io(2, 1); + 0x13 => SGT => bitwise::sgt => stack_io(2, 1); + 0x14 => EQ => bitwise::eq => stack_io(2, 1); + 0x15 => ISZERO => bitwise::iszero => stack_io(1, 1); + 0x16 => AND => bitwise::bitand => stack_io(2, 1); + 0x17 => OR => bitwise::bitor => stack_io(2, 1); + 0x18 => XOR => bitwise::bitxor => stack_io(2, 1); + 0x19 => NOT => bitwise::not => stack_io(1, 1); + 0x1A => BYTE => bitwise::byte => stack_io(2, 1); + 0x1B => SHL => bitwise::shl:: => stack_io(2, 1); + 0x1C => SHR => bitwise::shr:: => stack_io(2, 1); + 0x1D => SAR => bitwise::sar:: => stack_io(2, 1); // 0x1E // 0x1F - 0x20 => KECCAK256 => system::keccak256 => stack_io<2, 1>; + 0x20 => KECCAK256 => system::keccak256 => stack_io(2, 1); // 0x21 // 0x22 // 0x23 @@ -426,128 +510,128 @@ opcodes! { // 0x2D // 0x2E // 0x2F - 0x30 => ADDRESS => system::address => stack_io<0, 1>; - 0x31 => BALANCE => host::balance:: => stack_io<1, 1>; - 0x32 => ORIGIN => host_env::origin => stack_io<0, 1>; - 0x33 => CALLER => system::caller => stack_io<0, 1>; - 0x34 => CALLVALUE => system::callvalue => stack_io<0, 1>; - 0x35 => CALLDATALOAD => system::calldataload => stack_io<1, 1>; - 0x36 => CALLDATASIZE => system::calldatasize => stack_io<0, 1>; - 0x37 => CALLDATACOPY => system::calldatacopy => stack_io<3, 0>; - 0x38 => CODESIZE => system::codesize => stack_io<0, 1>, not_eof; - 0x39 => CODECOPY => system::codecopy => stack_io<3, 0>, not_eof; - - 0x3A => GASPRICE => host_env::gasprice => stack_io<0, 1>; - 0x3B => EXTCODESIZE => host::extcodesize:: => stack_io<1, 1>, not_eof; - 0x3C => EXTCODECOPY => host::extcodecopy:: => stack_io<4, 0>, not_eof; - 0x3D => RETURNDATASIZE => system::returndatasize:: => stack_io<0, 1>; - 0x3E => RETURNDATACOPY => system::returndatacopy:: => stack_io<3, 0>; - 0x3F => EXTCODEHASH => host::extcodehash:: => stack_io<1, 1>, not_eof; - 0x40 => BLOCKHASH => host::blockhash => stack_io<1, 1>; - 0x41 => COINBASE => host_env::coinbase => stack_io<0, 1>; - 0x42 => TIMESTAMP => host_env::timestamp => stack_io<0, 1>; - 0x43 => NUMBER => host_env::block_number => stack_io<0, 1>; - 0x44 => DIFFICULTY => host_env::difficulty:: => stack_io<0, 1>; - 0x45 => GASLIMIT => host_env::gaslimit => stack_io<0, 1>; - 0x46 => CHAINID => host_env::chainid:: => stack_io<0, 1>; - 0x47 => SELFBALANCE => host::selfbalance:: => stack_io<0, 1>; - 0x48 => BASEFEE => host_env::basefee:: => stack_io<0, 1>; - 0x49 => BLOBHASH => host_env::blob_hash:: => stack_io<1, 1>; - 0x4A => BLOBBASEFEE => host_env::blob_basefee:: => stack_io<0, 1>; + 0x30 => ADDRESS => system::address => stack_io(0, 1); + 0x31 => BALANCE => host::balance:: => stack_io(1, 1); + 0x32 => ORIGIN => host_env::origin => stack_io(0, 1); + 0x33 => CALLER => system::caller => stack_io(0, 1); + 0x34 => CALLVALUE => system::callvalue => stack_io(0, 1); + 0x35 => CALLDATALOAD => system::calldataload => stack_io(1, 1); + 0x36 => CALLDATASIZE => system::calldatasize => stack_io(0, 1); + 0x37 => CALLDATACOPY => system::calldatacopy => stack_io(3, 0); + 0x38 => CODESIZE => system::codesize => stack_io(0, 1), not_eof; + 0x39 => CODECOPY => system::codecopy => stack_io(3, 0), not_eof; + + 0x3A => GASPRICE => host_env::gasprice => stack_io(0, 1); + 0x3B => EXTCODESIZE => host::extcodesize:: => stack_io(1, 1), not_eof; + 0x3C => EXTCODECOPY => host::extcodecopy:: => stack_io(4, 0), not_eof; + 0x3D => RETURNDATASIZE => system::returndatasize:: => stack_io(0, 1); + 0x3E => RETURNDATACOPY => system::returndatacopy:: => stack_io(3, 0); + 0x3F => EXTCODEHASH => host::extcodehash:: => stack_io(1, 1), not_eof; + 0x40 => BLOCKHASH => host::blockhash => stack_io(1, 1); + 0x41 => COINBASE => host_env::coinbase => stack_io(0, 1); + 0x42 => TIMESTAMP => host_env::timestamp => stack_io(0, 1); + 0x43 => NUMBER => host_env::block_number => stack_io(0, 1); + 0x44 => DIFFICULTY => host_env::difficulty:: => stack_io(0, 1); + 0x45 => GASLIMIT => host_env::gaslimit => stack_io(0, 1); + 0x46 => CHAINID => host_env::chainid:: => stack_io(0, 1); + 0x47 => SELFBALANCE => host::selfbalance:: => stack_io(0, 1); + 0x48 => BASEFEE => host_env::basefee:: => stack_io(0, 1); + 0x49 => BLOBHASH => host_env::blob_hash:: => stack_io(1, 1); + 0x4A => BLOBBASEFEE => host_env::blob_basefee:: => stack_io(0, 1); // 0x4B // 0x4C // 0x4D // 0x4E // 0x4F - 0x50 => POP => stack::pop => stack_io<1, 0>; - 0x51 => MLOAD => memory::mload => stack_io<1, 1>; - 0x52 => MSTORE => memory::mstore => stack_io<2, 0>; - 0x53 => MSTORE8 => memory::mstore8 => stack_io<2, 0>; - 0x54 => SLOAD => host::sload:: => stack_io<1, 1>; - 0x55 => SSTORE => host::sstore:: => stack_io<2, 0>; - 0x56 => JUMP => control::jump => stack_io<1, 0>, not_eof; - 0x57 => JUMPI => control::jumpi => stack_io<2, 0>, not_eof; - 0x58 => PC => control::pc => stack_io<0, 1>, not_eof; - 0x59 => MSIZE => memory::msize => stack_io<0, 1>; - 0x5A => GAS => system::gas => stack_io<0, 1>, not_eof; - 0x5B => JUMPDEST => control::jumpdest_or_nop => stack_io<0, 0>; - 0x5C => TLOAD => host::tload:: => stack_io<1, 1>; - 0x5D => TSTORE => host::tstore:: => stack_io<2, 0>; - 0x5E => MCOPY => memory::mcopy:: => stack_io<3, 0>; - - 0x5F => PUSH0 => stack::push0:: => stack_io<0, 1>; - 0x60 => PUSH1 => stack::push::<1, H> => stack_io<0, 1>, imm_size<1>; - 0x61 => PUSH2 => stack::push::<2, H> => stack_io<0, 1>, imm_size<2>; - 0x62 => PUSH3 => stack::push::<3, H> => stack_io<0, 1>, imm_size<3>; - 0x63 => PUSH4 => stack::push::<4, H> => stack_io<0, 1>, imm_size<4>; - 0x64 => PUSH5 => stack::push::<5, H> => stack_io<0, 1>, imm_size<5>; - 0x65 => PUSH6 => stack::push::<6, H> => stack_io<0, 1>, imm_size<6>; - 0x66 => PUSH7 => stack::push::<7, H> => stack_io<0, 1>, imm_size<7>; - 0x67 => PUSH8 => stack::push::<8, H> => stack_io<0, 1>, imm_size<8>; - 0x68 => PUSH9 => stack::push::<9, H> => stack_io<0, 1>, imm_size<9>; - 0x69 => PUSH10 => stack::push::<10, H> => stack_io<0, 1>, imm_size<10>; - 0x6A => PUSH11 => stack::push::<11, H> => stack_io<0, 1>, imm_size<11>; - 0x6B => PUSH12 => stack::push::<12, H> => stack_io<0, 1>, imm_size<12>; - 0x6C => PUSH13 => stack::push::<13, H> => stack_io<0, 1>, imm_size<13>; - 0x6D => PUSH14 => stack::push::<14, H> => stack_io<0, 1>, imm_size<14>; - 0x6E => PUSH15 => stack::push::<15, H> => stack_io<0, 1>, imm_size<15>; - 0x6F => PUSH16 => stack::push::<16, H> => stack_io<0, 1>, imm_size<16>; - 0x70 => PUSH17 => stack::push::<17, H> => stack_io<0, 1>, imm_size<17>; - 0x71 => PUSH18 => stack::push::<18, H> => stack_io<0, 1>, imm_size<18>; - 0x72 => PUSH19 => stack::push::<19, H> => stack_io<0, 1>, imm_size<19>; - 0x73 => PUSH20 => stack::push::<20, H> => stack_io<0, 1>, imm_size<20>; - 0x74 => PUSH21 => stack::push::<21, H> => stack_io<0, 1>, imm_size<21>; - 0x75 => PUSH22 => stack::push::<22, H> => stack_io<0, 1>, imm_size<22>; - 0x76 => PUSH23 => stack::push::<23, H> => stack_io<0, 1>, imm_size<23>; - 0x77 => PUSH24 => stack::push::<24, H> => stack_io<0, 1>, imm_size<24>; - 0x78 => PUSH25 => stack::push::<25, H> => stack_io<0, 1>, imm_size<25>; - 0x79 => PUSH26 => stack::push::<26, H> => stack_io<0, 1>, imm_size<26>; - 0x7A => PUSH27 => stack::push::<27, H> => stack_io<0, 1>, imm_size<27>; - 0x7B => PUSH28 => stack::push::<28, H> => stack_io<0, 1>, imm_size<28>; - 0x7C => PUSH29 => stack::push::<29, H> => stack_io<0, 1>, imm_size<29>; - 0x7D => PUSH30 => stack::push::<30, H> => stack_io<0, 1>, imm_size<30>; - 0x7E => PUSH31 => stack::push::<31, H> => stack_io<0, 1>, imm_size<31>; - 0x7F => PUSH32 => stack::push::<32, H> => stack_io<0, 1>, imm_size<32>; - - 0x80 => DUP1 => stack::dup::<1, H> => stack_io<1, 2>; - 0x81 => DUP2 => stack::dup::<2, H> => stack_io<2, 3>; - 0x82 => DUP3 => stack::dup::<3, H> => stack_io<3, 4>; - 0x83 => DUP4 => stack::dup::<4, H> => stack_io<4, 5>; - 0x84 => DUP5 => stack::dup::<5, H> => stack_io<5, 6>; - 0x85 => DUP6 => stack::dup::<6, H> => stack_io<6, 7>; - 0x86 => DUP7 => stack::dup::<7, H> => stack_io<7, 8>; - 0x87 => DUP8 => stack::dup::<8, H> => stack_io<8, 9>; - 0x88 => DUP9 => stack::dup::<9, H> => stack_io<9, 10>; - 0x89 => DUP10 => stack::dup::<10, H> => stack_io<10, 11>; - 0x8A => DUP11 => stack::dup::<11, H> => stack_io<11, 12>; - 0x8B => DUP12 => stack::dup::<12, H> => stack_io<12, 13>; - 0x8C => DUP13 => stack::dup::<13, H> => stack_io<13, 14>; - 0x8D => DUP14 => stack::dup::<14, H> => stack_io<14, 15>; - 0x8E => DUP15 => stack::dup::<15, H> => stack_io<15, 16>; - 0x8F => DUP16 => stack::dup::<16, H> => stack_io<16, 17>; - - 0x90 => SWAP1 => stack::swap::<1, H> => stack_io<2, 2>; - 0x91 => SWAP2 => stack::swap::<2, H> => stack_io<3, 3>; - 0x92 => SWAP3 => stack::swap::<3, H> => stack_io<4, 4>; - 0x93 => SWAP4 => stack::swap::<4, H> => stack_io<5, 5>; - 0x94 => SWAP5 => stack::swap::<5, H> => stack_io<6, 6>; - 0x95 => SWAP6 => stack::swap::<6, H> => stack_io<7, 7>; - 0x96 => SWAP7 => stack::swap::<7, H> => stack_io<8, 8>; - 0x97 => SWAP8 => stack::swap::<8, H> => stack_io<9, 9>; - 0x98 => SWAP9 => stack::swap::<9, H> => stack_io<10, 10>; - 0x99 => SWAP10 => stack::swap::<10, H> => stack_io<11, 11>; - 0x9A => SWAP11 => stack::swap::<11, H> => stack_io<12, 12>; - 0x9B => SWAP12 => stack::swap::<12, H> => stack_io<13, 13>; - 0x9C => SWAP13 => stack::swap::<13, H> => stack_io<14, 14>; - 0x9D => SWAP14 => stack::swap::<14, H> => stack_io<15, 15>; - 0x9E => SWAP15 => stack::swap::<15, H> => stack_io<16, 16>; - 0x9F => SWAP16 => stack::swap::<16, H> => stack_io<17, 17>; - - 0xA0 => LOG0 => host::log::<0, H> => stack_io<2, 0>; - 0xA1 => LOG1 => host::log::<1, H> => stack_io<3, 0>; - 0xA2 => LOG2 => host::log::<2, H> => stack_io<4, 0>; - 0xA3 => LOG3 => host::log::<3, H> => stack_io<5, 0>; - 0xA4 => LOG4 => host::log::<4, H> => stack_io<6, 0>; + 0x50 => POP => stack::pop => stack_io(1, 0); + 0x51 => MLOAD => memory::mload => stack_io(1, 1); + 0x52 => MSTORE => memory::mstore => stack_io(2, 0); + 0x53 => MSTORE8 => memory::mstore8 => stack_io(2, 0); + 0x54 => SLOAD => host::sload:: => stack_io(1, 1); + 0x55 => SSTORE => host::sstore:: => stack_io(2, 0); + 0x56 => JUMP => control::jump => stack_io(1, 0), not_eof; + 0x57 => JUMPI => control::jumpi => stack_io(2, 0), not_eof; + 0x58 => PC => control::pc => stack_io(0, 1), not_eof; + 0x59 => MSIZE => memory::msize => stack_io(0, 1); + 0x5A => GAS => system::gas => stack_io(0, 1), not_eof; + 0x5B => JUMPDEST => control::jumpdest_or_nop => stack_io(0, 0); + 0x5C => TLOAD => host::tload:: => stack_io(1, 1); + 0x5D => TSTORE => host::tstore:: => stack_io(2, 0); + 0x5E => MCOPY => memory::mcopy:: => stack_io(3, 0); + + 0x5F => PUSH0 => stack::push0:: => stack_io(0, 1); + 0x60 => PUSH1 => stack::push::<1, H> => stack_io(0, 1), immediate_size(1); + 0x61 => PUSH2 => stack::push::<2, H> => stack_io(0, 1), immediate_size(2); + 0x62 => PUSH3 => stack::push::<3, H> => stack_io(0, 1), immediate_size(3); + 0x63 => PUSH4 => stack::push::<4, H> => stack_io(0, 1), immediate_size(4); + 0x64 => PUSH5 => stack::push::<5, H> => stack_io(0, 1), immediate_size(5); + 0x65 => PUSH6 => stack::push::<6, H> => stack_io(0, 1), immediate_size(6); + 0x66 => PUSH7 => stack::push::<7, H> => stack_io(0, 1), immediate_size(7); + 0x67 => PUSH8 => stack::push::<8, H> => stack_io(0, 1), immediate_size(8); + 0x68 => PUSH9 => stack::push::<9, H> => stack_io(0, 1), immediate_size(9); + 0x69 => PUSH10 => stack::push::<10, H> => stack_io(0, 1), immediate_size(10); + 0x6A => PUSH11 => stack::push::<11, H> => stack_io(0, 1), immediate_size(11); + 0x6B => PUSH12 => stack::push::<12, H> => stack_io(0, 1), immediate_size(12); + 0x6C => PUSH13 => stack::push::<13, H> => stack_io(0, 1), immediate_size(13); + 0x6D => PUSH14 => stack::push::<14, H> => stack_io(0, 1), immediate_size(14); + 0x6E => PUSH15 => stack::push::<15, H> => stack_io(0, 1), immediate_size(15); + 0x6F => PUSH16 => stack::push::<16, H> => stack_io(0, 1), immediate_size(16); + 0x70 => PUSH17 => stack::push::<17, H> => stack_io(0, 1), immediate_size(17); + 0x71 => PUSH18 => stack::push::<18, H> => stack_io(0, 1), immediate_size(18); + 0x72 => PUSH19 => stack::push::<19, H> => stack_io(0, 1), immediate_size(19); + 0x73 => PUSH20 => stack::push::<20, H> => stack_io(0, 1), immediate_size(20); + 0x74 => PUSH21 => stack::push::<21, H> => stack_io(0, 1), immediate_size(21); + 0x75 => PUSH22 => stack::push::<22, H> => stack_io(0, 1), immediate_size(22); + 0x76 => PUSH23 => stack::push::<23, H> => stack_io(0, 1), immediate_size(23); + 0x77 => PUSH24 => stack::push::<24, H> => stack_io(0, 1), immediate_size(24); + 0x78 => PUSH25 => stack::push::<25, H> => stack_io(0, 1), immediate_size(25); + 0x79 => PUSH26 => stack::push::<26, H> => stack_io(0, 1), immediate_size(26); + 0x7A => PUSH27 => stack::push::<27, H> => stack_io(0, 1), immediate_size(27); + 0x7B => PUSH28 => stack::push::<28, H> => stack_io(0, 1), immediate_size(28); + 0x7C => PUSH29 => stack::push::<29, H> => stack_io(0, 1), immediate_size(29); + 0x7D => PUSH30 => stack::push::<30, H> => stack_io(0, 1), immediate_size(30); + 0x7E => PUSH31 => stack::push::<31, H> => stack_io(0, 1), immediate_size(31); + 0x7F => PUSH32 => stack::push::<32, H> => stack_io(0, 1), immediate_size(32); + + 0x80 => DUP1 => stack::dup::<1, H> => stack_io(1, 2); + 0x81 => DUP2 => stack::dup::<2, H> => stack_io(2, 3); + 0x82 => DUP3 => stack::dup::<3, H> => stack_io(3, 4); + 0x83 => DUP4 => stack::dup::<4, H> => stack_io(4, 5); + 0x84 => DUP5 => stack::dup::<5, H> => stack_io(5, 6); + 0x85 => DUP6 => stack::dup::<6, H> => stack_io(6, 7); + 0x86 => DUP7 => stack::dup::<7, H> => stack_io(7, 8); + 0x87 => DUP8 => stack::dup::<8, H> => stack_io(8, 9); + 0x88 => DUP9 => stack::dup::<9, H> => stack_io(9, 10); + 0x89 => DUP10 => stack::dup::<10, H> => stack_io(10, 11); + 0x8A => DUP11 => stack::dup::<11, H> => stack_io(11, 12); + 0x8B => DUP12 => stack::dup::<12, H> => stack_io(12, 13); + 0x8C => DUP13 => stack::dup::<13, H> => stack_io(13, 14); + 0x8D => DUP14 => stack::dup::<14, H> => stack_io(14, 15); + 0x8E => DUP15 => stack::dup::<15, H> => stack_io(15, 16); + 0x8F => DUP16 => stack::dup::<16, H> => stack_io(16, 17); + + 0x90 => SWAP1 => stack::swap::<1, H> => stack_io(2, 2); + 0x91 => SWAP2 => stack::swap::<2, H> => stack_io(3, 3); + 0x92 => SWAP3 => stack::swap::<3, H> => stack_io(4, 4); + 0x93 => SWAP4 => stack::swap::<4, H> => stack_io(5, 5); + 0x94 => SWAP5 => stack::swap::<5, H> => stack_io(6, 6); + 0x95 => SWAP6 => stack::swap::<6, H> => stack_io(7, 7); + 0x96 => SWAP7 => stack::swap::<7, H> => stack_io(8, 8); + 0x97 => SWAP8 => stack::swap::<8, H> => stack_io(9, 9); + 0x98 => SWAP9 => stack::swap::<9, H> => stack_io(10, 10); + 0x99 => SWAP10 => stack::swap::<10, H> => stack_io(11, 11); + 0x9A => SWAP11 => stack::swap::<11, H> => stack_io(12, 12); + 0x9B => SWAP12 => stack::swap::<12, H> => stack_io(13, 13); + 0x9C => SWAP13 => stack::swap::<13, H> => stack_io(14, 14); + 0x9D => SWAP14 => stack::swap::<14, H> => stack_io(15, 15); + 0x9E => SWAP15 => stack::swap::<15, H> => stack_io(16, 16); + 0x9F => SWAP16 => stack::swap::<16, H> => stack_io(17, 17); + + 0xA0 => LOG0 => host::log::<0, H> => stack_io(2, 0); + 0xA1 => LOG1 => host::log::<1, H> => stack_io(3, 0); + 0xA2 => LOG2 => host::log::<2, H> => stack_io(4, 0); + 0xA3 => LOG3 => host::log::<3, H> => stack_io(5, 0); + 0xA4 => LOG4 => host::log::<4, H> => stack_io(6, 0); // 0xA5 // 0xA6 // 0xA7 @@ -591,10 +675,10 @@ opcodes! { // 0xCD // 0xCE // 0xCF - 0xD0 => DATALOAD => data::data_load => stack_io<1, 1>; - 0xD1 => DATALOADN => data::data_loadn => stack_io<0, 1>, imm_size<2>; - 0xD2 => DATASIZE => data::data_size => stack_io<0, 1>; - 0xD3 => DATACOPY => data::data_copy => stack_io<3, 0>; + 0xD0 => DATALOAD => data::data_load => stack_io(1, 1); + 0xD1 => DATALOADN => data::data_loadn => stack_io(0, 1), immediate_size(2); + 0xD2 => DATASIZE => data::data_size => stack_io(0, 1); + 0xD3 => DATACOPY => data::data_copy => stack_io(3, 0); // 0xD4 // 0xD5 // 0xD6 @@ -607,38 +691,38 @@ opcodes! { // 0xDD // 0xDE // 0xDF - 0xE0 => RJUMP => control::rjump => stack_io<0, 0>, imm_size<2>, terminating; - 0xE1 => RJUMPI => control::rjumpi => stack_io<1, 0>, imm_size<2>; - 0xE2 => RJUMPV => control::rjumpv => stack_io<1, 0>, imm_size<1>; - 0xE3 => CALLF => control::callf => stack_io<0, 0>, imm_size<2>; - 0xE4 => RETF => control::retf => stack_io<0, 0>, terminating; - 0xE5 => JUMPF => control::jumpf => stack_io<0, 0>, imm_size<2>, terminating; - 0xE6 => DUPN => stack::dupn => stack_io<0, 1>, imm_size<1>; - 0xE7 => SWAPN => stack::swapn => stack_io<0, 0>, imm_size<1>; - 0xE8 => EXCHANGE => stack::exchange => stack_io<0, 0>, imm_size<1>; + 0xE0 => RJUMP => control::rjump => stack_io(0, 0), immediate_size(2), terminating; + 0xE1 => RJUMPI => control::rjumpi => stack_io(1, 0), immediate_size(2); + 0xE2 => RJUMPV => control::rjumpv => stack_io(1, 0), immediate_size(1); + 0xE3 => CALLF => control::callf => stack_io(0, 0), immediate_size(2); + 0xE4 => RETF => control::retf => stack_io(0, 0), terminating; + 0xE5 => JUMPF => control::jumpf => stack_io(0, 0), immediate_size(2), terminating; + 0xE6 => DUPN => stack::dupn => stack_io(0, 1), immediate_size(1); + 0xE7 => SWAPN => stack::swapn => stack_io(0, 0), immediate_size(1); + 0xE8 => EXCHANGE => stack::exchange => stack_io(0, 0), immediate_size(1); // 0xE9 // 0xEA // 0xEB - 0xEC => EOFCREATE => contract::eofcreate:: => stack_io<4, 1>, imm_size<1>; - 0xED => TXCREATE => contract::txcreate:: => stack_io<5, 1>; - 0xEE => RETURNCONTRACT => contract::return_contract:: => stack_io<2, 0>, imm_size<1>, terminating; + 0xEC => EOFCREATE => contract::eofcreate => stack_io(4, 1), immediate_size(1); + 0xED => TXCREATE => contract::txcreate => stack_io(5, 1); + 0xEE => RETURNCONTRACT => contract::return_contract => stack_io(2, 0), immediate_size(1), terminating; // 0xEF - 0xF0 => CREATE => contract::create:: => stack_io<3, 1>, not_eof; - 0xF1 => CALL => contract::call:: => stack_io<7, 1>, not_eof; - 0xF2 => CALLCODE => contract::call_code:: => stack_io<7, 1>, not_eof; - 0xF3 => RETURN => control::ret => stack_io<2, 0>, terminating; - 0xF4 => DELEGATECALL => contract::delegate_call:: => stack_io<6, 1>, not_eof; - 0xF5 => CREATE2 => contract::create:: => stack_io<4, 1>, not_eof; + 0xF0 => CREATE => contract::create:: => stack_io(3, 1), not_eof; + 0xF1 => CALL => contract::call:: => stack_io(7, 1), not_eof; + 0xF2 => CALLCODE => contract::call_code:: => stack_io(7, 1), not_eof; + 0xF3 => RETURN => control::ret => stack_io(2, 0), terminating; + 0xF4 => DELEGATECALL => contract::delegate_call:: => stack_io(6, 1), not_eof; + 0xF5 => CREATE2 => contract::create:: => stack_io(4, 1), not_eof; // 0xF6 - 0xF7 => RETURNDATALOAD => system::returndataload:: => stack_io<1, 1>; - 0xF8 => EXTCALL => contract::extcall:: => stack_io<4, 1>; - 0xF9 => EXFCALL => contract::extdcall:: => stack_io<3, 1>; - 0xFA => STATICCALL => contract::static_call:: => stack_io<6, 1>, not_eof; - 0xFB => EXTSCALL => contract::extscall:: => stack_io<3, 1>; + 0xF7 => RETURNDATALOAD => system::returndataload => stack_io(1, 1); + 0xF8 => EXTCALL => contract::extcall:: => stack_io(4, 1); + 0xF9 => EXFCALL => contract::extdcall:: => stack_io(3, 1); + 0xFA => STATICCALL => contract::static_call:: => stack_io(6, 1), not_eof; + 0xFB => EXTSCALL => contract::extscall => stack_io(3, 1); // 0xFC - 0xFD => REVERT => control::revert:: => stack_io<2, 0>, terminating; - 0xFE => INVALID => control::invalid => stack_io<0, 0>, terminating; - 0xFF => SELFDESTRUCT => host::selfdestruct:: => stack_io<1, 0>, not_eof, terminating; + 0xFD => REVERT => control::revert:: => stack_io(2, 0), terminating; + 0xFE => INVALID => control::invalid => stack_io(0, 0), terminating; + 0xFF => SELFDESTRUCT => host::selfdestruct:: => stack_io(1, 0), not_eof, terminating; } #[cfg(test)] @@ -655,34 +739,49 @@ mod tests { assert_eq!(opcode.get(), 0x00); } - const REJECTED_IN_EOF: &[u8] = &[ - 0x38, 0x39, 0x3b, 0x3c, 0x3f, 0x5a, 0xf1, 0xf2, 0xf4, 0xfa, 0xff, - ]; - #[test] fn test_eof_disable() { - for opcode in REJECTED_IN_EOF.iter() { + const REJECTED_IN_EOF: &[u8] = &[ + 0x38, 0x39, 0x3b, 0x3c, 0x3f, 0x5a, 0xf1, 0xf2, 0xf4, 0xfa, 0xff, + ]; + + for opcode in REJECTED_IN_EOF { let opcode = OpCode::new(*opcode).unwrap(); - assert!(!opcode.info().is_eof, "Opcode {:?} is not EOF", opcode); + assert!( + opcode.info().is_disabled_in_eof(), + "not disabled in EOF: {opcode:#?}", + ); } } #[test] - fn test_imm_size() { - let mut opcodes = [0u8; 256]; + fn test_immediate_size() { + let mut expected = [0u8; 256]; // PUSH opcodes - for push in PUSH1..PUSH32 { - opcodes[push as usize] = push - PUSH1 + 1; + for push in PUSH1..=PUSH32 { + expected[push as usize] = push - PUSH1 + 1; + } + expected[DATALOADN as usize] = 2; + expected[RJUMP as usize] = 2; + expected[RJUMPI as usize] = 2; + expected[RJUMPV as usize] = 1; + expected[CALLF as usize] = 2; + expected[JUMPF as usize] = 2; + expected[DUPN as usize] = 1; + expected[SWAPN as usize] = 1; + expected[EXCHANGE as usize] = 1; + expected[EOFCREATE as usize] = 1; + expected[RETURNCONTRACT as usize] = 1; + + for (i, opcode) in OPCODE_INFO_JUMPTABLE.iter().enumerate() { + if let Some(opcode) = opcode { + assert_eq!( + opcode.immediate_size(), + expected[i], + "immediate_size check failed for {opcode:#?}", + ); + } } - opcodes[DATALOADN as usize] = 2; - opcodes[RJUMP as usize] = 2; - opcodes[RJUMPI as usize] = 2; - opcodes[RJUMPV as usize] = 2; - opcodes[CALLF as usize] = 2; - opcodes[JUMPF as usize] = 2; - opcodes[DUPN as usize] = 1; - opcodes[SWAPN as usize] = 1; - opcodes[EXCHANGE as usize] = 1; } #[test] @@ -733,9 +832,7 @@ mod tests { for (i, opcode) in OPCODE_INFO_JUMPTABLE.into_iter().enumerate() { assert_eq!( - opcode - .map(|opcode| opcode.is_terminating_opcode) - .unwrap_or_default(), + opcode.map(|opcode| opcode.terminating).unwrap_or_default(), opcodes[i], "Opcode {:?} terminating chack failed.", opcode diff --git a/crates/interpreter/src/opcode/eof_printer.rs b/crates/interpreter/src/opcode/eof_printer.rs index d593d9a7fa..dc22688222 100644 --- a/crates/interpreter/src/opcode/eof_printer.rs +++ b/crates/interpreter/src/opcode/eof_printer.rs @@ -16,19 +16,19 @@ pub fn print_eof_code(code: &[u8]) { continue; }; - if opcode.immediate_size != 0 { + if opcode.immediate_size() != 0 { // check if the opcode immediate are within the bounds of the code - if i + opcode.immediate_size as usize >= code.len() { + if i + opcode.immediate_size() as usize >= code.len() { println!("Malformed code: immediate out of bounds"); break; } } - print!("{}", opcode.name); - if opcode.immediate_size != 0 { + print!("{}", opcode.name()); + if opcode.immediate_size() != 0 { print!( " : 0x{:}", - hex::encode(&code[i + 1..i + 1 + opcode.immediate_size as usize]) + hex::encode(&code[i + 1..i + 1 + opcode.immediate_size() as usize]) ); } @@ -51,7 +51,7 @@ pub fn print_eof_code(code: &[u8]) { } } - i += 1 + opcode.immediate_size as usize + rjumpv_additional_immediates; + i += 1 + opcode.immediate_size() as usize + rjumpv_additional_immediates; } } diff --git a/crates/primitives/src/bytecode/eof/types_section.rs b/crates/primitives/src/bytecode/eof/types_section.rs index 84db61f019..7695dc97ff 100644 --- a/crates/primitives/src/bytecode/eof/types_section.rs +++ b/crates/primitives/src/bytecode/eof/types_section.rs @@ -20,9 +20,9 @@ pub struct TypesSection { } impl TypesSection { - /// Return the difference between inputs and outputs. + /// Calculates the difference between the number of input and output stack elements. #[inline] - pub fn io_diff(&self) -> i32 { + pub const fn io_diff(&self) -> i32 { self.outputs as i32 - self.inputs as i32 } diff --git a/crates/revm/src/inspector/eip3155.rs b/crates/revm/src/inspector/eip3155.rs index cbc4b81734..b5331157dc 100644 --- a/crates/revm/src/inspector/eip3155.rs +++ b/crates/revm/src/inspector/eip3155.rs @@ -222,7 +222,7 @@ impl Inspector for TracerEip3155 { refund: hex_number(self.refunded as u64), mem_size: self.mem_size.to_string(), - op_name: OpCode::new(self.opcode).map(|i| i.info().name), + op_name: OpCode::new(self.opcode).map(|i| i.as_str()), error: if !interp.instruction_result.is_ok() { Some(format!("{:?}", interp.instruction_result)) } else {