revm_interpreter/instructions/
control.rs

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