use alloc::sync::Arc;
use core::ops::ControlFlow;
use crate::{
BreakReason, ContextId, Host, Kernel, Stopper, Word,
continuation_stack::{Continuation, ContinuationStack},
mast::{MastForest, MastNode, MastNodeId},
processor::{Processor, SystemInterface},
tracer::{OperationHelperRegisters, Tracer},
};
mod basic_block;
mod call;
mod r#dyn;
mod external;
mod join;
mod r#loop;
mod operations;
mod split;
pub(crate) use basic_block::finish_emit_op_execution;
pub(crate) use r#dyn::finish_load_mast_forest_from_dyn_start;
pub(crate) use external::finish_load_mast_forest_from_external;
#[cfg(test)]
pub(crate) use operations::eval_circuit_impl;
use operations::execute_op;
pub(crate) struct ExecutionState<'a, P, H, S, T> {
pub processor: &'a mut P,
pub continuation_stack: &'a mut ContinuationStack,
pub kernel: &'a Kernel,
pub host: &'a mut H,
pub tracer: &'a mut T,
pub stopper: &'a S,
}
pub(crate) fn execute_impl<P, S, T>(
processor: &mut P,
continuation_stack: &mut ContinuationStack,
current_forest: &mut Arc<MastForest>,
kernel: &Kernel,
host: &mut impl Host,
tracer: &mut T,
stopper: &S,
) -> ControlFlow<InternalBreakReason>
where
P: Processor,
S: Stopper<Processor = P>,
T: Tracer<Processor = P>,
{
let mut state = ExecutionState {
processor,
continuation_stack,
kernel,
host,
tracer,
stopper,
};
while let Some(continuation) = state.continuation_stack.pop_continuation() {
match continuation {
Continuation::StartNode(node_id) => {
let node = current_forest.get_node_by_id(node_id).unwrap();
match node {
MastNode::Block(basic_block_node) => {
basic_block::execute_basic_block_node_from_start(
&mut state,
basic_block_node,
node_id,
current_forest,
)?
},
MastNode::Join(join_node) => {
join::start_join_node(&mut state, join_node, node_id, current_forest)
.map_break(InternalBreakReason::from)?
},
MastNode::Split(split_node) => {
split::start_split_node(&mut state, split_node, node_id, current_forest)
.map_break(InternalBreakReason::from)?
},
MastNode::Loop(loop_node) => {
r#loop::start_loop_node(&mut state, loop_node, node_id, current_forest)
.map_break(InternalBreakReason::from)?
},
MastNode::Call(call_node) => {
call::start_call_node(&mut state, call_node, node_id, current_forest)
.map_break(InternalBreakReason::from)?
},
MastNode::Dyn(_) => r#dyn::start_dyn_node(&mut state, node_id, current_forest)?,
MastNode::External(_) => external::execute_external_node(
state.processor,
node_id,
current_forest,
state.host,
)?,
}
},
Continuation::FinishJoin(node_id) => {
join::finish_join_node(&mut state, node_id, current_forest)
.map_break(InternalBreakReason::from)?
},
Continuation::FinishSplit(node_id) => {
split::finish_split_node(&mut state, node_id, current_forest)
.map_break(InternalBreakReason::from)?
},
Continuation::FinishLoop { node_id, was_entered } => {
r#loop::finish_loop_node(&mut state, was_entered, node_id, current_forest)
.map_break(InternalBreakReason::from)?
},
Continuation::FinishCall(node_id) => {
call::finish_call_node(&mut state, node_id, current_forest)
.map_break(InternalBreakReason::from)?
},
Continuation::FinishDyn(node_id) => {
r#dyn::finish_dyn_node(&mut state, node_id, current_forest)
.map_break(InternalBreakReason::from)?
},
Continuation::FinishExternal(node_id) => {
state
.processor
.execute_after_exit_decorators(node_id, current_forest, state.host)
.map_break(InternalBreakReason::from)?;
},
Continuation::ResumeBasicBlock { node_id, batch_index, op_idx_in_batch } => {
let basic_block_node =
current_forest.get_node_by_id(node_id).unwrap().unwrap_basic_block();
basic_block::execute_basic_block_node_from_op_idx(
&mut state,
basic_block_node,
node_id,
batch_index,
op_idx_in_batch,
current_forest,
)?
},
Continuation::Respan { node_id, batch_index } => {
let basic_block_node =
current_forest.get_node_by_id(node_id).unwrap().unwrap_basic_block();
basic_block::execute_basic_block_node_from_batch(
&mut state,
basic_block_node,
node_id,
batch_index,
current_forest,
)?
},
Continuation::FinishBasicBlock(node_id) => {
let basic_block_node =
current_forest.get_node_by_id(node_id).unwrap().unwrap_basic_block();
basic_block::finish_basic_block(
&mut state,
basic_block_node,
node_id,
current_forest,
)
.map_break(InternalBreakReason::from)?
},
Continuation::EnterForest(previous_forest) => {
*current_forest = previous_forest;
},
Continuation::AfterExitDecorators(node_id) => state
.processor
.execute_after_exit_decorators(node_id, current_forest, state.host)
.map_break(InternalBreakReason::from)?,
Continuation::AfterExitDecoratorsBasicBlock(node_id) => {
let basic_block_node =
current_forest.get_node_by_id(node_id).unwrap().unwrap_basic_block();
state
.processor
.execute_end_of_block_decorators(
basic_block_node,
node_id,
current_forest,
state.host,
)
.map_break(InternalBreakReason::from)?;
state
.processor
.execute_after_exit_decorators(node_id, current_forest, state.host)
.map_break(InternalBreakReason::from)?;
},
}
}
ControlFlow::Continue(())
}
pub enum InternalBreakReason {
User(BreakReason),
Emit {
basic_block_node_id: MastNodeId,
op_idx: usize,
continuation: Continuation,
},
LoadMastForestFromDyn {
dyn_node_id: MastNodeId,
callee_hash: Word,
},
LoadMastForestFromExternal {
external_node_id: MastNodeId,
procedure_hash: Word,
},
}
impl From<BreakReason> for InternalBreakReason {
fn from(reason: BreakReason) -> Self {
Self::User(reason)
}
}
#[inline(always)]
fn finalize_clock_cycle<P, S, T>(
processor: &mut P,
tracer: &mut T,
stopper: &S,
continuation_stack: &ContinuationStack,
current_forest: &Arc<MastForest>,
) -> ControlFlow<BreakReason>
where
P: Processor,
S: Stopper<Processor = P>,
T: Tracer<Processor = P>,
{
finalize_clock_cycle_with_continuation(
processor,
tracer,
stopper,
continuation_stack,
|| None,
current_forest,
)
}
#[inline(always)]
fn finalize_clock_cycle_with_continuation<P, S, T>(
processor: &mut P,
tracer: &mut T,
stopper: &S,
continuation_stack: &ContinuationStack,
continuation_after_stop: impl FnOnce() -> Option<Continuation>,
current_forest: &Arc<MastForest>,
) -> ControlFlow<BreakReason>
where
P: Processor,
S: Stopper<Processor = P>,
T: Tracer<Processor = P>,
{
finalize_clock_cycle_with_continuation_and_op_helpers(
processor,
tracer,
stopper,
continuation_stack,
continuation_after_stop,
OperationHelperRegisters::Empty,
current_forest,
)
}
#[inline(always)]
fn finalize_clock_cycle_with_continuation_and_op_helpers<P, S, T>(
processor: &mut P,
tracer: &mut T,
stopper: &S,
continuation_stack: &ContinuationStack,
continuation_after_stop: impl FnOnce() -> Option<Continuation>,
op_helper_registers: OperationHelperRegisters,
current_forest: &Arc<MastForest>,
) -> ControlFlow<BreakReason>
where
P: Processor,
S: Stopper<Processor = P>,
T: Tracer<Processor = P>,
{
tracer.finalize_clock_cycle(processor, op_helper_registers, current_forest);
processor.system_mut().increment_clock();
stopper.should_stop(processor, continuation_stack, continuation_after_stop)
}
fn get_next_ctx_id(processor: &impl Processor) -> ContextId {
(processor.system().clock() + 1).into()
}