cairo_lang_executable/
executable.rs

1use cairo_lang_casm::assembler::AssembledCairoProgram;
2use cairo_lang_casm::casm;
3use cairo_vm::types::builtin_name::BuiltinName;
4use itertools::chain;
5use serde::{Deserialize, Serialize};
6
7use crate::compile::CompiledFunction;
8use crate::debug_info::{Annotations, DebugInfo, ProgramInformation};
9
10pub const NOT_RETURNING_HEADER_SIZE: usize = 6;
11
12/// Structure to hold the executable representation of a program.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Executable {
15    /// The bytecode of the program.
16    pub program: AssembledCairoProgram,
17    /// The available entrypoints for the program.
18    pub entrypoints: Vec<ExecutableEntryPoint>,
19    /// Debug information for the assembled program.
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub debug_info: Option<DebugInfo>,
22}
23
24impl Executable {
25    /// Create a new executable program from a compiled function.
26    pub fn new(compiled: CompiledFunction) -> Self {
27        let non_returning_header = casm! {
28            ap += (compiled.wrapper.builtins.len());
29            call rel 4;
30            jmp rel 0;
31        };
32        assert_eq!(non_returning_header.current_code_offset, NOT_RETURNING_HEADER_SIZE);
33        Self {
34            program: compiled.program.assemble_ex(
35                chain!(&non_returning_header.instructions, &compiled.wrapper.header),
36                &compiled.wrapper.footer,
37            ),
38            entrypoints: vec![
39                ExecutableEntryPoint {
40                    builtins: compiled.wrapper.builtins.clone(),
41                    offset: 0,
42                    kind: EntryPointKind::Standalone,
43                },
44                ExecutableEntryPoint {
45                    builtins: compiled.wrapper.builtins,
46                    offset: NOT_RETURNING_HEADER_SIZE,
47                    kind: EntryPointKind::Bootloader,
48                },
49            ],
50            debug_info: Some(DebugInfo {
51                annotations: Annotations::from(ProgramInformation {
52                    program_offset: NOT_RETURNING_HEADER_SIZE
53                        + compiled
54                            .wrapper
55                            .header
56                            .iter()
57                            .map(|inst| inst.body.op_size())
58                            .sum::<usize>(),
59                }),
60            }),
61        }
62    }
63}
64
65/// Information about an executable entrypoint.
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct ExecutableEntryPoint {
68    /// The used builtins of the function.
69    pub builtins: Vec<BuiltinName>,
70    /// The offset of the entrypoint in the bytecode.
71    pub offset: usize,
72    /// The kind of the entrypoint.
73    pub kind: EntryPointKind,
74}
75
76/// The kind of an entrypoint.
77#[derive(Debug, Clone, Serialize, PartialEq, Deserialize)]
78pub enum EntryPointKind {
79    /// Entrypoint is for running it using a bootloader.
80    ///
81    /// The entrypoint is a function, ending with a `ret`, expecting the builtins as its parameters.
82    Bootloader,
83    /// Entrypoint is for running this executable as a standalone program.
84    ///
85    /// The entrypoint starts with `ap += <builtins.len()>` and expects the builtins to be injected
86    /// there, and ends with an infinite loop.
87    Standalone,
88}