use cairo_lang_casm::assembler::AssembledCairoProgram;
use cairo_lang_casm::casm;
use cairo_vm::types::builtin_name::BuiltinName;
use itertools::chain;
use serde::{Deserialize, Serialize};
use crate::compile::CompiledFunction;
use crate::debug_info::{Annotations, DebugInfo, ProgramInformation};
pub const NOT_RETURNING_HEADER_SIZE: usize = 6;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Executable {
pub program: AssembledCairoProgram,
pub entrypoints: Vec<ExecutableEntryPoint>,
#[serde(skip_serializing_if = "Option::is_none")]
pub debug_info: Option<DebugInfo>,
}
impl Executable {
pub fn new(compiled: CompiledFunction) -> Self {
let non_returning_header = casm! {
ap += (compiled.wrapper.builtins.len());
call rel 4;
jmp rel 0;
};
assert_eq!(non_returning_header.current_code_offset, NOT_RETURNING_HEADER_SIZE);
Self {
program: compiled.program.assemble_ex(
chain!(&non_returning_header.instructions, &compiled.wrapper.header),
&compiled.wrapper.footer,
),
entrypoints: vec![
ExecutableEntryPoint {
builtins: compiled.wrapper.builtins.clone(),
offset: 0,
kind: EntryPointKind::Standalone,
},
ExecutableEntryPoint {
builtins: compiled.wrapper.builtins,
offset: NOT_RETURNING_HEADER_SIZE,
kind: EntryPointKind::Bootloader,
},
],
debug_info: Some(DebugInfo {
annotations: Annotations::from(ProgramInformation {
program_offset: NOT_RETURNING_HEADER_SIZE
+ compiled
.wrapper
.header
.iter()
.map(|inst| inst.body.op_size())
.sum::<usize>(),
}),
}),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExecutableEntryPoint {
pub builtins: Vec<BuiltinName>,
pub offset: usize,
pub kind: EntryPointKind,
}
#[derive(Debug, Clone, Serialize, PartialEq, Deserialize)]
pub enum EntryPointKind {
Bootloader,
Standalone,
}