miden-processor 0.24.0

Miden VM processor
Documentation
use alloc::vec::Vec;
use core::ops::ControlFlow;

use miden_core::events::{EventId, SystemEvent};
use miden_mast_package::debug_info::{DebugSourceNodeId, PackageDebugInfo};

use crate::{
    BaseHost, Host, SyncHost,
    advice::AdviceMutation,
    errors::{
        MapExecErrWithOpIdx, PackageSourceDebugContext, advice_error_with_context,
        advice_error_with_package_source_context, event_error_with_context,
        event_error_with_package_source_context,
    },
    event::EventError,
    fast::{BreakReason, FastProcessor},
};

mod sys_event_handlers;
pub use sys_event_handlers::SystemEventError;
use sys_event_handlers::handle_system_event;

impl FastProcessor {
    #[inline(always)]
    fn handle_system_event<F>(
        &mut self,
        system_event: SystemEvent,
        host: &impl BaseHost,
        op_idx: usize,
        package_debug_info: Option<&PackageDebugInfo>,
        source_node_id: Option<DebugSourceNodeId>,
    ) -> ControlFlow<BreakReason<F>> {
        let context = package_source_context(package_debug_info, source_node_id);
        match handle_system_event(self, system_event)
            .map_exec_err_with_package_source_op_idx(context, host, op_idx)
        {
            Ok(()) => ControlFlow::Continue(()),
            Err(err) => ControlFlow::Break(BreakReason::Err(err)),
        }
    }

    #[inline(always)]
    fn apply_host_event_mutations<F>(
        &mut self,
        host: &impl BaseHost,
        op_idx: usize,
        event_id: EventId,
        mutations: Result<Vec<AdviceMutation>, EventError>,
        package_debug_info: Option<&PackageDebugInfo>,
        source_node_id: Option<DebugSourceNodeId>,
    ) -> ControlFlow<BreakReason<F>> {
        let mutations = match mutations {
            Ok(mutations) => mutations,
            Err(err) => {
                let event_name = host.resolve_event(event_id).cloned();
                let context = package_source_context(package_debug_info, source_node_id);
                if let Some(context) = context {
                    return ControlFlow::Break(BreakReason::Err(
                        event_error_with_package_source_context(
                            err,
                            context,
                            host,
                            Some(op_idx),
                            event_id,
                            event_name,
                        ),
                    ));
                }
                return ControlFlow::Break(BreakReason::Err(event_error_with_context(
                    err, event_id, event_name,
                )));
            },
        };

        match self.advice.apply_mutations(mutations) {
            Ok(()) => ControlFlow::Continue(()),
            Err(err) => {
                let context = package_source_context(package_debug_info, source_node_id);
                let err = if let Some(context) = context {
                    advice_error_with_package_source_context(err, context, host, Some(op_idx))
                } else {
                    advice_error_with_context(err)
                };
                ControlFlow::Break(BreakReason::Err(err))
            },
        }
    }

    #[inline(always)]
    pub(super) fn op_emit_sync<F>(
        &mut self,
        host: &mut impl SyncHost,
        op_idx: usize,
        package_debug_info: Option<&PackageDebugInfo>,
        source_node_id: Option<DebugSourceNodeId>,
    ) -> ControlFlow<BreakReason<F>> {
        let event_id = EventId::from_felt(self.stack_get(0));

        // If it's a system event, handle it directly. Otherwise, forward it to the host.
        if let Some(system_event) = SystemEvent::from_event_id(event_id) {
            return self.handle_system_event(
                system_event,
                host,
                op_idx,
                package_debug_info,
                source_node_id,
            );
        }

        let processor_state = self.state();
        let mutations = host.on_event(&processor_state);
        self.apply_host_event_mutations(
            host,
            op_idx,
            event_id,
            mutations,
            package_debug_info,
            source_node_id,
        )
    }

    #[inline(always)]
    pub(super) async fn op_emit<F>(
        &mut self,
        host: &mut impl Host,
        op_idx: usize,
        package_debug_info: Option<&PackageDebugInfo>,
        source_node_id: Option<DebugSourceNodeId>,
    ) -> ControlFlow<BreakReason<F>> {
        let event_id = EventId::from_felt(self.stack_get(0));

        if let Some(system_event) = SystemEvent::from_event_id(event_id) {
            return self.handle_system_event(
                system_event,
                host,
                op_idx,
                package_debug_info,
                source_node_id,
            );
        }

        let processor_state = self.state();
        let mutations = host.on_event(&processor_state).await;
        self.apply_host_event_mutations(
            host,
            op_idx,
            event_id,
            mutations,
            package_debug_info,
            source_node_id,
        )
    }
}

fn package_source_context(
    package_debug_info: Option<&PackageDebugInfo>,
    source_node_id: Option<DebugSourceNodeId>,
) -> Option<PackageSourceDebugContext<'_>> {
    Some(PackageSourceDebugContext::new_optional(package_debug_info?, source_node_id))
}