revm_interpreter/interpreter/
subroutine_stack.rs

1use std::vec::Vec;
2
3use crate::interpreter_types::SubRoutineStack;
4
5/// Function(Sub Routine) return frame in eof
6///
7/// Needed information for returning from a function.
8#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct SubRoutineReturnFrame {
11    /// The index of the code container that this frame is executing.
12    pub idx: usize,
13    /// The program counter where frame execution should continue.
14    pub pc: usize,
15}
16
17impl SubRoutineReturnFrame {
18    /// Return new function frame.
19    pub fn new(idx: usize, pc: usize) -> Self {
20        Self { idx, pc }
21    }
22}
23
24/// Function Stack
25#[derive(Clone, Debug, Default, PartialEq, Eq)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
27pub struct SubRoutineImpl {
28    pub return_stack: Vec<SubRoutineReturnFrame>,
29    pub current_code_idx: usize,
30}
31
32impl SubRoutineImpl {
33    /// Returns new function stack.
34    pub fn new() -> Self {
35        Self {
36            return_stack: Vec::new(),
37            current_code_idx: 0,
38        }
39    }
40
41    pub fn len(&self) -> usize {
42        self.return_stack.len()
43    }
44
45    pub fn is_empty(&self) -> bool {
46        self.return_stack.is_empty()
47    }
48
49    /// Return stack length
50    pub fn return_stack_len(&self) -> usize {
51        self.return_stack.len()
52    }
53
54    /// Sets current_code_idx, this is needed for JUMPF opcode.
55    pub fn set_current_code_idx(&mut self, idx: usize) {
56        self.current_code_idx = idx;
57    }
58}
59
60impl SubRoutineStack for SubRoutineImpl {
61    fn len(&self) -> usize {
62        self.return_stack.len()
63    }
64
65    fn routine_idx(&self) -> usize {
66        self.current_code_idx
67    }
68
69    fn push(&mut self, program_counter: usize, new_idx: usize) -> bool {
70        if self.return_stack.len() >= 1024 {
71            return false;
72        }
73        self.return_stack.push(SubRoutineReturnFrame {
74            idx: self.current_code_idx,
75            pc: program_counter,
76        });
77        self.current_code_idx = new_idx;
78        true
79    }
80
81    fn pop(&mut self) -> Option<usize> {
82        self.return_stack.pop().map(|i| {
83            self.current_code_idx = i.idx;
84            i.pc
85        })
86    }
87
88    fn set_routine_idx(&mut self, idx: usize) {
89        self.current_code_idx = idx;
90    }
91}