use alloc::sync::Arc;
use miden_core::{
EventId, Operation,
mast::{BasicBlockNode, DecoratorOpLinkIterator, MastForest, MastNodeId, OpBatch},
sys_events::SystemEvent,
};
use crate::{
AsyncHost, ErrorContext, ExecutionError,
continuation_stack::ContinuationStack,
err_ctx,
fast::{FastProcessor, Tracer, trace_state::NodeExecutionState},
operations::sys_ops::sys_event_handlers::handle_system_event,
processor::Processor,
};
impl FastProcessor {
#[allow(clippy::too_many_arguments)]
#[inline(always)]
pub(super) async fn execute_basic_block_node(
&mut self,
basic_block_node: &BasicBlockNode,
node_id: MastNodeId,
program: &MastForest,
host: &mut impl AsyncHost,
continuation_stack: &mut ContinuationStack,
current_forest: &Arc<MastForest>,
tracer: &mut impl Tracer,
) -> Result<(), ExecutionError> {
tracer.start_clock_cycle(
self,
NodeExecutionState::Start(node_id),
continuation_stack,
current_forest,
);
self.execute_before_enter_decorators(node_id, program, host)?;
self.increment_clk(tracer);
let mut batch_offset_in_block = 0;
let mut op_batches = basic_block_node.op_batches().iter();
let mut decorator_ids = basic_block_node.indexed_decorator_iter();
if let Some(first_op_batch) = op_batches.next() {
self.execute_op_batch(
basic_block_node,
node_id,
first_op_batch,
0,
&mut decorator_ids,
batch_offset_in_block,
program,
host,
continuation_stack,
current_forest,
tracer,
)
.await?;
batch_offset_in_block += first_op_batch.ops().len();
}
for (batch_index_minus_1, op_batch) in op_batches.enumerate() {
let batch_index = batch_index_minus_1 + 1;
{
tracer.start_clock_cycle(
self,
NodeExecutionState::Respan { node_id, batch_index },
continuation_stack,
current_forest,
);
self.increment_clk(tracer);
}
self.execute_op_batch(
basic_block_node,
node_id,
op_batch,
batch_index,
&mut decorator_ids,
batch_offset_in_block,
program,
host,
continuation_stack,
current_forest,
tracer,
)
.await?;
batch_offset_in_block += op_batch.ops().len();
}
tracer.start_clock_cycle(
self,
NodeExecutionState::End(node_id),
continuation_stack,
current_forest,
);
self.increment_clk(tracer);
for (_, decorator_id) in decorator_ids {
let decorator = program
.get_decorator_by_id(decorator_id)
.ok_or(ExecutionError::DecoratorNotFoundInForest { decorator_id })?;
self.execute_decorator(decorator, host)?;
}
self.execute_after_exit_decorators(node_id, program, host)
}
#[inline(always)]
#[allow(clippy::too_many_arguments)]
async fn execute_op_batch(
&mut self,
basic_block: &BasicBlockNode,
node_id: MastNodeId,
batch: &OpBatch,
batch_index: usize,
decorators: &mut DecoratorOpLinkIterator<'_>,
batch_offset_in_block: usize,
program: &MastForest,
host: &mut impl AsyncHost,
continuation_stack: &mut ContinuationStack,
current_forest: &Arc<MastForest>,
tracer: &mut impl Tracer,
) -> Result<(), ExecutionError> {
let end_indices = batch.end_indices();
let mut group_idx = 0;
let mut next_group_idx = 1;
for (op_idx_in_batch, op) in batch.ops().iter().enumerate() {
let op_idx_in_block = batch_offset_in_block + op_idx_in_batch;
while let Some((_, decorator_id)) = decorators.next_filtered(op_idx_in_block) {
let decorator = program
.get_decorator_by_id(decorator_id)
.ok_or(ExecutionError::DecoratorNotFoundInForest { decorator_id })?;
self.execute_decorator(decorator, host)?;
}
tracer.start_clock_cycle(
self,
NodeExecutionState::BasicBlock { node_id, batch_index, op_idx_in_batch },
continuation_stack,
current_forest,
);
{
let err_ctx = err_ctx!(program, basic_block, host, op_idx_in_block);
match op {
Operation::Emit => self.op_emit(host, &err_ctx).await?,
_ => {
self.execute_sync_op(op, op_idx_in_block, program, host, &err_ctx, tracer)?;
},
}
}
let has_imm = op.imm_value().is_some();
if has_imm {
next_group_idx += 1;
}
if op_idx_in_batch + 1 == end_indices[group_idx] {
group_idx = next_group_idx;
next_group_idx += 1;
}
self.increment_clk(tracer);
}
Ok(())
}
#[inline(always)]
async fn op_emit(
&mut self,
host: &mut impl AsyncHost,
err_ctx: &impl ErrorContext,
) -> Result<(), ExecutionError> {
let mut process = self.state();
let event_id = EventId::from_felt(process.get_stack_item(0));
if let Some(system_event) = SystemEvent::from_event_id(event_id) {
handle_system_event(&mut process, system_event, err_ctx)
} else {
let clk = process.clk();
let mutations = host.on_event(&process).await.map_err(|err| {
let event_name = host.resolve_event(event_id).cloned();
ExecutionError::event_error(err, event_id, event_name, err_ctx)
})?;
self.advice
.apply_mutations(mutations)
.map_err(|err| ExecutionError::advice_error(err, clk, err_ctx))?;
Ok(())
}
}
}