wasm/execution/
value_stack.rs1use alloc::vec::{Drain, Vec};
2
3use crate::core::indices::{FuncIdx, 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 = 0xf1000; const MAX_CALL_STACK_SIZE: usize = 0xff; #[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 fn drop_value(&mut self) {
39 debug_assert!(
44 if !self.frames.is_empty() {
45 self.values.len() > self.current_stackframe().value_stack_base_idx
46 } else {
47 true
48 },
49 "can not pop values past the current stackframe"
50 );
51
52 self.values.pop().unwrap_validated();
53 }
54
55 pub fn pop_unknown_ref(&mut self) -> Ref {
57 debug_assert!(
62 if !self.frames.is_empty() {
63 self.values.len() > self.current_stackframe().value_stack_base_idx
64 } else {
65 true
66 },
67 "can not pop values past the current stackframe"
68 );
69
70 let popped = self.values.pop().unwrap_validated();
71 match popped.to_ty() {
72 ValType::RefType(_) => match popped {
73 Value::Ref(rref) => rref,
74 _ => unreachable!(),
75 },
76 _ => unreachable_validated!(),
77 }
78 }
79
80 pub fn pop_value(&mut self, ty: ValType) -> Value {
82 debug_assert!(
87 if !self.frames.is_empty() {
88 self.values.len() > self.current_stackframe().value_stack_base_idx
89 } else {
90 true
91 },
92 "can not pop values past the current stackframe"
93 );
94
95 let popped = self.values.pop().unwrap_validated();
96 if popped.to_ty() == ty {
97 popped
98 } else {
99 unreachable_validated!()
100 }
101 }
102
103 pub fn pop_value_with_unknown_type(&mut self) -> Value {
105 self.values.pop().unwrap_validated()
106 }
107
108 pub fn peek_value(&self, ty: ValType) -> Value {
110 let value = self.values.last().unwrap_validated();
111 if value.to_ty() == ty {
112 *value
113 } else {
114 unreachable_validated!()
115 }
116 }
117
118 pub fn peek_unknown_value(&self) -> Option<Value> {
120 self.values.last().copied()
121 }
122
123 pub fn push_value(&mut self, value: Value) -> Result<(), RuntimeError> {
125 if self.values.len() > MAX_VALUE_STACK_SIZE {
127 return Err(RuntimeError::StackExhaustion);
128 }
129
130 self.values.push(value);
132
133 Ok(())
134 }
135
136 pub fn get_local(&mut self, idx: LocalIdx) -> Result<(), RuntimeError> {
138 let local_value = self.frames.last().unwrap_validated().locals.get(idx);
139 self.push_value(*local_value)
140 }
141
142 pub fn set_local(&mut self, idx: LocalIdx) {
144 debug_assert!(
145 self.values.len() > self.current_stackframe().value_stack_base_idx,
146 "can not pop values past the current stackframe"
147 );
148
149 let local_ty = self.current_stackframe().locals.get_ty(idx);
150 let stack_value = self.pop_value(local_ty);
151
152 trace!("Instruction: local.set [{stack_value:?}] -> []");
153 *self.current_stackframe_mut().locals.get_mut(idx) = stack_value;
154 }
155
156 pub fn tee_local(&mut self, idx: LocalIdx) {
158 let local_ty = self.current_stackframe().locals.get_ty(idx);
159 let stack_value = self.peek_value(local_ty);
160
161 trace!("Instruction: local.tee [{stack_value:?}] -> []");
162 *self.current_stackframe_mut().locals.get_mut(idx) = stack_value;
163 }
164
165 pub fn current_stackframe(&self) -> &CallFrame {
167 self.frames.last().unwrap_validated()
168 }
169
170 pub fn current_stackframe_mut(&mut self) -> &mut CallFrame {
172 self.frames.last_mut().unwrap_validated()
173 }
174
175 pub fn pop_stackframe(&mut self) -> (usize, usize, usize) {
177 let CallFrame {
178 module_idx,
179 return_addr,
180 value_stack_base_idx,
181 return_value_count,
182 return_stp,
183 ..
184 } = self.frames.pop().unwrap_validated();
185
186 let truncation_top = self.values.len() - return_value_count;
187 let _ = self.values.drain(value_stack_base_idx..truncation_top);
188
189 debug_assert_eq!(
190 self.values.len(),
191 value_stack_base_idx + return_value_count,
192 "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"
193 );
194
195 (module_idx, return_addr, return_stp)
196 }
197
198 pub fn push_stackframe(
202 &mut self,
203 return_module_idx: usize,
204 func_idx: FuncIdx,
205 func_ty: &FuncType,
206 locals: Locals,
207 return_addr: usize,
208 return_stp: usize,
209 ) -> Result<(), RuntimeError> {
210 if self.frames.len() > MAX_CALL_STACK_SIZE {
212 return Err(RuntimeError::StackExhaustion);
213 }
214
215 self.frames.push(CallFrame {
216 module_idx: return_module_idx,
217 func_idx,
218 locals,
219 return_addr,
220 value_stack_base_idx: self.values.len(),
221 return_value_count: func_ty.returns.valtypes.len(),
222 return_stp,
223 });
224
225 Ok(())
226 }
227
228 pub fn callframe_count(&self) -> usize {
230 self.frames.len()
231 }
232
233 pub fn pop_tail_iter(&mut self, n: usize) -> Drain<Value> {
239 let start = self.values.len() - n;
240 self.values.drain(start..)
241 }
242
243 pub fn pop_n_values(&mut self, n: usize) {
245 self.values.truncate(self.values.len() - n);
246 }
247}
248
249pub(crate) struct CallFrame {
251 pub module_idx: usize,
254
255 pub func_idx: FuncIdx,
257
258 pub locals: Locals,
260
261 pub return_addr: usize,
263
264 pub value_stack_base_idx: usize,
266
267 pub return_value_count: usize,
269
270 pub return_stp: usize,
272}