1use alloc::{sync::Arc, vec::Vec};
2
3use miden_core::{mast::MastNodeId, program::Program};
4use miden_mast_package::debug_info::{DebugSourceNodeId, PackageDebugInfo};
5
6const CONTINUATION_STACK_SIZE_HINT: usize = 64;
8
9#[derive(Debug, Clone)]
22pub enum Continuation<F> {
23 StartNode(MastNodeId),
25 FinishJoin(MastNodeId),
27 FinishSplit(MastNodeId),
29 FinishLoop(MastNodeId),
36 FinishCall(MastNodeId),
38 FinishDyn(MastNodeId),
40 ResumeBasicBlock {
43 node_id: MastNodeId,
44 batch_index: usize,
45 op_idx_in_batch: usize,
46 },
47 Respan { node_id: MastNodeId, batch_index: usize },
50 FinishBasicBlock(MastNodeId),
54 EnterForest {
59 forest: F,
60 package_debug_info: Option<Arc<PackageDebugInfo>>,
61 },
62}
63
64impl<F> Continuation<F> {
65 pub fn increments_clk(&self) -> bool {
68 use Continuation::*;
69
70 match self {
74 StartNode(_)
75 | FinishJoin(_)
76 | FinishSplit(_)
77 | FinishLoop(_)
78 | FinishCall(_)
79 | FinishDyn(_)
80 | ResumeBasicBlock {
81 node_id: _,
82 batch_index: _,
83 op_idx_in_batch: _,
84 }
85 | Respan { node_id: _, batch_index: _ }
86 | FinishBasicBlock(_) => true,
87
88 EnterForest { .. } => false,
89 }
90 }
91
92 pub fn exec_node(&self) -> Option<MastNodeId> {
93 match self {
94 Self::StartNode(node_id)
95 | Self::FinishJoin(node_id)
96 | Self::FinishSplit(node_id)
97 | Self::FinishLoop(node_id)
98 | Self::FinishCall(node_id)
99 | Self::FinishDyn(node_id)
100 | Self::ResumeBasicBlock { node_id, .. }
101 | Self::Respan { node_id, .. }
102 | Self::FinishBasicBlock(node_id) => Some(*node_id),
103 Self::EnterForest { .. } => None,
104 }
105 }
106}
107
108#[derive(Debug, Clone)]
118pub struct ContinuationStack<F> {
119 stack: Vec<Continuation<F>>,
120 source_node_ids: Option<Vec<Option<DebugSourceNodeId>>>,
121}
122
123impl<F> Default for ContinuationStack<F> {
124 fn default() -> Self {
125 Self { stack: Vec::new(), source_node_ids: None }
126 }
127}
128
129impl<F> ContinuationStack<F> {
130 pub fn new(program: &Program) -> Self {
135 let mut stack = Vec::with_capacity(CONTINUATION_STACK_SIZE_HINT);
136 stack.push(Continuation::StartNode(program.entrypoint()));
137
138 Self { stack, source_node_ids: None }
139 }
140
141 pub(crate) fn new_with_source_node_id(
142 program: &Program,
143 source_node_id: DebugSourceNodeId,
144 ) -> Self {
145 Self::new_with_optional_source_node_id(program, Some(source_node_id))
146 }
147
148 pub(crate) fn new_with_optional_source_node_id(
149 program: &Program,
150 source_node_id: Option<DebugSourceNodeId>,
151 ) -> Self {
152 let mut stack = Vec::with_capacity(CONTINUATION_STACK_SIZE_HINT);
153 stack.push(Continuation::StartNode(program.entrypoint()));
154
155 let mut source_node_ids = Vec::with_capacity(CONTINUATION_STACK_SIZE_HINT);
156 source_node_ids.push(source_node_id);
157
158 Self {
159 stack,
160 source_node_ids: Some(source_node_ids),
161 }
162 }
163
164 pub fn push_continuation(&mut self, continuation: Continuation<F>) {
169 self.stack.push(continuation);
170 self.push_source_node_id(None);
171 }
172
173 pub(crate) fn push_with_source_node_id(
174 &mut self,
175 continuation: Continuation<F>,
176 source_node_id: Option<DebugSourceNodeId>,
177 ) {
178 self.stack.push(continuation);
179 self.push_source_node_id(source_node_id);
180 }
181
182 pub fn push_enter_forest(&mut self, forest: F) {
187 self.push_enter_forest_with_package_debug_info(forest, None);
188 }
189
190 pub(crate) fn push_enter_forest_with_package_debug_info(
191 &mut self,
192 forest: F,
193 package_debug_info: Option<Arc<PackageDebugInfo>>,
194 ) {
195 self.stack.push(Continuation::EnterForest { forest, package_debug_info });
196 self.push_source_node_id(None);
197 }
198
199 pub fn push_finish_join(&mut self, node_id: MastNodeId) {
201 self.stack.push(Continuation::FinishJoin(node_id));
202 self.push_source_node_id(None);
203 }
204
205 pub fn push_finish_split(&mut self, node_id: MastNodeId) {
207 self.stack.push(Continuation::FinishSplit(node_id));
208 self.push_source_node_id(None);
209 }
210
211 pub fn push_finish_loop(&mut self, node_id: MastNodeId) {
213 self.stack.push(Continuation::FinishLoop(node_id));
214 self.push_source_node_id(None);
215 }
216
217 pub fn push_finish_call(&mut self, node_id: MastNodeId) {
219 self.stack.push(Continuation::FinishCall(node_id));
220 self.push_source_node_id(None);
221 }
222
223 pub fn push_finish_dyn(&mut self, node_id: MastNodeId) {
225 self.stack.push(Continuation::FinishDyn(node_id));
226 self.push_source_node_id(None);
227 }
228
229 pub fn push_start_node(&mut self, node_id: MastNodeId) {
234 self.stack.push(Continuation::StartNode(node_id));
235 self.push_source_node_id(None);
236 }
237
238 pub fn pop_continuation(&mut self) -> Option<Continuation<F>> {
241 let continuation = self.stack.pop()?;
242 if let Some(source_node_ids) = &mut self.source_node_ids {
243 source_node_ids.pop();
244 }
245 Some(continuation)
246 }
247
248 pub(crate) fn pop_continuation_with_source_node_id(
249 &mut self,
250 ) -> Option<(Continuation<F>, Option<DebugSourceNodeId>)> {
251 let continuation = self.stack.pop()?;
252 let source_node_id = self.source_node_ids.as_mut().and_then(Vec::pop).flatten();
253 Some((continuation, source_node_id))
254 }
255
256 pub fn into_inner(self) -> Vec<Continuation<F>> {
259 self.stack
260 }
261
262 fn push_source_node_id(&mut self, source_node_id: Option<DebugSourceNodeId>) {
263 if let Some(source_node_ids) = &mut self.source_node_ids {
264 source_node_ids.push(source_node_id);
265 }
266 }
267
268 pub(crate) fn start_tracking_source_nodes(
269 &mut self,
270 next_source_node_id: Option<DebugSourceNodeId>,
271 ) {
272 let mut source_node_ids = Vec::with_capacity(self.stack.len());
273 source_node_ids.resize(self.stack.len(), None);
274 if let Some(source_node_id) = source_node_ids.last_mut() {
275 *source_node_id = next_source_node_id;
276 }
277 self.source_node_ids = Some(source_node_ids);
278 }
279
280 pub fn len(&self) -> usize {
285 self.stack.len()
286 }
287
288 pub fn peek_continuation(&self) -> Option<&Continuation<F>> {
294 self.stack.last()
295 }
296
297 pub(crate) fn peek_continuation_with_source_node_id(
298 &self,
299 ) -> Option<(&Continuation<F>, Option<DebugSourceNodeId>)> {
300 let continuation = self.stack.last()?;
301 let source_node_id = self
302 .source_node_ids
303 .as_ref()
304 .and_then(|source_node_ids| source_node_ids.last().copied().flatten());
305 Some((continuation, source_node_id))
306 }
307
308 pub(crate) fn tracks_source_nodes(&self) -> bool {
309 self.source_node_ids.is_some()
310 }
311
312 pub fn iter_continuations_for_next_clock(&self) -> impl Iterator<Item = &Continuation<F>> {
324 let mut found_incrementing_cont = false;
325
326 self.stack.iter().rev().take_while(move |continuation| {
327 if found_incrementing_cont {
328 false
330 } else if continuation.increments_clk() {
331 found_incrementing_cont = true;
333 true
334 } else {
335 true
337 }
338 })
339 }
340
341 pub fn iter_continuations_for_next_clock_with_source_node_ids(
344 &self,
345 ) -> impl Iterator<Item = (&Continuation<F>, Option<DebugSourceNodeId>)> {
346 let mut stack_index = self.stack.len().saturating_sub(1);
347
348 self.iter_continuations_for_next_clock().map(move |cont| {
349 let source_node_id = self
350 .source_node_ids
351 .as_deref()
352 .and_then(|ids| ids.get(stack_index).copied())
353 .flatten();
354 stack_index = stack_index.saturating_sub(1);
355 (cont, source_node_id)
356 })
357 }
358}
359
360#[cfg(test)]
364mod tests {
365 use alloc::sync::Arc;
366
367 use miden_core::mast::MastForest;
368
369 use super::*;
370
371 #[test]
372 fn get_next_clock_cycle_increment_empty_stack() {
373 let stack: ContinuationStack<Arc<MastForest>> = ContinuationStack::default();
374 assert!(stack.iter_continuations_for_next_clock().next().is_none());
375 }
376
377 #[test]
378 fn get_next_clock_cycle_increment_ends_with_incrementing() {
379 let mut stack: ContinuationStack<Arc<MastForest>> = ContinuationStack::default();
380 stack.push_continuation(Continuation::StartNode(MastNodeId::new_unchecked(0)));
382
383 let result: Vec<_> = stack.iter_continuations_for_next_clock().collect();
384 assert_eq!(result.len(), 1);
385 assert!(matches!(result[0], Continuation::StartNode(_)));
386 }
387
388 #[test]
389 fn get_next_clock_cycle_increment_enter_forest_after_incrementing() {
390 let mut stack: ContinuationStack<Arc<MastForest>> = ContinuationStack::default();
391 stack.push_continuation(Continuation::StartNode(MastNodeId::new_unchecked(0)));
393 stack.push_continuation(Continuation::EnterForest {
395 forest: Arc::new(MastForest::new()),
396 package_debug_info: None,
397 });
398
399 let result: Vec<_> = stack.iter_continuations_for_next_clock().collect();
400 assert_eq!(result.len(), 2);
402 assert!(matches!(result[0], Continuation::EnterForest { .. }));
403 assert!(matches!(result[1], Continuation::StartNode(_)));
404 }
405
406 #[test]
407 fn get_next_clock_cycle_increment_multiple_enter_forest_after_incrementing() {
408 let mut stack: ContinuationStack<Arc<MastForest>> = ContinuationStack::default();
409 stack.push_continuation(Continuation::StartNode(MastNodeId::new_unchecked(0)));
411 stack.push_continuation(Continuation::EnterForest {
413 forest: Arc::new(MastForest::new()),
414 package_debug_info: None,
415 });
416 stack.push_continuation(Continuation::EnterForest {
417 forest: Arc::new(MastForest::new()),
418 package_debug_info: None,
419 });
420
421 let result: Vec<_> = stack.iter_continuations_for_next_clock().collect();
422 assert_eq!(result.len(), 3);
424 assert!(matches!(result[0], Continuation::EnterForest { .. }));
425 assert!(matches!(result[1], Continuation::EnterForest { .. }));
426 assert!(matches!(result[2], Continuation::StartNode(_)));
427 }
428}