wasm/execution/
value_stack.rs1use alloc::vec::{Drain, Vec};
2
3use crate::core::indices::LocalIdx;
4use crate::core::reader::types::{FuncType, ValType};
5use crate::execution::assert_validated::UnwrapValidatedExt;
6use crate::execution::value::Value;
7use crate::{unreachable_validated, RuntimeError};
8
9use super::value::Ref;
10
11const MAX_VALUE_STACK_SIZE: usize = 0xf0000; const MAX_CALL_STACK_SIZE: usize = 0x1000; #[derive(Default)]
22pub(crate) struct Stack {
23 values: Vec<Value>,
25
26 frames: Vec<CallFrame>,
30}
31
32impl Stack {
33 pub fn new() -> Self {
34 Self::default()
35 }
36
37 pub fn new_with_values(values: Vec<Value>) -> Self {
38 Self {
39 values,
40 ..Self::default()
41 }
42 }
43
44 pub(super) fn into_values(self) -> Vec<Value> {
45 self.values
46 }
47
48 pub fn drop_value(&mut self) {
49 debug_assert!(
54 if !self.frames.is_empty() {
55 self.values.len() > self.current_call_frame().value_stack_base_idx
56 } else {
57 true
58 },
59 "can not pop values past the current call frame"
60 );
61
62 self.values.pop().unwrap_validated();
63 }
64
65 pub fn pop_unknown_ref(&mut self) -> Ref {
67 debug_assert!(
72 if !self.frames.is_empty() {
73 self.values.len() > self.current_call_frame().value_stack_base_idx
74 } else {
75 true
76 },
77 "can not pop values past the current call frame"
78 );
79
80 let popped = self.values.pop().unwrap_validated();
81 match popped.to_ty() {
82 ValType::RefType(_) => match popped {
83 Value::Ref(rref) => rref,
84 _ => unreachable!(),
85 },
86 _ => unreachable_validated!(),
87 }
88 }
89
90 pub fn pop_value(&mut self, ty: ValType) -> Value {
92 debug_assert!(
97 if !self.frames.is_empty() {
98 self.values.len() > self.current_call_frame().value_stack_base_idx
99 } else {
100 true
101 },
102 "can not pop values past the current call frame"
103 );
104
105 let popped = self.values.pop().unwrap_validated();
106 if popped.to_ty() == ty {
107 popped
108 } else {
109 unreachable_validated!()
110 }
111 }
112
113 pub fn pop_value_with_unknown_type(&mut self) -> Value {
115 self.values.pop().unwrap_validated()
116 }
117
118 pub fn peek_value(&self, ty: ValType) -> Value {
120 let value = self.values.last().unwrap_validated();
121 if value.to_ty() == ty {
122 *value
123 } else {
124 unreachable_validated!()
125 }
126 }
127
128 pub fn peek_unknown_value(&self) -> Option<Value> {
130 self.values.last().copied()
131 }
132
133 pub fn push_value(&mut self, value: Value) -> Result<(), RuntimeError> {
135 if self.values.len() > MAX_VALUE_STACK_SIZE {
137 return Err(RuntimeError::StackExhaustion);
138 }
139
140 self.values.push(value);
142
143 Ok(())
144 }
145
146 pub fn get_local(&mut self, idx: LocalIdx) -> Result<(), RuntimeError> {
148 let call_frame_base_idx = self.current_call_frame().call_frame_base_idx;
149 let local_value = self
150 .values
151 .get(call_frame_base_idx + idx)
152 .unwrap_validated();
153 self.push_value(*local_value)
154 }
155
156 pub fn set_local(&mut self, idx: LocalIdx) {
158 debug_assert!(
159 self.values.len() > self.current_call_frame().value_stack_base_idx,
160 "can not pop values past the current call frame"
161 );
162
163 let call_frame_base_idx = self.current_call_frame().call_frame_base_idx;
164 let local_ty = self
165 .values
166 .get(call_frame_base_idx + idx)
167 .unwrap_validated()
168 .to_ty();
169 let stack_value = self.pop_value(local_ty);
170
171 trace!("Instruction: local.set [{stack_value:?}] -> []");
172
173 *self
174 .values
175 .get_mut(call_frame_base_idx + idx)
176 .unwrap_validated() = stack_value;
177 }
178
179 pub fn tee_local(&mut self, idx: LocalIdx) {
181 let call_frame_base_idx = self.current_call_frame().call_frame_base_idx;
182
183 let local_ty = self
184 .values
185 .get(call_frame_base_idx + idx)
186 .unwrap_validated()
187 .to_ty();
188 let stack_value = self.peek_value(local_ty);
189
190 trace!("Instruction: local.tee [{stack_value:?}] -> []");
191
192 *self
193 .values
194 .get_mut(call_frame_base_idx + idx)
195 .unwrap_validated() = stack_value;
196 }
197
198 pub fn current_call_frame(&self) -> &CallFrame {
200 self.frames.last().unwrap_validated()
201 }
202
203 pub fn _current_call_frame_mut(&mut self) -> &mut CallFrame {
205 self.frames.last_mut().unwrap_validated()
206 }
207
208 pub fn pop_call_frame(&mut self) -> (usize, usize, usize) {
210 let CallFrame {
211 return_func_addr,
212 return_addr,
213 call_frame_base_idx,
214 return_value_count,
215 return_stp,
216 ..
217 } = self.frames.pop().unwrap_validated();
218
219 let remove_count = self.values.len() - call_frame_base_idx - return_value_count;
220
221 self.remove_inbetween(remove_count, return_value_count);
222
223 debug_assert_eq!(
224 self.values.len(),
225 call_frame_base_idx + return_value_count,
226 "after a function call finished, the stack must have exactly as many values as it had before calling the function plus the number of function return values"
227 );
228
229 (return_func_addr, return_addr, return_stp)
230 }
231
232 pub fn push_call_frame(
236 &mut self,
237 return_func_addr: usize,
238 func_ty: &FuncType,
239 remaining_locals: &[ValType],
240 return_addr: usize,
241 return_stp: usize,
242 ) -> Result<(), RuntimeError> {
243 if self.call_frame_count() > MAX_CALL_STACK_SIZE {
245 return Err(RuntimeError::StackExhaustion);
246 }
247
248 debug_assert!(
249 self.values.len() >= func_ty.params.valtypes.len(),
250 "when pushing a new call frame, at least as many values need to be on the stack as required by the new call frames's function"
251 );
252
253 let param_count = func_ty.params.valtypes.len();
255 let call_frame_base_idx = self.values.len() - param_count;
256
257 for local in remaining_locals {
259 self.values.push(Value::default_from_ty(*local));
260 }
261
262 let value_stack_base_idx = self.values.len();
264
265 self.frames.push(CallFrame {
266 return_func_addr,
267 return_addr,
268 value_stack_base_idx,
269 call_frame_base_idx,
270 return_value_count: func_ty.returns.valtypes.len(),
271 return_stp,
272 });
273
274 Ok(())
275 }
276
277 pub fn call_frame_count(&self) -> usize {
279 self.frames.len()
280 }
281
282 pub fn pop_tail_iter(&mut self, n: usize) -> Drain<'_, Value> {
288 let start = self.values.len() - n;
289 self.values.drain(start..)
290 }
291
292 pub fn remove_inbetween(&mut self, remove_count: usize, keep_count: usize) {
303 let len = self.values.len();
304 self.values
305 .copy_within(len - keep_count.., len - keep_count - remove_count);
306 self.values.truncate(len - remove_count);
307 }
308}
309
310pub(crate) struct CallFrame {
312 pub return_func_addr: usize,
314
315 pub return_addr: usize,
317
318 pub value_stack_base_idx: usize,
326
327 pub call_frame_base_idx: usize,
332
333 pub return_value_count: usize,
335
336 pub return_stp: usize,
338}