midenc_debug/exec/
state.rs1use std::collections::{BTreeSet, VecDeque};
2
3use miden_core::Word;
4use miden_processor::{
5 ContextId, ExecutionError, Operation, RowIndex, StackOutputs, VmState, VmStateIterator,
6};
7
8use super::ExecutionTrace;
9use crate::{CallFrame, CallStack, TestFelt};
10
11pub struct DebugExecutor {
18 pub iter: VmStateIterator,
20 pub result: Result<StackOutputs, ExecutionError>,
22 pub contexts: BTreeSet<ContextId>,
24 pub root_context: ContextId,
26 pub current_context: ContextId,
28 pub callstack: CallStack,
30 pub recent: VecDeque<Operation>,
32 pub last: Option<VmState>,
34 pub cycle: usize,
36 pub stopped: bool,
38}
39
40impl DebugExecutor {
41 pub fn step(&mut self) -> Result<Option<CallFrame>, ExecutionError> {
48 if self.stopped {
49 return self.result.as_ref().map(|_| None).map_err(|err| err.clone());
50 }
51 match self.iter.next() {
52 Some(Ok(state)) => {
53 self.cycle += 1;
54 if self.current_context != state.ctx {
55 self.contexts.insert(state.ctx);
56 self.current_context = state.ctx;
57 }
58
59 if let Some(op) = state.op {
60 if self.recent.len() == 5 {
61 self.recent.pop_front();
62 }
63 self.recent.push_back(op);
64 }
65
66 let exited = self.callstack.next(&state);
67
68 self.last = Some(state);
69
70 Ok(exited)
71 }
72 Some(Err(err)) => {
73 self.stopped = true;
74 Err(err)
75 }
76 None => {
77 self.stopped = true;
78 Ok(None)
79 }
80 }
81 }
82
83 pub fn into_execution_trace(self) -> ExecutionTrace {
85 let last_cycle = self.cycle;
86 let trace_len_summary = *self.iter.trace_len_summary();
87 let (_, _, _, chiplets, _) = self.iter.into_parts();
88 let outputs = self.result.unwrap_or_default();
89 ExecutionTrace {
90 root_context: self.root_context,
91 last_cycle: RowIndex::from(last_cycle),
92 chiplets: Chiplets::new(move |context, clk| chiplets.get_mem_state_at(context, clk)),
93 outputs,
94 trace_len_summary,
95 }
96 }
97}
98impl core::iter::FusedIterator for DebugExecutor {}
99impl Iterator for DebugExecutor {
100 type Item = Result<VmState, ExecutionError>;
101
102 #[inline]
103 fn next(&mut self) -> Option<Self::Item> {
104 if self.stopped {
105 return None;
106 }
107 match self.step() {
108 Ok(_) => self.last.clone().map(Ok),
109 Err(err) => Some(Err(err)),
110 }
111 }
112}
113
114#[allow(clippy::type_complexity)]
116pub struct Chiplets(Box<dyn Fn(ContextId, RowIndex) -> Vec<(u64, Word)>>);
117impl Chiplets {
118 pub fn new<F>(callback: F) -> Self
119 where
120 F: Fn(ContextId, RowIndex) -> Vec<(u64, Word)> + 'static,
121 {
122 Self(Box::new(callback))
123 }
124
125 pub fn get_mem_state_at(&self, context: ContextId, clk: RowIndex) -> Vec<(u64, Word)> {
126 (self.0)(context, clk)
127 }
128}