starlark/eval/bc/
stack_ptr.rs

1/*
2 * Copyright 2019 The Starlark in Rust Authors.
3 * Copyright (c) Facebook, Inc. and its affiliates.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18//! Stack pointer.
19
20use std::ops::Add;
21
22use dupe::Dupe;
23
24/// Index of the slot in the function frame.
25/// This can be both a local variable or a temporary.
26/// When reading local variable, it must be definitely initialized (e.g. function parameter).
27#[derive(
28    Copy,
29    Clone,
30    Dupe,
31    Debug,
32    PartialOrd,
33    Ord,
34    PartialEq,
35    Eq,
36    Hash,
37    derive_more::Display
38)]
39#[display("&{}", _0)]
40pub(crate) struct BcSlot(pub(crate) u32);
41
42impl BcSlot {
43    pub(crate) fn to_in(self) -> BcSlotIn {
44        BcSlotIn(self)
45    }
46
47    pub(crate) fn to_out(self) -> BcSlotOut {
48        BcSlotOut(self)
49    }
50}
51
52impl Add<u32> for BcSlot {
53    type Output = BcSlot;
54
55    #[inline]
56    fn add(self, rhs: u32) -> BcSlot {
57        BcSlot(self.0 + rhs)
58    }
59}
60
61/// `N` slots starting with given number.
62#[derive(Copy, Clone, Dupe, Debug)]
63pub(crate) struct BcSlotsN<const N: usize> {
64    /// `N` slots starting with given slot.
65    pub(crate) start: BcSlot,
66}
67
68impl<const N: usize> BcSlotsN<N> {
69    #[inline]
70    pub(crate) fn get<const I: u32>(self) -> BcSlot {
71        assert!((I as usize) < N);
72        self.start + I
73    }
74
75    pub(crate) fn from_range(range: BcSlotRange) -> BcSlotsN<N> {
76        assert_eq!(N, range.len() as usize);
77        BcSlotsN { start: range.start }
78    }
79}
80
81#[derive(Copy, Clone, Dupe, Debug, derive_more::Display)]
82#[display("{}..{}", start, end)]
83pub(crate) struct BcSlotRange {
84    pub(crate) start: BcSlot,
85    pub(crate) end: BcSlot,
86}
87
88impl BcSlotRange {
89    #[inline]
90    pub(crate) fn len(self) -> u32 {
91        self.end.0 - self.start.0
92    }
93
94    pub(crate) fn iter(self) -> impl Iterator<Item = BcSlot> {
95        (self.start.0..self.end.0).map(BcSlot)
96    }
97
98    pub(crate) fn to_in(self) -> BcSlotInRange {
99        BcSlotInRange {
100            start: self.start.to_in(),
101            end: self.end.to_in(),
102        }
103    }
104}
105
106/// Slot containing a value.
107///
108/// The slot may be a local variable, so this slot cannot be used to store a temporary value.
109#[derive(Debug, Copy, Clone, Dupe, derive_more::Display, PartialEq, Eq)]
110pub(crate) struct BcSlotIn(BcSlot);
111
112impl Add<u32> for BcSlotIn {
113    type Output = BcSlotIn;
114
115    #[inline]
116    fn add(self, rhs: u32) -> BcSlotIn {
117        BcSlotIn(self.0 + rhs)
118    }
119}
120
121impl BcSlotIn {
122    /// Take the slot.
123    ///
124    /// This operation need to be used carefully: this slot cannot be used for writing.
125    #[inline]
126    pub(crate) fn get(self) -> BcSlot {
127        self.0
128    }
129}
130
131#[derive(Copy, Clone, Dupe, Debug, derive_more::Display)]
132#[display("{}..{}", start, end)]
133pub(crate) struct BcSlotInRange {
134    pub(crate) start: BcSlotIn,
135    pub(crate) end: BcSlotIn,
136}
137
138impl Default for BcSlotInRange {
139    fn default() -> Self {
140        BcSlotInRange {
141            start: BcSlotIn(BcSlot(0)),
142            end: BcSlotIn(BcSlot(0)),
143        }
144    }
145}
146
147impl BcSlotInRange {
148    #[inline]
149    pub(crate) fn len(self) -> u32 {
150        self.end.0.0 - self.start.0.0
151    }
152
153    pub(crate) fn to_range_from(self) -> BcSlotInRangeFrom {
154        BcSlotInRangeFrom(self.start)
155    }
156
157    pub(crate) fn iter(self) -> impl Iterator<Item = BcSlotIn> {
158        (self.start.0.0..self.end.0.0).map(|s| BcSlotIn(BcSlot(s)))
159    }
160
161    /// Add an element to the slot range if possible.
162    pub(crate) fn try_push(&mut self, slot: BcSlotIn) -> bool {
163        if self.len() == 0 {
164            *self = BcSlotInRange {
165                start: slot,
166                end: slot + 1,
167            };
168            true
169        } else if self.end == slot {
170            self.end = slot + 1;
171            true
172        } else {
173            false
174        }
175    }
176}
177
178#[derive(Copy, Clone, Dupe, Debug)]
179pub(crate) struct BcSlotInRangeFrom(pub(crate) BcSlotIn);
180
181impl BcSlotInRangeFrom {
182    #[inline]
183    pub(crate) fn to_range(self, len: u32) -> BcSlotInRange {
184        BcSlotInRange {
185            start: self.0,
186            end: self.0 + len,
187        }
188    }
189}
190
191/// Slot where the value should be stored.
192///
193/// The slot may be a local variable, so this slot cannot be used to store a temporary value.
194#[derive(Debug, Copy, Clone, Dupe, derive_more::Display)]
195pub(crate) struct BcSlotOut(BcSlot);
196
197impl BcSlotOut {
198    #[inline]
199    pub(crate) fn get(self) -> BcSlot {
200        self.0
201    }
202}