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::locals::Locals;
8use crate::{unreachable_validated, RuntimeError};
9
10use super::value::Ref;
11
12const MAX_VALUE_STACK_SIZE: usize = 0xf0000; const MAX_CALL_STACK_SIZE: usize = 0x1000; #[derive(Default)]
23pub(crate) struct Stack {
24 values: Vec<Value>,
26
27 frames: Vec<CallFrame>,
31}
32
33impl Stack {
34 pub fn new() -> Self {
35 Self::default()
36 }
37
38 pub(super) fn into_values(self) -> Vec<Value> {
39 self.values
40 }
41
42 pub fn drop_value(&mut self) {
43 debug_assert!(
48 if !self.frames.is_empty() {
49 self.values.len() > self.current_stackframe().value_stack_base_idx
50 } else {
51 true
52 },
53 "can not pop values past the current stackframe"
54 );
55
56 self.values.pop().unwrap_validated();
57 }
58
59 pub fn pop_unknown_ref(&mut self) -> Ref {
61 debug_assert!(
66 if !self.frames.is_empty() {
67 self.values.len() > self.current_stackframe().value_stack_base_idx
68 } else {
69 true
70 },
71 "can not pop values past the current stackframe"
72 );
73
74 let popped = self.values.pop().unwrap_validated();
75 match popped.to_ty() {
76 ValType::RefType(_) => match popped {
77 Value::Ref(rref) => rref,
78 _ => unreachable!(),
79 },
80 _ => unreachable_validated!(),
81 }
82 }
83
84 pub fn pop_value(&mut self, ty: ValType) -> Value {
86 debug_assert!(
91 if !self.frames.is_empty() {
92 self.values.len() > self.current_stackframe().value_stack_base_idx
93 } else {
94 true
95 },
96 "can not pop values past the current stackframe"
97 );
98
99 let popped = self.values.pop().unwrap_validated();
100 if popped.to_ty() == ty {
101 popped
102 } else {
103 unreachable_validated!()
104 }
105 }
106
107 pub fn pop_value_with_unknown_type(&mut self) -> Value {
109 self.values.pop().unwrap_validated()
110 }
111
112 pub fn peek_value(&self, ty: ValType) -> Value {
114 let value = self.values.last().unwrap_validated();
115 if value.to_ty() == ty {
116 *value
117 } else {
118 unreachable_validated!()
119 }
120 }
121
122 pub fn peek_unknown_value(&self) -> Option<Value> {
124 self.values.last().copied()
125 }
126
127 pub fn push_value(&mut self, value: Value) -> Result<(), RuntimeError> {
129 if self.values.len() > MAX_VALUE_STACK_SIZE {
131 return Err(RuntimeError::StackExhaustion);
132 }
133
134 self.values.push(value);
136
137 Ok(())
138 }
139
140 pub fn get_local(&mut self, idx: LocalIdx) -> Result<(), RuntimeError> {
142 let local_value = self.frames.last().unwrap_validated().locals.get(idx);
143 self.push_value(*local_value)
144 }
145
146 pub fn set_local(&mut self, idx: LocalIdx) {
148 debug_assert!(
149 self.values.len() > self.current_stackframe().value_stack_base_idx,
150 "can not pop values past the current stackframe"
151 );
152
153 let local_ty = self.current_stackframe().locals.get_ty(idx);
154 let stack_value = self.pop_value(local_ty);
155
156 trace!("Instruction: local.set [{stack_value:?}] -> []");
157 *self.current_stackframe_mut().locals.get_mut(idx) = stack_value;
158 }
159
160 pub fn tee_local(&mut self, idx: LocalIdx) {
162 let local_ty = self.current_stackframe().locals.get_ty(idx);
163 let stack_value = self.peek_value(local_ty);
164
165 trace!("Instruction: local.tee [{stack_value:?}] -> []");
166 *self.current_stackframe_mut().locals.get_mut(idx) = stack_value;
167 }
168
169 pub fn current_stackframe(&self) -> &CallFrame {
171 self.frames.last().unwrap_validated()
172 }
173
174 pub fn current_stackframe_mut(&mut self) -> &mut CallFrame {
176 self.frames.last_mut().unwrap_validated()
177 }
178
179 pub fn pop_stackframe(&mut self) -> (usize, usize, usize) {
181 let CallFrame {
182 return_func_addr,
183 return_addr,
184 value_stack_base_idx,
185 return_value_count,
186 return_stp,
187 ..
188 } = self.frames.pop().unwrap_validated();
189
190 let truncation_top = self.values.len() - return_value_count;
191 let _ = self.values.drain(value_stack_base_idx..truncation_top);
192
193 debug_assert_eq!(
194 self.values.len(),
195 value_stack_base_idx + return_value_count,
196 "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"
197 );
198
199 (return_func_addr, return_addr, return_stp)
200 }
201
202 pub fn push_stackframe(
206 &mut self,
207 return_func_addr: usize,
208 func_ty: &FuncType,
209 locals: Locals,
210 return_addr: usize,
211 return_stp: usize,
212 ) -> Result<(), RuntimeError> {
213 if self.frames.len() > MAX_CALL_STACK_SIZE {
215 return Err(RuntimeError::StackExhaustion);
216 }
217
218 self.frames.push(CallFrame {
219 return_func_addr,
220 locals,
221 return_addr,
222 value_stack_base_idx: self.values.len(),
223 return_value_count: func_ty.returns.valtypes.len(),
224 return_stp,
225 });
226
227 Ok(())
228 }
229
230 pub fn callframe_count(&self) -> usize {
232 self.frames.len()
233 }
234
235 pub fn pop_tail_iter(&mut self, n: usize) -> Drain<Value> {
241 let start = self.values.len() - n;
242 self.values.drain(start..)
243 }
244
245 pub fn pop_n_values(&mut self, n: usize) {
247 self.values.truncate(self.values.len() - n);
248 }
249}
250
251pub(crate) struct CallFrame {
253 pub return_func_addr: usize,
255
256 pub locals: Locals,
258
259 pub return_addr: usize,
261
262 pub value_stack_base_idx: usize,
264
265 pub return_value_count: usize,
267
268 pub return_stp: usize,
270}