Skip to main content

miden_processor/fast/
step.rs

1//! This module defines items relevant to controlling execution stopping conditions.
2
3use alloc::sync::Arc;
4use core::ops::ControlFlow;
5
6use miden_core::{mast::MastForest, program::Kernel};
7
8use crate::{
9    ExecutionError, FastProcessor, Stopper,
10    continuation_stack::{Continuation, ContinuationStack},
11};
12
13// RESUME CONTEXT
14// ===============================================================================================
15
16/// The context required to resume execution of a program from the last point at which it was
17/// stopped.
18#[derive(Debug)]
19pub struct ResumeContext {
20    pub(crate) current_forest: Arc<MastForest>,
21    pub(crate) continuation_stack: ContinuationStack,
22    pub(crate) kernel: Kernel,
23}
24
25impl ResumeContext {
26    /// Returns a reference to the continuation stack.
27    pub fn continuation_stack(&self) -> &ContinuationStack {
28        &self.continuation_stack
29    }
30
31    /// Returns a reference to the MAST forest being currently executed.
32    pub fn current_forest(&self) -> &Arc<MastForest> {
33        &self.current_forest
34    }
35
36    /// Returns a reference to the kernel being currently executed.
37    pub fn kernel(&self) -> &Kernel {
38        &self.kernel
39    }
40}
41
42// STOPPERS
43// ===============================================================================================
44
45/// A [`Stopper`] that never stops execution (except for returning an error when the maximum cycle
46/// count is exceeded).
47pub struct NeverStopper;
48
49impl Stopper for NeverStopper {
50    type Processor = FastProcessor;
51
52    #[inline(always)]
53    fn should_stop(
54        &self,
55        processor: &FastProcessor,
56        continuation_stack: &ContinuationStack,
57        _continuation_after_stop: impl FnOnce() -> Option<Continuation>,
58    ) -> ControlFlow<BreakReason> {
59        check_if_max_cycles_exceeded(processor)?;
60        check_if_continuation_stack_too_large(processor, continuation_stack)
61    }
62}
63
64/// A [`Stopper`] that always stops execution after each single step. An error is returned if the
65/// maximum cycle count is exceeded.
66pub struct StepStopper;
67
68impl Stopper for StepStopper {
69    type Processor = FastProcessor;
70
71    #[inline(always)]
72    fn should_stop(
73        &self,
74        processor: &FastProcessor,
75        continuation_stack: &ContinuationStack,
76        continuation_after_stop: impl FnOnce() -> Option<Continuation>,
77    ) -> ControlFlow<BreakReason> {
78        check_if_max_cycles_exceeded(processor)?;
79        check_if_continuation_stack_too_large(processor, continuation_stack)?;
80
81        ControlFlow::Break(BreakReason::Stopped(continuation_after_stop()))
82    }
83}
84
85/// Checks if the maximum cycle count has been exceeded, returning a `BreakReason::Err` if so.
86#[inline(always)]
87fn check_if_max_cycles_exceeded(processor: &FastProcessor) -> ControlFlow<BreakReason> {
88    if processor.clk > processor.options.max_cycles() as usize {
89        ControlFlow::Break(BreakReason::Err(ExecutionError::CycleLimitExceeded(
90            processor.options.max_cycles(),
91        )))
92    } else {
93        ControlFlow::Continue(())
94    }
95}
96
97/// Checks if the continuation stack size exceeds the maximum allowed, returning a
98/// `BreakReason::Err` if so.
99#[inline(always)]
100fn check_if_continuation_stack_too_large(
101    processor: &FastProcessor,
102    continuation_stack: &ContinuationStack,
103) -> ControlFlow<BreakReason> {
104    if continuation_stack.len() > processor.options.max_num_continuations() {
105        ControlFlow::Break(BreakReason::Err(ExecutionError::Internal(
106            "continuation stack size exceeded the allowed maximum",
107        )))
108    } else {
109        ControlFlow::Continue(())
110    }
111}
112
113// BREAK REASON
114// ===============================================================================================
115
116/// The reason why execution was interrupted.
117#[derive(Debug)]
118pub enum BreakReason {
119    /// An execution error occurred
120    Err(ExecutionError),
121    /// Execution was stopped by a [`Stopper`]. Provides the continuation to add to the continuation
122    /// stack before returning, if any. The mental model to have in mind when choosing the
123    /// continuation to add on a call to `FastProcessor::increment_clk()` is:
124    ///
125    /// "If execution is stopped here, does the current continuation stack properly encode the next
126    /// step of execution?"
127    ///
128    /// If yes, then `None` should be returned. If not, then the continuation that runs the next
129    /// step in `FastProcessor::execute_impl()` should be returned.
130    Stopped(Option<Continuation>),
131}