Skip to main content

revm_rwasm_interpreter/interpreter/
stack.rs

1use crate::InstructionResult;
2use core::{fmt, ptr};
3use primitives::U256;
4use std::vec::Vec;
5
6use super::StackTr;
7
8/// EVM interpreter stack limit.
9pub const STACK_LIMIT: usize = 1024;
10
11/// EVM stack with [STACK_LIMIT] capacity of words.
12#[derive(Debug, PartialEq, Eq, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize))]
14pub struct Stack {
15    /// The underlying data of the stack.
16    data: Vec<U256>,
17}
18
19impl fmt::Display for Stack {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        f.write_str("[")?;
22        for (i, x) in self.data.iter().enumerate() {
23            if i > 0 {
24                f.write_str(", ")?;
25            }
26            write!(f, "{x}")?;
27        }
28        f.write_str("]")
29    }
30}
31
32impl Default for Stack {
33    #[inline]
34    fn default() -> Self {
35        Self::new()
36    }
37}
38
39impl Clone for Stack {
40    fn clone(&self) -> Self {
41        // Use `Self::new()` to ensure the cloned Stack is constructed with at least
42        // STACK_LIMIT capacity, and then copy the data. This preserves the invariant
43        // that Stack has sufficient capacity for operations that rely on it.
44        let mut new_stack = Self::new();
45        new_stack.data.extend_from_slice(&self.data);
46        new_stack
47    }
48}
49
50impl StackTr for Stack {
51    #[inline]
52    fn len(&self) -> usize {
53        self.len()
54    }
55
56    #[inline]
57    fn data(&self) -> &[U256] {
58        &self.data
59    }
60
61    #[inline]
62    fn clear(&mut self) {
63        self.data.clear();
64    }
65
66    #[inline]
67    fn popn<const N: usize>(&mut self) -> Option<[U256; N]> {
68        if self.len() < N {
69            return None;
70        }
71        // SAFETY: Stack length is checked above.
72        Some(unsafe { self.popn::<N>() })
73    }
74
75    #[inline]
76    fn popn_top<const POPN: usize>(&mut self) -> Option<([U256; POPN], &mut U256)> {
77        if self.len() < POPN + 1 {
78            return None;
79        }
80        // SAFETY: Stack length is checked above.
81        Some(unsafe { self.popn_top::<POPN>() })
82    }
83
84    #[inline]
85    fn exchange(&mut self, n: usize, m: usize) -> bool {
86        self.exchange(n, m)
87    }
88
89    #[inline]
90    fn dup(&mut self, n: usize) -> bool {
91        self.dup(n)
92    }
93
94    #[inline]
95    fn push(&mut self, value: U256) -> bool {
96        self.push(value)
97    }
98
99    #[inline]
100    fn push_slice(&mut self, slice: &[u8]) -> bool {
101        self.push_slice_(slice)
102    }
103}
104
105impl Stack {
106    /// Instantiate a new stack with the [default stack limit][STACK_LIMIT].
107    #[inline]
108    pub fn new() -> Self {
109        Self {
110            // SAFETY: Expansion functions assume that capacity is `STACK_LIMIT`.
111            data: Vec::with_capacity(STACK_LIMIT),
112        }
113    }
114
115    /// Instantiate a new invalid Stack.
116    #[inline]
117    pub fn invalid() -> Self {
118        Self { data: Vec::new() }
119    }
120
121    /// Returns the length of the stack in words.
122    #[inline]
123    pub fn len(&self) -> usize {
124        self.data.len()
125    }
126
127    /// Returns whether the stack is empty.
128    #[inline]
129    pub fn is_empty(&self) -> bool {
130        self.data.is_empty()
131    }
132
133    /// Returns a reference to the underlying data buffer.
134    #[inline]
135    pub fn data(&self) -> &Vec<U256> {
136        &self.data
137    }
138
139    /// Returns a mutable reference to the underlying data buffer.
140    #[inline]
141    pub fn data_mut(&mut self) -> &mut Vec<U256> {
142        &mut self.data
143    }
144
145    /// Consumes the stack and returns the underlying data buffer.
146    #[inline]
147    pub fn into_data(self) -> Vec<U256> {
148        self.data
149    }
150
151    /// Removes the topmost element from the stack and returns it, or `StackUnderflow` if it is
152    /// empty.
153    #[inline]
154    #[cfg_attr(debug_assertions, track_caller)]
155    pub fn pop(&mut self) -> Result<U256, InstructionResult> {
156        //Todo: can you likely instrincts to show the else branch is more likely to be hit
157        let len = self.data.len();
158        if primitives::hints_util::unlikely(len == 0) {
159            Err(InstructionResult::StackUnderflow)
160        } else {
161            unsafe {
162                self.data.set_len(len - 1);
163                Ok(core::ptr::read(self.data.as_ptr().add(len - 1)))
164            }
165        }
166    }
167
168    /// Removes the topmost element from the stack and returns it.
169    ///
170    /// # Safety
171    ///
172    /// The caller is responsible for checking the length of the stack.
173    #[inline]
174    #[cfg_attr(debug_assertions, track_caller)]
175    pub unsafe fn pop_unsafe(&mut self) -> U256 {
176        assume!(!self.data.is_empty());
177        self.data.pop().unwrap_unchecked()
178    }
179
180    /// Peeks the top of the stack.
181    ///
182    /// # Safety
183    ///
184    /// The caller is responsible for checking the length of the stack.
185    #[inline]
186    #[cfg_attr(debug_assertions, track_caller)]
187    pub unsafe fn top_unsafe(&mut self) -> &mut U256 {
188        assume!(!self.data.is_empty());
189        self.data.last_mut().unwrap_unchecked()
190    }
191
192    /// Pops `N` values from the stack.
193    ///
194    /// # Safety
195    ///
196    /// The caller is responsible for checking the length of the stack.
197    #[inline]
198    #[cfg_attr(debug_assertions, track_caller)]
199    pub unsafe fn popn<const N: usize>(&mut self) -> [U256; N] {
200        assume!(self.data.len() >= N);
201        core::array::from_fn(|_| unsafe { self.pop_unsafe() })
202    }
203
204    /// Pops `N` values from the stack and returns the top of the stack.
205    ///
206    /// # Safety
207    ///
208    /// The caller is responsible for checking the length of the stack.
209    #[inline]
210    #[cfg_attr(debug_assertions, track_caller)]
211    pub unsafe fn popn_top<const POPN: usize>(&mut self) -> ([U256; POPN], &mut U256) {
212        let result = self.popn::<POPN>();
213        let top = self.top_unsafe();
214        (result, top)
215    }
216
217    /// Push a new value onto the stack.
218    ///
219    /// If it will exceed the stack limit, returns false and leaves the stack
220    /// unchanged.
221    #[inline]
222    #[must_use]
223    #[cfg_attr(debug_assertions, track_caller)]
224    pub fn push(&mut self, value: U256) -> bool {
225        // In debug builds, verify we have sufficient capacity provisioned.
226        debug_assert!(self.data.capacity() >= STACK_LIMIT);
227        let len = self.data.len();
228        if len == STACK_LIMIT {
229            return false;
230        }
231        unsafe {
232            let end = self.data.as_mut_ptr().add(len);
233            core::ptr::write(end, value);
234            self.data.set_len(len + 1);
235        }
236        true
237    }
238
239    /// Peek a value at given index for the stack, where the top of
240    /// the stack is at index `0`. If the index is too large,
241    /// `StackError::Underflow` is returned.
242    #[inline]
243    pub fn peek(&self, no_from_top: usize) -> Result<U256, InstructionResult> {
244        if self.data.len() > no_from_top {
245            Ok(self.data[self.data.len() - no_from_top - 1])
246        } else {
247            Err(InstructionResult::StackUnderflow)
248        }
249    }
250
251    /// Peek N records from the top
252    #[inline]
253    pub fn peekn<const N: usize>(&self) -> Option<[U256; N]> {
254        let len = self.data.len();
255        (len >= N).then(|| core::array::from_fn(|i| self.data[len - 1 - i]))
256    }
257
258    /// Duplicates the `N`th value from the top of the stack.
259    ///
260    /// # Panics
261    ///
262    /// Panics if `n` is 0.
263    #[inline]
264    #[must_use]
265    #[cfg_attr(debug_assertions, track_caller)]
266    pub fn dup(&mut self, n: usize) -> bool {
267        assume!(n > 0, "attempted to dup 0");
268        let len = self.data.len();
269        if len < n || len + 1 > STACK_LIMIT {
270            false
271        } else {
272            // SAFETY: Check for out of bounds is done above and it makes this safe to do.
273            unsafe {
274                let ptr = self.data.as_mut_ptr().add(len);
275                ptr::copy_nonoverlapping(ptr.sub(n), ptr, 1);
276                self.data.set_len(len + 1);
277            }
278            true
279        }
280    }
281
282    /// Swaps the topmost value with the `N`th value from the top.
283    ///
284    /// # Panics
285    ///
286    /// Panics if `n` is 0.
287    #[inline(always)]
288    #[cfg_attr(debug_assertions, track_caller)]
289    pub fn swap(&mut self, n: usize) -> bool {
290        self.exchange(0, n)
291    }
292
293    /// Exchange two values on the stack.
294    ///
295    /// `n` is the first index, and the second index is calculated as `n + m`.
296    ///
297    /// # Panics
298    ///
299    /// Panics if `m` is zero.
300    #[inline]
301    #[cfg_attr(debug_assertions, track_caller)]
302    pub fn exchange(&mut self, n: usize, m: usize) -> bool {
303        assume!(m > 0, "overlapping exchange");
304        let len = self.data.len();
305        let n_m_index = n + m;
306        if n_m_index >= len {
307            return false;
308        }
309        // SAFETY: `n` and `n_m` are checked to be within bounds, and they don't overlap.
310        unsafe {
311            // Note: `ptr::swap_nonoverlapping` is more efficient than `slice::swap` or `ptr::swap`
312            // because it operates under the assumption that the pointers do not overlap,
313            // eliminating an intermediate copy,
314            // which is a condition we know to be true in this context.
315            let top = self.data.as_mut_ptr().add(len - 1);
316            core::ptr::swap_nonoverlapping(top.sub(n), top.sub(n_m_index), 1);
317        }
318        true
319    }
320
321    /// Pushes an arbitrary length slice of bytes onto the stack, padding the last word with zeros
322    /// if necessary.
323    #[inline]
324    pub fn push_slice(&mut self, slice: &[u8]) -> Result<(), InstructionResult> {
325        if self.push_slice_(slice) {
326            Ok(())
327        } else {
328            Err(InstructionResult::StackOverflow)
329        }
330    }
331
332    /// Pushes an arbitrary length slice of bytes onto the stack, padding the last word with zeros
333    /// if necessary.
334    #[inline]
335    fn push_slice_(&mut self, slice: &[u8]) -> bool {
336        if slice.is_empty() {
337            return true;
338        }
339
340        let n_words = slice.len().div_ceil(32);
341        let new_len = self.data.len() + n_words;
342        if new_len > STACK_LIMIT {
343            return false;
344        }
345
346        // In debug builds, ensure underlying capacity is sufficient for the write.
347        debug_assert!(self.data.capacity() >= new_len);
348
349        // SAFETY: Length checked above.
350        unsafe {
351            let dst = self.data.as_mut_ptr().add(self.data.len()).cast::<u64>();
352            self.data.set_len(new_len);
353
354            let mut i = 0;
355
356            // Write full words
357            let words = slice.chunks_exact(32);
358            let partial_last_word = words.remainder();
359            for word in words {
360                // Note: We unroll `U256::from_be_bytes` here to write directly into the buffer,
361                // instead of creating a 32 byte array on the stack and then copying it over.
362                for l in word.rchunks_exact(8) {
363                    dst.add(i).write(u64::from_be_bytes(l.try_into().unwrap()));
364                    i += 1;
365                }
366            }
367
368            if partial_last_word.is_empty() {
369                return true;
370            }
371
372            // Write limbs of partial last word
373            let limbs = partial_last_word.rchunks_exact(8);
374            let partial_last_limb = limbs.remainder();
375            for l in limbs {
376                dst.add(i).write(u64::from_be_bytes(l.try_into().unwrap()));
377                i += 1;
378            }
379
380            // Write partial last limb by padding with zeros
381            if !partial_last_limb.is_empty() {
382                let mut tmp = [0u8; 8];
383                tmp[8 - partial_last_limb.len()..].copy_from_slice(partial_last_limb);
384                dst.add(i).write(u64::from_be_bytes(tmp));
385                i += 1;
386            }
387
388            debug_assert_eq!(i.div_ceil(4), n_words, "wrote too much");
389
390            // Zero out upper bytes of last word
391            let m = i % 4; // 32 / 8
392            if m != 0 {
393                dst.add(i).write_bytes(0, 4 - m);
394            }
395        }
396
397        true
398    }
399
400    /// Set a value at given index for the stack, where the top of the
401    /// stack is at index `0`. If the index is too large,
402    /// `StackError::Underflow` is returned.
403    #[inline]
404    pub fn set(&mut self, no_from_top: usize, val: U256) -> Result<(), InstructionResult> {
405        if self.data.len() > no_from_top {
406            let len = self.data.len();
407            self.data[len - no_from_top - 1] = val;
408            Ok(())
409        } else {
410            Err(InstructionResult::StackUnderflow)
411        }
412    }
413}
414
415#[cfg(feature = "serde")]
416impl<'de> serde::Deserialize<'de> for Stack {
417    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
418    where
419        D: serde::Deserializer<'de>,
420    {
421        #[derive(serde::Deserialize)]
422        struct StackSerde {
423            data: Vec<U256>,
424        }
425
426        let mut stack = StackSerde::deserialize(deserializer)?;
427        if stack.data.len() > STACK_LIMIT {
428            return Err(serde::de::Error::custom(std::format!(
429                "stack size exceeds limit: {} > {}",
430                stack.data.len(),
431                STACK_LIMIT
432            )));
433        }
434        stack.data.reserve(STACK_LIMIT - stack.data.len());
435        Ok(Self { data: stack.data })
436    }
437}
438
439#[cfg(test)]
440mod tests {
441    use super::*;
442
443    fn run(f: impl FnOnce(&mut Stack)) {
444        let mut stack = Stack::new();
445        // Fill capacity with non-zero values
446        unsafe {
447            stack.data.set_len(STACK_LIMIT);
448            stack.data.fill(U256::MAX);
449            stack.data.set_len(0);
450        }
451        f(&mut stack);
452    }
453
454    #[test]
455    fn push_slices() {
456        // No-op
457        run(|stack| {
458            stack.push_slice(b"").unwrap();
459            assert!(stack.data.is_empty());
460        });
461
462        // One word
463        run(|stack| {
464            stack.push_slice(&[42]).unwrap();
465            assert_eq!(stack.data, [U256::from(42)]);
466        });
467
468        let n = 0x1111_2222_3333_4444_5555_6666_7777_8888_u128;
469        run(|stack| {
470            stack.push_slice(&n.to_be_bytes()).unwrap();
471            assert_eq!(stack.data, [U256::from(n)]);
472        });
473
474        // More than one word
475        run(|stack| {
476            let b = [U256::from(n).to_be_bytes::<32>(); 2].concat();
477            stack.push_slice(&b).unwrap();
478            assert_eq!(stack.data, [U256::from(n); 2]);
479        });
480
481        run(|stack| {
482            let b = [&[0; 32][..], &[42u8]].concat();
483            stack.push_slice(&b).unwrap();
484            assert_eq!(stack.data, [U256::ZERO, U256::from(42)]);
485        });
486
487        run(|stack| {
488            let b = [&[0; 32][..], &n.to_be_bytes()].concat();
489            stack.push_slice(&b).unwrap();
490            assert_eq!(stack.data, [U256::ZERO, U256::from(n)]);
491        });
492
493        run(|stack| {
494            let b = [&[0; 64][..], &n.to_be_bytes()].concat();
495            stack.push_slice(&b).unwrap();
496            assert_eq!(stack.data, [U256::ZERO, U256::ZERO, U256::from(n)]);
497        });
498    }
499
500    #[test]
501    fn stack_clone() {
502        // Test cloning an empty stack
503        let empty_stack = Stack::new();
504        let cloned_empty = empty_stack.clone();
505        assert_eq!(empty_stack, cloned_empty);
506        assert_eq!(cloned_empty.len(), 0);
507        assert_eq!(cloned_empty.data().capacity(), STACK_LIMIT);
508
509        // Test cloning a partially filled stack
510        let mut partial_stack = Stack::new();
511        for i in 0..10 {
512            assert!(partial_stack.push(U256::from(i)));
513        }
514        let mut cloned_partial = partial_stack.clone();
515        assert_eq!(partial_stack, cloned_partial);
516        assert_eq!(cloned_partial.len(), 10);
517        assert_eq!(cloned_partial.data().capacity(), STACK_LIMIT);
518
519        // Test that modifying the clone doesn't affect the original
520        assert!(cloned_partial.push(U256::from(100)));
521        assert_ne!(partial_stack, cloned_partial);
522        assert_eq!(partial_stack.len(), 10);
523        assert_eq!(cloned_partial.len(), 11);
524
525        // Test cloning a full stack
526        let mut full_stack = Stack::new();
527        for i in 0..STACK_LIMIT {
528            assert!(full_stack.push(U256::from(i)));
529        }
530        let mut cloned_full = full_stack.clone();
531        assert_eq!(full_stack, cloned_full);
532        assert_eq!(cloned_full.len(), STACK_LIMIT);
533        assert_eq!(cloned_full.data().capacity(), STACK_LIMIT);
534
535        // Test push to the full original or cloned stack should return StackOverflow
536        assert!(!full_stack.push(U256::from(100)));
537        assert!(!cloned_full.push(U256::from(100)));
538    }
539}