miden_assembly/instruction/
procedures.rs

1use miden_assembly_syntax::{
2    Word,
3    ast::{InvocationTarget, InvokeKind},
4    diagnostics::Report,
5};
6use miden_core::{Operation, mast::MastNodeId};
7use smallvec::SmallVec;
8
9use crate::{
10    Assembler, ProcedureContext, basic_block_builder::BasicBlockBuilder,
11    mast_forest_builder::MastForestBuilder,
12};
13
14/// Procedure Invocation
15impl Assembler {
16    /// Returns the [`MastNodeId`] of the invoked procedure specified by `callee`.
17    ///
18    /// For example, given `exec.f`, this method would return the procedure body id of `f`. If the
19    /// only representation of `f` that we have is its MAST root, then this method will also insert
20    /// a [`core::mast::ExternalNode`] that wraps `f`'s MAST root and return the corresponding id.
21    pub(super) fn invoke(
22        &self,
23        kind: InvokeKind,
24        callee: &InvocationTarget,
25        proc_ctx: &ProcedureContext,
26        mast_forest_builder: &mut MastForestBuilder,
27    ) -> Result<MastNodeId, Report> {
28        let resolved = self.resolve_target(kind, callee, proc_ctx, mast_forest_builder)?;
29
30        match kind {
31            InvokeKind::ProcRef | InvokeKind::Exec => Ok(resolved.node),
32            InvokeKind::Call => mast_forest_builder.ensure_call(resolved.node),
33            InvokeKind::SysCall => mast_forest_builder.ensure_syscall(resolved.node),
34        }
35    }
36
37    /// Creates a new DYN block for the dynamic code execution and return.
38    pub(super) fn dynexec(
39        &self,
40        mast_forest_builder: &mut MastForestBuilder,
41    ) -> Result<Option<MastNodeId>, Report> {
42        let dyn_node_id = mast_forest_builder.ensure_dyn()?;
43
44        Ok(Some(dyn_node_id))
45    }
46
47    /// Creates a new DYNCALL block for the dynamic function call and return.
48    pub(super) fn dyncall(
49        &self,
50        mast_forest_builder: &mut MastForestBuilder,
51    ) -> Result<Option<MastNodeId>, Report> {
52        let dyn_call_node_id = mast_forest_builder.ensure_dyncall()?;
53
54        Ok(Some(dyn_call_node_id))
55    }
56
57    pub(super) fn procref(
58        &self,
59        callee: &InvocationTarget,
60        proc_ctx: &mut ProcedureContext,
61        block_builder: &mut BasicBlockBuilder,
62    ) -> Result<(), Report> {
63        let mast_root = {
64            let resolved = self.resolve_target(
65                InvokeKind::ProcRef,
66                callee,
67                proc_ctx,
68                block_builder.mast_forest_builder_mut(),
69            )?;
70            // Note: it's ok to `unwrap()` here since `proc_body_id` was returned from
71            // `mast_forest_builder`
72            block_builder
73                .mast_forest_builder()
74                .get_mast_node(resolved.node)
75                .unwrap()
76                .digest()
77        };
78
79        self.procref_mast_root(mast_root, block_builder)
80    }
81
82    fn procref_mast_root(
83        &self,
84        mast_root: Word,
85        block_builder: &mut BasicBlockBuilder,
86    ) -> Result<(), Report> {
87        // Create an array with `Push` operations containing root elements
88        let ops = mast_root
89            .iter()
90            .map(|elem| Operation::Push(*elem))
91            .collect::<SmallVec<[_; 4]>>();
92        block_builder.push_ops(ops);
93        Ok(())
94    }
95}