revm_interpreter/interpreter/
subroutine_stack.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use std::vec::Vec;

use crate::interpreter_types::SubRoutineStack;

/// Function(Sub Routine) return frame in eof
///
/// Needed information for returning from a function.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SubRoutineReturnFrame {
    /// The index of the code container that this frame is executing.
    pub idx: usize,
    /// The program counter where frame execution should continue.
    pub pc: usize,
}

impl SubRoutineReturnFrame {
    /// Return new function frame.
    pub fn new(idx: usize, pc: usize) -> Self {
        Self { idx, pc }
    }
}

/// Function Stack
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SubRoutineImpl {
    pub return_stack: Vec<SubRoutineReturnFrame>,
    pub current_code_idx: usize,
}

impl SubRoutineImpl {
    /// Returns new function stack.
    pub fn new() -> Self {
        Self {
            return_stack: Vec::new(),
            current_code_idx: 0,
        }
    }

    pub fn len(&self) -> usize {
        self.return_stack.len()
    }

    pub fn is_empty(&self) -> bool {
        self.return_stack.is_empty()
    }

    /// Return stack length
    pub fn return_stack_len(&self) -> usize {
        self.return_stack.len()
    }

    /// Sets current_code_idx, this is needed for JUMPF opcode.
    pub fn set_current_code_idx(&mut self, idx: usize) {
        self.current_code_idx = idx;
    }
}

impl SubRoutineStack for SubRoutineImpl {
    fn len(&self) -> usize {
        self.return_stack.len()
    }

    fn routine_idx(&self) -> usize {
        self.current_code_idx
    }

    fn push(&mut self, program_counter: usize, new_idx: usize) -> bool {
        if self.return_stack.len() >= 1024 {
            return false;
        }
        self.return_stack.push(SubRoutineReturnFrame {
            idx: self.current_code_idx,
            pc: program_counter,
        });
        self.current_code_idx = new_idx;
        true
    }

    fn pop(&mut self) -> Option<usize> {
        self.return_stack.pop().map(|i| {
            self.current_code_idx = i.idx;
            i.pc
        })
    }

    fn set_routine_idx(&mut self, idx: usize) {
        self.current_code_idx = idx;
    }
}