go_vm/
stack.rs

1// Copyright 2022 The Goscript Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5use crate::value::*;
6
7const DEFAULT_CAPACITY: usize = 256;
8
9pub struct Stack {
10    vec: Vec<GosValue>,
11}
12
13impl Stack {
14    #[inline]
15    pub fn new() -> Stack {
16        Stack {
17            vec: vec![GosValue::new_nil(ValueType::Void); DEFAULT_CAPACITY],
18        }
19    }
20
21    #[inline]
22    pub fn with_vec(v: Vec<GosValue>) -> Stack {
23        let mut s = Stack { vec: v };
24        s.set_min_size(DEFAULT_CAPACITY);
25        s
26    }
27
28    #[inline]
29    pub fn get(&self, index: OpIndex) -> &GosValue {
30        unsafe { self.vec.get_unchecked(index as usize) }
31    }
32
33    #[inline]
34    pub fn get_mut(&mut self, index: OpIndex) -> &mut GosValue {
35        unsafe { self.vec.get_unchecked_mut(index as usize) }
36    }
37
38    #[inline]
39    pub fn set(&mut self, index: OpIndex, val: GosValue) {
40        *self.get_mut(index) = val;
41    }
42
43    #[inline]
44    pub fn read<'a>(&'a self, i: OpIndex, sb: OpIndex, consts: &'a [GosValue]) -> &'a GosValue {
45        if i >= 0 {
46            &self.get(i + sb)
47        } else {
48            &consts[(-i - 1) as usize]
49        }
50    }
51
52    #[inline]
53    pub(crate) fn read_and_op(
54        &self,
55        lhs: &ValueData,
56        t: ValueType,
57        op: Opcode,
58        rhs: OpIndex,
59        sb: OpIndex,
60        consts: &[GosValue],
61    ) -> GosValue {
62        let d = match op {
63            Opcode::INC => lhs.inc(t),
64            Opcode::DEC => lhs.dec(t),
65            Opcode::ADD => lhs.binary_op_add(self.read(rhs, sb, consts).data(), t),
66            Opcode::SUB => lhs.binary_op_sub(self.read(rhs, sb, consts).data(), t),
67            Opcode::MUL => lhs.binary_op_mul(self.read(rhs, sb, consts).data(), t),
68            Opcode::QUO => lhs.binary_op_quo(self.read(rhs, sb, consts).data(), t),
69            Opcode::REM => lhs.binary_op_rem(self.read(rhs, sb, consts).data(), t),
70            Opcode::AND => lhs.binary_op_and(self.read(rhs, sb, consts).data(), t),
71            Opcode::OR => lhs.binary_op_or(self.read(rhs, sb, consts).data(), t),
72            Opcode::XOR => lhs.binary_op_xor(self.read(rhs, sb, consts).data(), t),
73            Opcode::AND_NOT => lhs.binary_op_and_not(self.read(rhs, sb, consts).data(), t),
74            Opcode::SHL => lhs.binary_op_shl(self.read(rhs, sb, consts).data().as_uint32(), t),
75            Opcode::SHR => lhs.binary_op_shr(self.read(rhs, sb, consts).data().as_uint32(), t),
76            _ => {
77                dbg!(op);
78                unreachable!();
79            }
80        };
81        GosValue::new(t, d)
82    }
83
84    #[inline]
85    pub fn set_min_size(&mut self, size: usize) {
86        if size > self.vec.len() {
87            self.vec.resize(size, GosValue::new_nil(ValueType::Void))
88        }
89    }
90
91    #[inline]
92    pub fn set_vec(&mut self, index: OpIndex, mut vec: Vec<GosValue>) {
93        let begin = index as usize;
94        let new_len = begin + vec.len();
95        self.set_min_size(new_len);
96        self.vec[begin..new_len].swap_with_slice(&mut vec);
97    }
98
99    #[inline]
100    pub fn move_vec(&mut self, begin: OpIndex, end: OpIndex) -> Vec<GosValue> {
101        let b = begin as usize;
102        let e = end as usize;
103        let mut defaults = vec![GosValue::new_nil(ValueType::Void); e - b];
104        self.vec[b..e].swap_with_slice(&mut defaults[..]);
105        defaults
106    }
107
108    #[inline]
109    pub fn get_bool(&mut self, index: OpIndex) -> bool {
110        *self.get_data(index).as_bool()
111    }
112
113    #[inline]
114    pub fn set_bool(&mut self, index: OpIndex, b: bool) {
115        *self.get_data_mut(index) = ValueData::new_bool(b);
116    }
117
118    #[inline]
119    pub fn get_int(&mut self, index: OpIndex) -> isize {
120        *self.get_data(index).as_int()
121    }
122
123    #[inline]
124    pub fn set_int(&mut self, index: OpIndex, i: isize) {
125        *self.get_data_mut(index) = ValueData::new_int(i);
126    }
127
128    #[inline]
129    pub(crate) fn get_data(&self, index: OpIndex) -> &ValueData {
130        self.get(index).data()
131    }
132
133    #[inline]
134    pub(crate) fn get_data_mut(&mut self, index: OpIndex) -> &mut ValueData {
135        unsafe { self.get_mut(index).data_mut() }
136    }
137}
138
139impl std::fmt::Debug for Stack {
140    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
141        write!(f, "{:#?}", &self.vec[..16])
142    }
143}
144
145/// store iterators for Opcode::RANGE
146pub struct RangeStack {
147    maps: Vec<GosMapIter<'static>>,
148    slices: Vec<SliceEnumIter<'static, AnyElem>>,
149    strings: Vec<StringEnumIter<'static>>,
150}
151
152impl RangeStack {
153    pub fn new() -> RangeStack {
154        RangeStack {
155            maps: vec![],
156            slices: vec![],
157            strings: vec![],
158        }
159    }
160
161    /// range_init creates iters and transmute them to 'static, then save them on stacks.
162    /// it's safe because they are held only during 'ranging', which can never be longer
163    /// than their real lifetime
164    ///
165    /// But it's not rust-safe just go-safe. because the Ref is dropped inside the transmute.
166    /// that means if you write to the container we are ranging, it'll not be stopped by
167    /// the borrow checker. Which is not safe to Rust, but it's exactly what Go does.
168    pub(crate) fn range_init(
169        &mut self,
170        target: &GosValue,
171        typ: ValueType,
172        arr_caller: &Box<dyn Dispatcher>,
173    ) -> RuntimeResult<()> {
174        match typ {
175            ValueType::Map => {
176                let map = target.as_non_nil_map()?.0.borrow_data();
177                let iter = unsafe { std::mem::transmute(map.iter()) };
178                self.maps.push(iter);
179            }
180            ValueType::Array | ValueType::Slice => {
181                let iter = arr_caller.array_slice_iter(&target)?;
182                self.slices.push(iter);
183            }
184            ValueType::String => {
185                let iter =
186                    unsafe { std::mem::transmute(target.as_string().as_str().chars().enumerate()) };
187                self.strings.push(iter);
188            }
189            _ => unreachable!(),
190        }
191        Ok(())
192    }
193
194    pub(crate) fn range_body(
195        &mut self,
196        typ: ValueType,
197        arr_caller: &Box<dyn Dispatcher>,
198        stack: &mut Stack,
199        index_key: OpIndex,
200        index_val: OpIndex,
201    ) -> bool {
202        match typ {
203            ValueType::Map => match self.maps.last_mut().unwrap().next() {
204                Some((k, v)) => {
205                    stack.set(index_key, k.clone());
206                    stack.set(index_val, v.clone());
207                    false
208                }
209                None => {
210                    self.maps.pop();
211                    true
212                }
213            },
214            ValueType::Array | ValueType::Slice => {
215                match arr_caller.array_slice_next(self.slices.last_mut().unwrap()) {
216                    Some((k, v)) => {
217                        stack.set(index_key, (k as isize).into());
218                        stack.set(index_val, v);
219                        false
220                    }
221                    None => {
222                        self.slices.pop();
223                        true
224                    }
225                }
226            }
227            ValueType::String => match self.strings.last_mut().unwrap().next() {
228                Some((k, v)) => {
229                    stack.set(index_key, (k as isize).into());
230                    stack.set(index_val, (v as isize).into());
231                    false
232                }
233                None => {
234                    self.strings.pop();
235                    true
236                }
237            },
238            _ => unreachable!(),
239        }
240    }
241}