use alloc::sync::Arc;
use core::ops::ControlFlow;
use miden_core::{mast::MastForest, program::Kernel};
use miden_mast_package::debug_info::{DebugSourceNodeId, PackageDebugInfo};
use crate::{
ExecutionError, FastProcessor, Stopper,
continuation_stack::{Continuation, ContinuationStack},
};
#[derive(Debug)]
pub struct ResumeContext {
pub(crate) current_forest: Arc<MastForest>,
pub(crate) continuation_stack: ContinuationStack<Arc<MastForest>>,
pub(crate) kernel: Kernel,
pub(crate) package_debug_info: Option<Arc<PackageDebugInfo>>,
}
impl ResumeContext {
pub fn continuation_stack(&self) -> &ContinuationStack<Arc<MastForest>> {
&self.continuation_stack
}
pub fn current_forest(&self) -> &Arc<MastForest> {
&self.current_forest
}
pub fn kernel(&self) -> &Kernel {
&self.kernel
}
}
pub struct NeverStopper;
impl Stopper for NeverStopper {
type Processor = FastProcessor;
type Forest = Arc<MastForest>;
#[inline(always)]
fn should_stop(
&self,
processor: &FastProcessor,
continuation_stack: &ContinuationStack<Arc<MastForest>>,
_continuation_after_stop: impl FnOnce() -> Option<(
Continuation<Arc<MastForest>>,
Option<DebugSourceNodeId>,
)>,
) -> ControlFlow<BreakReason<Arc<MastForest>>> {
check_if_max_cycles_exceeded(processor)?;
check_if_continuation_stack_too_large(processor, continuation_stack)
}
}
pub struct StepStopper;
impl Stopper for StepStopper {
type Processor = FastProcessor;
type Forest = Arc<MastForest>;
#[inline(always)]
fn should_stop(
&self,
processor: &FastProcessor,
continuation_stack: &ContinuationStack<Arc<MastForest>>,
continuation_after_stop: impl FnOnce() -> Option<(
Continuation<Arc<MastForest>>,
Option<DebugSourceNodeId>,
)>,
) -> ControlFlow<BreakReason<Arc<MastForest>>> {
check_if_max_cycles_exceeded(processor)?;
check_if_continuation_stack_too_large(processor, continuation_stack)?;
ControlFlow::Break(BreakReason::Stopped(continuation_after_stop()))
}
}
#[inline(always)]
fn check_if_max_cycles_exceeded<F>(processor: &FastProcessor) -> ControlFlow<BreakReason<F>> {
if processor.clk > processor.options.max_cycles() as usize {
ControlFlow::Break(BreakReason::Err(ExecutionError::CycleLimitExceeded(
processor.options.max_cycles(),
)))
} else {
ControlFlow::Continue(())
}
}
#[inline(always)]
fn check_if_continuation_stack_too_large<F>(
processor: &FastProcessor,
continuation_stack: &ContinuationStack<F>,
) -> ControlFlow<BreakReason<F>> {
if continuation_stack.len() > processor.options.max_num_continuations() {
ControlFlow::Break(BreakReason::Err(ExecutionError::Internal(
"continuation stack size exceeded the allowed maximum",
)))
} else {
ControlFlow::Continue(())
}
}
#[derive(Debug)]
pub enum BreakReason<F> {
Err(ExecutionError),
Stopped(Option<(Continuation<F>, Option<DebugSourceNodeId>)>),
}