Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(interpreter): export utility macros #1203

Merged
merged 4 commits into from
Mar 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion crates/interpreter/src/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ impl Gas {
true
}

/// used in shared_memory_resize! macro to record gas used for memory expansion.
/// Records memory expansion gas.
///
/// Used in [`resize_memory!`](crate::resize_memory).
#[inline]
pub fn record_memory(&mut self, gas_memory: u64) -> bool {
if gas_memory > self.memory {
Expand Down
2 changes: 1 addition & 1 deletion crates/interpreter/src/instructions/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::i256::{i256_div, i256_mod};
use crate::{
gas,
primitives::{Spec, U256},
Host, InstructionResult, Interpreter,
Host, Interpreter,
};

pub fn wrapping_add<H: Host>(interpreter: &mut Interpreter, _host: &mut H) {
Expand Down
2 changes: 1 addition & 1 deletion crates/interpreter/src/instructions/bitwise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::i256::{i256_cmp, i256_sign_compl, two_compl, Sign};
use crate::{
gas,
primitives::{Spec, U256},
Host, InstructionResult, Interpreter,
Host, Interpreter,
};
use core::cmp::Ordering;

Expand Down
2 changes: 1 addition & 1 deletion crates/interpreter/src/instructions/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fn return_inner(interpreter: &mut Interpreter, instruction_result: InstructionRe
let mut output = Bytes::default();
if len != 0 {
let offset = as_usize_or_fail!(interpreter, offset);
shared_memory_resize!(interpreter, offset, len);
resize_memory!(interpreter, offset, len);

output = interpreter.shared_memory.slice(offset, len).to_vec().into()
}
Expand Down
8 changes: 4 additions & 4 deletions crates/interpreter/src/instructions/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub use call_helpers::{calc_call_gas, get_memory_input_and_out_ranges};
use crate::{
gas::{self, COLD_ACCOUNT_ACCESS_COST, WARM_STORAGE_READ_COST},
interpreter::{Interpreter, InterpreterAction},
primitives::{Address, Bytes, Log, LogData, Spec, SpecId::*, B256, U256},
primitives::{Bytes, Log, LogData, Spec, SpecId::*, B256, U256},
CallContext, CallInputs, CallScheme, CreateInputs, CreateScheme, Host, InstructionResult,
SStoreResult, Transfer, MAX_INITCODE_SIZE,
};
Expand Down Expand Up @@ -112,7 +112,7 @@ pub fn extcodecopy<H: Host, SPEC: Spec>(interpreter: &mut Interpreter, host: &mu
}
let memory_offset = as_usize_or_fail!(interpreter, memory_offset);
let code_offset = min(as_usize_saturated!(code_offset), code.len());
shared_memory_resize!(interpreter, memory_offset, len);
resize_memory!(interpreter, memory_offset, len);

// Note: this can't panic because we resized memory to fit.
interpreter
Expand Down Expand Up @@ -204,7 +204,7 @@ pub fn log<const N: usize, H: Host>(interpreter: &mut Interpreter, host: &mut H)
Bytes::new()
} else {
let offset = as_usize_or_fail!(interpreter, offset);
shared_memory_resize!(interpreter, offset, len);
resize_memory!(interpreter, offset, len);
Bytes::copy_from_slice(interpreter.shared_memory.slice(offset, len))
};

Expand Down Expand Up @@ -278,7 +278,7 @@ pub fn create<const IS_CREATE2: bool, H: Host, SPEC: Spec>(
}

let code_offset = as_usize_or_fail!(interpreter, code_offset);
shared_memory_resize!(interpreter, code_offset, len);
resize_memory!(interpreter, code_offset, len);
code = Bytes::copy_from_slice(interpreter.shared_memory.slice(code_offset, len));
}

Expand Down
4 changes: 2 additions & 2 deletions crates/interpreter/src/instructions/host/call_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub fn get_memory_input_and_out_ranges(
let in_len = as_usize_or_fail_ret!(interpreter, in_len, None);
let input = if in_len != 0 {
let in_offset = as_usize_or_fail_ret!(interpreter, in_offset, None);
shared_memory_resize!(interpreter, in_offset, in_len, None);
resize_memory!(interpreter, in_offset, in_len, None);
Bytes::copy_from_slice(interpreter.shared_memory.slice(in_offset, in_len))
} else {
Bytes::new()
Expand All @@ -24,7 +24,7 @@ pub fn get_memory_input_and_out_ranges(
let out_len = as_usize_or_fail_ret!(interpreter, out_len, None);
let out_offset = if out_len != 0 {
let out_offset = as_usize_or_fail_ret!(interpreter, out_offset, None);
shared_memory_resize!(interpreter, out_offset, out_len, None);
resize_memory!(interpreter, out_offset, out_len, None);
out_offset
} else {
usize::MAX //unrealistic value so we are sure it is not used
Expand Down
2 changes: 1 addition & 1 deletion crates/interpreter/src/instructions/host_env.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
gas,
primitives::{Spec, SpecId::*, U256},
Host, InstructionResult, Interpreter,
Host, Interpreter,
};

/// EIP-1344: ChainID opcode
Expand Down
95 changes: 69 additions & 26 deletions crates/interpreter/src/instructions/macros.rs
Original file line number Diff line number Diff line change
@@ -1,57 +1,70 @@
//! Utility macros to help implementementing opcode instruction functions.

/// Fails the instruction if the current call is static.
#[macro_export]
macro_rules! check_staticcall {
($interp:expr) => {
if $interp.is_static {
$interp.instruction_result = InstructionResult::StateChangeDuringStaticCall;
$interp.instruction_result = $crate::InstructionResult::StateChangeDuringStaticCall;
return;
}
};
}

/// Fails the instruction if the `min` is not enabled in `SPEC`.
#[macro_export]
macro_rules! check {
($interp:expr, $min:ident) => {
// TODO: Force const-eval on the condition with a `const {}` block once they are stable
if !<SPEC as $crate::primitives::Spec>::enabled($crate::primitives::SpecId::$min) {
$interp.instruction_result = InstructionResult::NotActivated;
$interp.instruction_result = $crate::InstructionResult::NotActivated;
return;
}
};
}

/// Records a `gas` cost and fails the instruction if it would exceed the available gas.
#[macro_export]
macro_rules! gas {
($interp:expr, $gas:expr) => {
gas!($interp, $gas, ())
$crate::gas!($interp, $gas, ())
};
($interp:expr, $gas:expr, $ret:expr) => {
if !$interp.gas.record_cost($gas) {
$interp.instruction_result = InstructionResult::OutOfGas;
$interp.instruction_result = $crate::InstructionResult::OutOfGas;
return $ret;
}
};
}

/// Records a `gas` refund.
#[macro_export]
macro_rules! refund {
($interp:expr, $gas:expr) => {
$interp.gas.record_refund($gas)
};
}

/// Same as [`gas!`], but with `gas` as an option.
#[macro_export]
DaniPopes marked this conversation as resolved.
Show resolved Hide resolved
macro_rules! gas_or_fail {
($interp:expr, $gas:expr) => {
match $gas {
Some(gas_used) => gas!($interp, gas_used),
Some(gas_used) => $crate::gas!($interp, gas_used),
None => {
$interp.instruction_result = InstructionResult::OutOfGas;
$interp.instruction_result = $crate::InstructionResult::OutOfGas;
return;
}
}
};
}

/// Resizes the interpreter memory if necessary. Fails the instruction if the memory or gas limit
/// is exceeded.
#[macro_export]
macro_rules! shared_memory_resize {
macro_rules! resize_memory {
($interp:expr, $offset:expr, $len:expr) => {
shared_memory_resize!($interp, $offset, $len, ())
$crate::resize_memory!($interp, $offset, $len, ())
};
($interp:expr, $offset:expr, $len:expr, $ret:expr) => {
let size = $offset.saturating_add($len);
Expand All @@ -61,7 +74,7 @@ macro_rules! shared_memory_resize {

#[cfg(feature = "memory_limit")]
if $interp.shared_memory.limit_reached(size) {
$interp.instruction_result = InstructionResult::MemoryLimitOOG;
$interp.instruction_result = $crate::InstructionResult::MemoryLimitOOG;
return $ret;
}

Expand All @@ -71,34 +84,43 @@ macro_rules! shared_memory_resize {
.gas
.record_memory($crate::gas::memory_gas(words_num))
{
$interp.instruction_result = InstructionResult::MemoryLimitOOG;
$interp.instruction_result = $crate::InstructionResult::MemoryLimitOOG;
return $ret;
}
$interp.shared_memory.resize(rounded_size);
}
};
}

/// Pops `Address` values from the stack. Fails the instruction if the stack is too small.
#[macro_export]
macro_rules! pop_address {
($interp:expr, $x1:ident) => {
if $interp.stack.len() < 1 {
$interp.instruction_result = InstructionResult::StackUnderflow;
$interp.instruction_result = $crate::InstructionResult::StackUnderflow;
return;
}
// SAFETY: Length is checked above.
let $x1 = Address::from_word(B256::from(unsafe { $interp.stack.pop_unsafe() }));
let $x1 = $crate::primitives::Address::from_word($crate::primitives::B256::from(unsafe {
$interp.stack.pop_unsafe()
}));
};
($interp:expr, $x1:ident, $x2:ident) => {
if $interp.stack.len() < 2 {
$interp.instruction_result = InstructionResult::StackUnderflow;
$interp.instruction_result = $crate::InstructionResult::StackUnderflow;
return;
}
// SAFETY: Length is checked above.
let $x1 = Address::from_word(B256::from(unsafe { $interp.stack.pop_unsafe() }));
let $x2 = Address::from_word(B256::from(unsafe { $interp.stack.pop_unsafe() }));
let $x1 = $crate::primitives::Address::from_word($crate::primitives::B256::from(unsafe {
$interp.stack.pop_unsafe()
}));
let $x2 = $crate::primitives::Address::from_word($crate::primitives::B256::from(unsafe {
$interp.stack.pop_unsafe()
}));
};
}

/// Pops `U256` values from the stack. Fails the instruction if the stack is too small.
#[macro_export]
macro_rules! pop {
($interp:expr, $x1:ident) => {
Expand All @@ -115,69 +137,75 @@ macro_rules! pop {
};
}

/// Pops `U256` values from the stack, and returns `ret`.
/// Fails the instruction if the stack is too small.
#[macro_export]
macro_rules! pop_ret {
($interp:expr, $x1:ident, $ret:expr) => {
if $interp.stack.len() < 1 {
$interp.instruction_result = InstructionResult::StackUnderflow;
$interp.instruction_result = $crate::InstructionResult::StackUnderflow;
return $ret;
}
// SAFETY: Length is checked above.
let $x1 = unsafe { $interp.stack.pop_unsafe() };
};
($interp:expr, $x1:ident, $x2:ident, $ret:expr) => {
if $interp.stack.len() < 2 {
$interp.instruction_result = InstructionResult::StackUnderflow;
$interp.instruction_result = $crate::InstructionResult::StackUnderflow;
return $ret;
}
// SAFETY: Length is checked above.
let ($x1, $x2) = unsafe { $interp.stack.pop2_unsafe() };
};
($interp:expr, $x1:ident, $x2:ident, $x3:ident, $ret:expr) => {
if $interp.stack.len() < 3 {
$interp.instruction_result = InstructionResult::StackUnderflow;
$interp.instruction_result = $crate::InstructionResult::StackUnderflow;
return $ret;
}
// SAFETY: Length is checked above.
let ($x1, $x2, $x3) = unsafe { $interp.stack.pop3_unsafe() };
};
($interp:expr, $x1:ident, $x2:ident, $x3:ident, $x4:ident, $ret:expr) => {
if $interp.stack.len() < 4 {
$interp.instruction_result = InstructionResult::StackUnderflow;
$interp.instruction_result = $crate::InstructionResult::StackUnderflow;
return $ret;
}
// SAFETY: Length is checked above.
let ($x1, $x2, $x3, $x4) = unsafe { $interp.stack.pop4_unsafe() };
};
}

/// Pops `U256` values from the stack, and returns a reference to the top of the stack.
/// Fails the instruction if the stack is too small.
#[macro_export]
macro_rules! pop_top {
($interp:expr, $x1:ident) => {
if $interp.stack.len() < 1 {
$interp.instruction_result = InstructionResult::StackUnderflow;
$interp.instruction_result = $crate::InstructionResult::StackUnderflow;
return;
}
// SAFETY: Length is checked above.
let $x1 = unsafe { $interp.stack.top_unsafe() };
};
($interp:expr, $x1:ident, $x2:ident) => {
if $interp.stack.len() < 2 {
$interp.instruction_result = InstructionResult::StackUnderflow;
$interp.instruction_result = $crate::InstructionResult::StackUnderflow;
return;
}
// SAFETY: Length is checked above.
let ($x1, $x2) = unsafe { $interp.stack.pop_top_unsafe() };
};
($interp:expr, $x1:ident, $x2:ident, $x3:ident) => {
if $interp.stack.len() < 3 {
$interp.instruction_result = InstructionResult::StackUnderflow;
$interp.instruction_result = $crate::InstructionResult::StackUnderflow;
return;
}
// SAFETY: Length is checked above.
let ($x1, $x2, $x3) = unsafe { $interp.stack.pop2_top_unsafe() };
};
}

/// Pushes `B256` values onto the stack. Fails the instruction if the stack is full.
#[macro_export]
macro_rules! push_b256 {
($interp:expr, $($x:expr),* $(,)?) => ($(
Expand All @@ -191,6 +219,7 @@ macro_rules! push_b256 {
)*)
}

/// Pushes a `B256` value onto the stack. Fails the instruction if the stack is full.
#[macro_export]
macro_rules! push {
($interp:expr, $($x:expr),* $(,)?) => ($(
Expand All @@ -204,6 +233,8 @@ macro_rules! push {
)*)
}

/// Converts a `U256` value to a `u64`, saturating to `MAX` if the value is too large.
#[macro_export]
macro_rules! as_u64_saturated {
($v:expr) => {{
let x: &[u64; 4] = $v.as_limbs();
Expand All @@ -215,24 +246,36 @@ macro_rules! as_u64_saturated {
}};
}

/// Converts a `U256` value to a `usize`, saturating to `MAX` if the value is too large.
#[macro_export]
macro_rules! as_usize_saturated {
($v:expr) => {
usize::try_from(as_u64_saturated!($v)).unwrap_or(usize::MAX)
usize::try_from($crate::as_u64_saturated!($v)).unwrap_or(usize::MAX)
};
}

/// Converts a `U256` value to a `usize`, failing the instruction if the value is too large.
#[macro_export]
macro_rules! as_usize_or_fail {
($interp:expr, $v:expr) => {
as_usize_or_fail_ret!($interp, $v, ())
$crate::as_usize_or_fail_ret!($interp, $v, ())
};
($interp:expr, $v:expr, $reason:expr) => {
as_usize_or_fail_ret!($interp, $v, $reason, ())
$crate::as_usize_or_fail_ret!($interp, $v, $reason, ())
};
}

/// Converts a `U256` value to a `usize` and returns `ret`,
/// failing the instruction if the value is too large.
#[macro_export]
macro_rules! as_usize_or_fail_ret {
($interp:expr, $v:expr, $ret:expr) => {
as_usize_or_fail_ret!($interp, $v, InstructionResult::InvalidOperandOOG, $ret)
$crate::as_usize_or_fail_ret!(
$interp,
$v,
$crate::InstructionResult::InvalidOperandOOG,
$ret
)
};

($interp:expr, $v:expr, $reason:expr, $ret:expr) => {{
Expand Down
Loading
Loading