evmil/util/
interval_stack.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5//    http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12use std::{cmp, fmt, mem};
13use std::fmt::{Debug,Display};
14use crate::util::{Bottom, Interval, Join, JoinInto, JoinLattice};
15
16// ============================================================================
17// Disassembly Context
18// ============================================================================
19
20#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
21pub struct IntervalStack<T: PartialEq> {
22    // The lower segment of an abstract stack represents a variable
23    // number of unknown values.  An interval is used for a compact
24    // representation.  So, for example, `0..1` represents two
25    // possible lower segments: `[]` and `[??]`.
26    lower: Interval<usize>,
27    // The upper segment represents zero or more concrete values on
28    // the stack.
29    upper: Vec<T>,
30}
31
32impl<T> IntervalStack<T>
33where
34    T: PartialEq + Clone + JoinLattice,
35{
36    pub fn new(lower: impl Into<Interval<usize>>, upper: Vec<T>) -> Self {
37        let lower_iv = lower.into();
38        // Done
39        Self {
40            lower: lower_iv,
41            upper,
42        }
43    }
44    /// Construct an empty stack.
45    pub fn empty() -> Self {
46        Self::new(0, Vec::new())
47    }
48    /// Determine possible lengths of the stack as an interval
49    pub fn len(&self) -> Interval<usize> {
50        self.lower.add(self.upper.len().into())
51    }
52    /// Peek nth item on the stack (where `0` is top).
53    pub fn peek(&self, n: usize) -> T {
54        // Should never be called on bottom
55        assert!(self != &Self::BOTTOM);
56        // Get the nth value!
57        if n < self.upper.len() {
58            // Determine stack index
59            let i = self.upper.len() - (1 + n);
60            // Extract value
61            self.upper[i].clone()
62        } else {
63            T::TOP
64        }
65    }
66    /// Push an iterm onto this stack.
67    pub fn push(&mut self, val: T) -> &mut Self {
68        // Should never be called on bottom
69        assert!(self != &Self::BOTTOM);
70        //
71        if val == T::TOP && self.upper.is_empty() {
72            self.lower = self.lower.add(1.into());
73        } else {
74            // Pop target address off the stack.
75            self.upper.push(val);
76        }
77        self
78    }
79    // Pop a single item off the stack
80    pub fn pop(&mut self) -> &mut Self {
81        // Should never be called on bottom
82        assert!(self != &Self::BOTTOM);
83        // Pop target address off the stack.
84        if self.upper.is_empty() {
85            self.lower = self.lower.sub(1.into());
86        } else {
87            self.upper.pop();
88        }
89        self
90    }
91
92    /// Determine the minimum length of any stack represented by this
93    /// abstract stack.
94    pub fn min_len(&self) -> usize {
95        self.lower.start + self.upper.len()
96    }
97    /// Determine the maximum length of any stack represented by this
98    /// abstract stack.
99    pub fn max_len(&self) -> usize {
100        self.lower.end + self.upper.len()
101    }
102    /// Access the array of concrete values represented by this stack
103    /// (i.e. the _upper_ portion of the stack).
104    pub fn values(&self) -> &[T] {
105        &self.upper
106    }
107
108    /// Set `ith` item from the top on this stack.  Thus, `0` is the
109    /// top of the stack, etc.
110    pub fn set(mut self, n: usize, val: T) -> Self {
111        // Should never be called on bottom
112        assert!(self != Self::BOTTOM);
113        // NOTE: inefficient when putting unknown value into lower
114        // portion.
115        self.ensure_upper(n + 1);
116        // Determine stack index
117        let i = self.upper.len() - (1 + n);
118        // Set value
119        self.upper[i] = val;
120        // Rebalance (which can be necessary is val unknown)
121        self.rebalance()
122    }
123
124    /// Join two abstract stacks together.
125    pub fn join(self, other: &IntervalStack<T>) -> Self {
126        let slen = self.upper.len();
127        let olen = other.upper.len();
128        // Determine common upper length
129        let n = cmp::min(slen, olen);
130        // Normalise lower segments
131        let lself = self.lower.add(Interval::from(slen - n));
132        let lother = other.lower.add(Interval::from(olen - n));
133        let mut merger = IntervalStack::new(lself.union(&lother), Vec::new());
134        // Push merged items from upper segment
135        for i in (0..n).rev() {
136            let ithself = self.peek(i);
137            let ithother = other.peek(i);
138            merger.push(ithself.join(&ithother));
139        }
140        // Done
141        merger
142    }
143
144    /// Rebalance the stack if necessary.  This is necessary when the
145    /// upper portion contains unknown values which can be shifted
146    /// into the lower portion.
147    fn rebalance(mut self) -> Self {
148        let mut i = 0;
149        // Determine whether any rebalancing necessary.
150        while i < self.upper.len() {
151            if self.upper[i] != T::TOP {
152                break;
153            }
154            i += 1;
155        }
156        // Rebalance only if necessary
157        if i > 0 {
158            // Increase lower portion
159            self.lower = self.lower.add(i.into());
160            // Decrease upper portion
161            self.upper.drain(0..i);
162        }
163        //
164        self
165    }
166
167    /// Ensure the upper portion has space for at least `n` elements.
168    fn ensure_upper(&mut self, n: usize) {
169        // FIXME: inefficient!!
170        while n > self.upper.len() {
171            self.upper.insert(0, T::TOP);
172            self.lower = self.lower.sub(1.into());
173        }
174    }
175}
176
177// ==================================================================
178// Standard Traits
179// ==================================================================
180
181impl<T: PartialEq + Clone + JoinLattice> Default for IntervalStack<T> {
182    fn default() -> Self {
183        Self::empty()
184    }
185}
186
187impl<T> Clone for IntervalStack<T>
188where
189    T: PartialEq + Clone,
190{
191    fn clone(&self) -> Self {
192        IntervalStack {
193            lower: self.lower,
194            upper: self.upper.clone(),
195        }
196    }
197}
198
199impl<T> Display for IntervalStack<T>
200where
201    T: Clone + Display + PartialEq + Bottom,
202{
203    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
204        if self == &Self::BOTTOM {
205            write!(f, "_|_")
206        } else {
207            write!(f, "({})[", self.lower)?;
208            for i in 0..self.upper.len() {
209                write!(f, "{}", self.upper[i])?;
210            }
211            write!(f, "]")
212        }
213    }
214}
215
216// ==================================================================
217// Lattice Traits
218// ==================================================================
219
220impl<T> Bottom for IntervalStack<T>
221where
222    T: PartialEq + Clone + Bottom,
223{
224    const BOTTOM: Self = Self {
225        lower: Interval::BOTTOM,
226        upper: Vec::new(),
227    };
228}
229
230impl<T> JoinInto for IntervalStack<T>
231where
232    T: PartialEq + Clone + JoinLattice,
233{
234    /// Merge an abstract stack into this stack, whilst reporting
235    /// whether this stack changed or not.
236    fn join_into(&mut self, other: &IntervalStack<T>) -> bool {
237        // NOTE: this could be done more efficiently.
238        let old = self.clone();
239        let mut tmp = Self::empty();
240        // Install dummy value to keep self alive
241        mem::swap(self, &mut tmp);
242        // Perform merge
243        *self = tmp.join(other);
244        // Check for change
245        *self != old
246    }
247}