Skip to main content

revm_interpreter/instructions/
control.rs

1use crate::{
2    interpreter::Interpreter,
3    interpreter_types::{
4        InterpreterTypes as ITy, Jumps, LoopControl, MemoryTr, RuntimeFlag, StackTr,
5    },
6    InstructionExecResult as Result, InstructionResult, InterpreterAction,
7};
8use context_interface::{cfg::GasParams, Host};
9use primitives::{hints_util::cold_path, Bytes, U256};
10
11use crate::InstructionContext as Ictx;
12
13/// Implements the JUMP instruction.
14///
15/// Unconditional jump to a valid destination.
16pub fn jump<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
17    popn!([target], context.interpreter);
18    jump_inner(context.interpreter, target)
19}
20
21/// Implements the JUMPI instruction.
22///
23/// Conditional jump to a valid destination if condition is true.
24pub fn jumpi<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
25    popn!([target, cond], context.interpreter);
26    if !cond.is_zero() {
27        jump_inner(context.interpreter, target)?;
28    }
29    Ok(())
30}
31
32/// Internal helper function for jump operations.
33///
34/// Validates jump target and performs the actual jump.
35#[inline(always)]
36fn jump_inner<IT: ITy>(
37    interpreter: &mut Interpreter<IT>,
38    target: U256,
39) -> Result<(), InstructionResult> {
40    let target = as_usize_saturated!(target);
41    if !interpreter.bytecode.is_valid_legacy_jump(target) {
42        cold_path();
43        return Err(InstructionResult::InvalidJump);
44    }
45    // SAFETY: `is_valid_jump` ensures that `dest` is in bounds.
46    interpreter.bytecode.absolute_jump(target);
47    Ok(())
48}
49
50/// Implements the JUMPDEST instruction.
51///
52/// Marks a valid destination for jump operations.
53pub const fn jumpdest<IT: ITy, H: ?Sized>(_context: Ictx<'_, H, IT>) -> Result {
54    Ok(())
55}
56
57/// Implements the PC instruction.
58///
59/// Pushes the current program counter onto the stack.
60pub fn pc<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
61    // - 1 because we have already advanced the instruction pointer in `Interpreter::step`
62    push!(
63        context.interpreter,
64        U256::from(context.interpreter.bytecode.pc() - 1)
65    );
66    Ok(())
67}
68
69/// Internal helper function for return operations.
70///
71/// Handles memory data retrieval and sets the return action.
72#[inline]
73fn return_inner(
74    interpreter: &mut Interpreter<impl ITy>,
75    gas_params: &GasParams,
76    instruction_result: InstructionResult,
77) -> Result<(), InstructionResult> {
78    popn!([offset, len], interpreter);
79    let len = as_usize_or_fail!(interpreter, len);
80    // Important: Offset must be ignored if len is zeros
81    let mut output = Bytes::default();
82    if len != 0 {
83        let offset = as_usize_or_fail!(interpreter, offset);
84        interpreter.resize_memory(gas_params, offset, len)?;
85        output = interpreter.memory.slice_len(offset, len).to_vec().into()
86    }
87
88    interpreter
89        .bytecode
90        .set_action(InterpreterAction::new_return(
91            instruction_result,
92            output,
93            interpreter.gas,
94        ));
95    Err(instruction_result)
96}
97
98/// Implements the RETURN instruction.
99///
100/// Halts execution and returns data from memory.
101pub fn ret<IT: ITy, H: Host + ?Sized>(context: Ictx<'_, H, IT>) -> Result {
102    return_inner(
103        context.interpreter,
104        context.host.gas_params(),
105        InstructionResult::Return,
106    )
107}
108
109/// EIP-140: REVERT instruction
110pub fn revert<IT: ITy, H: Host + ?Sized>(context: Ictx<'_, H, IT>) -> Result {
111    check!(context.interpreter, BYZANTIUM);
112    return_inner(
113        context.interpreter,
114        context.host.gas_params(),
115        InstructionResult::Revert,
116    )
117}
118
119/// Stop opcode. This opcode halts the execution.
120pub const fn stop<IT: ITy, H: ?Sized>(_context: Ictx<'_, H, IT>) -> Result {
121    Err(InstructionResult::Stop)
122}
123
124/// Invalid opcode. This opcode halts the execution.
125pub const fn invalid<IT: ITy, H: ?Sized>(_context: Ictx<'_, H, IT>) -> Result {
126    Err(InstructionResult::InvalidFEOpcode)
127}
128
129/// Unknown opcode. This opcode halts the execution.
130pub const fn unknown<IT: ITy, H: ?Sized>(_context: Ictx<'_, H, IT>) -> Result {
131    Err(InstructionResult::OpcodeNotFound)
132}