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