Skip to content

Commit

Permalink
perf(interpreter): use pop_top! where possible (bluealloy#1267)
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniPopes authored Apr 7, 2024
1 parent c961887 commit c1eb0e6
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 45 deletions.
18 changes: 9 additions & 9 deletions crates/interpreter/src/instructions/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,27 @@ use crate::{

pub fn jump<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::MID);
pop!(interpreter, dest);
jump_inner(interpreter, dest);
pop!(interpreter, target);
jump_inner(interpreter, target);
}

pub fn jumpi<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::HIGH);
pop!(interpreter, dest, value);
if value != U256::ZERO {
jump_inner(interpreter, dest);
pop!(interpreter, target, cond);
if cond != U256::ZERO {
jump_inner(interpreter, target);
}
}

#[inline(always)]
fn jump_inner(interpreter: &mut Interpreter, dest: U256) {
let dest = as_usize_or_fail!(interpreter, dest, InstructionResult::InvalidJump);
if !interpreter.contract.is_valid_jump(dest) {
fn jump_inner(interpreter: &mut Interpreter, target: U256) {
let target = as_usize_or_fail!(interpreter, target, InstructionResult::InvalidJump);
if !interpreter.contract.is_valid_jump(target) {
interpreter.instruction_result = InstructionResult::InvalidJump;
return;
}
// SAFETY: `is_valid_jump` ensures that `dest` is in bounds.
interpreter.instruction_pointer = unsafe { interpreter.contract.bytecode.as_ptr().add(dest) };
interpreter.instruction_pointer = unsafe { interpreter.contract.bytecode.as_ptr().add(target) };
}

pub fn jumpdest<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
Expand Down
6 changes: 3 additions & 3 deletions crates/interpreter/src/instructions/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,14 @@ pub fn blockhash<H: Host + ?Sized>(interpreter: &mut Interpreter, host: &mut H)
}

pub fn sload<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
pop!(interpreter, index);
pop_top!(interpreter, index);

let Some((value, is_cold)) = host.sload(interpreter.contract.address, index) else {
let Some((value, is_cold)) = host.sload(interpreter.contract.address, *index) else {
interpreter.instruction_result = InstructionResult::FatalExternalError;
return;
};
gas!(interpreter, gas::sload_cost(SPEC::SPEC_ID, is_cold));
push!(interpreter, value);
*index = value;
}

pub fn sstore<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, host: &mut H) {
Expand Down
24 changes: 12 additions & 12 deletions crates/interpreter/src/instructions/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,26 @@ use core::cmp::max;

pub fn mload<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop!(interpreter, index);
let index = as_usize_or_fail!(interpreter, index);
resize_memory!(interpreter, index, 32);
push!(interpreter, interpreter.shared_memory.get_u256(index));
pop_top!(interpreter, offset_ptr);
let offset = as_usize_or_fail!(interpreter, offset_ptr);
resize_memory!(interpreter, offset, 32);
*offset_ptr = interpreter.shared_memory.get_u256(offset);
}

pub fn mstore<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop!(interpreter, index, value);
let index = as_usize_or_fail!(interpreter, index);
resize_memory!(interpreter, index, 32);
interpreter.shared_memory.set_u256(index, value);
pop!(interpreter, offset, value);
let offset = as_usize_or_fail!(interpreter, offset);
resize_memory!(interpreter, offset, 32);
interpreter.shared_memory.set_u256(offset, value);
}

pub fn mstore8<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop!(interpreter, index, value);
let index = as_usize_or_fail!(interpreter, index);
resize_memory!(interpreter, index, 1);
interpreter.shared_memory.set_byte(index, value.byte(0))
pop!(interpreter, offset, value);
let offset = as_usize_or_fail!(interpreter, offset);
resize_memory!(interpreter, offset, 1);
interpreter.shared_memory.set_byte(offset, value.byte(0))
}

pub fn msize<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
Expand Down
41 changes: 24 additions & 17 deletions crates/interpreter/src/instructions/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ use crate::{
primitives::{Spec, B256, KECCAK_EMPTY, U256},
Host, InstructionResult, Interpreter,
};
use core::ptr;

pub fn keccak256<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
pop!(interpreter, from, len);
let len = as_usize_or_fail!(interpreter, len);
pop_top!(interpreter, offset, len_ptr);
let len = as_usize_or_fail!(interpreter, len_ptr);
gas_or_fail!(interpreter, gas::keccak256_cost(len as u64));
let hash = if len == 0 {
KECCAK_EMPTY
} else {
let from = as_usize_or_fail!(interpreter, from);
let from = as_usize_or_fail!(interpreter, offset);
resize_memory!(interpreter, from, len);
crate::primitives::keccak256(interpreter.shared_memory.slice(from, len))
};

push_b256!(interpreter, hash);
*len_ptr = hash.into();
}

pub fn address<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
Expand Down Expand Up @@ -56,18 +56,25 @@ pub fn codecopy<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H)

pub fn calldataload<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
gas!(interpreter, gas::VERYLOW);
pop!(interpreter, index);
let index = as_usize_saturated!(index);
let load = if index < interpreter.contract.input.len() {
let have_bytes = 32.min(interpreter.contract.input.len() - index);
let mut bytes = [0u8; 32];
bytes[..have_bytes].copy_from_slice(&interpreter.contract.input[index..index + have_bytes]);
B256::new(bytes)
} else {
B256::ZERO
};

push_b256!(interpreter, load);
pop_top!(interpreter, offset_ptr);
let mut word = B256::ZERO;
let offset = as_usize_saturated!(offset_ptr);
if offset < interpreter.contract.input.len() {
let count = 32.min(interpreter.contract.input.len() - offset);
// SAFETY: count is bounded by the calldata length.
// This is `word[..count].copy_from_slice(input[offset..offset + count])`, written using
// raw pointers as apparently the compiler cannot optimize the slice version, and using
// `get_unchecked` twice is uglier.
debug_assert!(count <= 32 && offset + count <= interpreter.contract.input.len());
unsafe {
ptr::copy_nonoverlapping(
interpreter.contract.input.as_ptr().add(offset),
word.as_mut_ptr(),
count,
)
};
}
*offset_ptr = word.into();
}

pub fn calldatasize<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
Expand Down
2 changes: 1 addition & 1 deletion crates/interpreter/src/interpreter/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ impl Stack {
/// unchanged.
#[inline]
pub fn push(&mut self, value: U256) -> Result<(), InstructionResult> {
// allows the compiler to optimize out the `Vec::push` capacity check
// Allows the compiler to optimize out the `Vec::push` capacity check.
assume!(self.data.capacity() == STACK_LIMIT);
if self.data.len() == STACK_LIMIT {
return Err(InstructionResult::StackOverflow);
Expand Down
7 changes: 4 additions & 3 deletions crates/revm/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,13 +382,14 @@ impl<EXT, DB: Database> Evm<'_, EXT, DB> {
}

impl<EXT, DB: Database> Host for Evm<'_, EXT, DB> {
fn env_mut(&mut self) -> &mut Env {
&mut self.context.evm.env
}
fn env(&self) -> &Env {
&self.context.evm.env
}

fn env_mut(&mut self) -> &mut Env {
&mut self.context.evm.env
}

fn block_hash(&mut self, number: U256) -> Option<B256> {
self.context
.evm
Expand Down

0 comments on commit c1eb0e6

Please sign in to comment.