revm_interpreter/instructions/
control.rs

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