Skip to content

Commit 4297365

Browse files
Eliminate pie deep copies in cairo program runner.
1 parent f41cdeb commit 4297365

File tree

5 files changed

+47
-38
lines changed

5 files changed

+47
-38
lines changed

crates/cairo-program-runner-lib/src/hints/execute_task_hints.rs

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::any::Any;
22
use std::collections::HashMap;
3+
use std::rc::Rc;
34
use std::vec;
45

56
use cairo_lang_runner::{Arg, CairoHintProcessor};
@@ -82,8 +83,8 @@ pub fn load_program_hint(
8283
ap_tracking,
8384
)?;
8485

85-
let task: Task = exec_scopes.get(vars::TASK)?;
86-
let program = get_program_from_task(&task)?;
86+
let task: &Rc<Task> = exec_scopes.get_ref(vars::TASK)?;
87+
let program = get_program_from_task(task)?;
8788

8889
let program_header_ptr = get_ptr_from_var_name("program_header", vm, ids_data, ap_tracking)?;
8990

@@ -125,7 +126,7 @@ pub fn append_fact_topologies(
125126
ids_data: &HashMap<String, HintReference>,
126127
ap_tracking: &ApTracking,
127128
) -> Result<(), HintError> {
128-
let task: Task = exec_scopes.get(vars::TASK)?;
129+
let task: Rc<Task> = exec_scopes.get(vars::TASK)?;
129130
let output_runner_data: Option<OutputBuiltinState> =
130131
exec_scopes.get(vars::OUTPUT_RUNNER_DATA)?;
131132
let fact_topologies: &mut Vec<FactTopology> = exec_scopes.get_mut_ref(vars::FACT_TOPOLOGIES)?;
@@ -162,8 +163,8 @@ pub fn validate_hash(
162163
ids_data: &HashMap<String, HintReference>,
163164
ap_tracking: &ApTracking,
164165
) -> Result<(), HintError> {
165-
let task: Task = exec_scopes.get(vars::TASK)?;
166-
let program = get_program_from_task(&task)?;
166+
let task: &Rc<Task> = exec_scopes.get_ref(vars::TASK)?;
167+
let program = get_program_from_task(task)?;
167168

168169
let output_ptr = get_ptr_from_var_name("output_ptr", vm, ids_data, ap_tracking)?;
169170
let program_hash_ptr = (output_ptr + 1)?;
@@ -301,11 +302,11 @@ pub fn write_return_builtins_hint(
301302
ids_data: &HashMap<String, HintReference>,
302303
ap_tracking: &ApTracking,
303304
) -> Result<(), HintError> {
304-
let task: Task = exec_scopes.get(vars::TASK)?;
305+
let task: &Rc<Task> = exec_scopes.get_ref(vars::TASK)?;
305306
let n_builtins: usize = exec_scopes.get(vars::N_BUILTINS)?;
306307

307308
// builtins = task.get_program().builtins
308-
let program = get_program_from_task(&task)?;
309+
let program = get_program_from_task(task)?;
309310
let builtins = &program.builtins;
310311

311312
// write_return_builtins(
@@ -325,7 +326,7 @@ pub fn write_return_builtins_hint(
325326
builtins,
326327
used_builtins_addr,
327328
pre_execution_builtins_addr,
328-
&task,
329+
task,
329330
)?;
330331

331332
// vm_enter_scope({'n_selected_builtins': n_builtins})
@@ -398,7 +399,7 @@ pub fn setup_subtask_for_execution(
398399
ids_data: &HashMap<String, HintReference>,
399400
ap_tracking: &ApTracking,
400401
) -> Result<HintExtension, HintError> {
401-
let task: Task = exec_scopes.get(vars::TASK)?;
402+
let task: Rc<Task> = exec_scopes.get(vars::TASK)?;
402403

403404
let n_builtins = get_program_from_task(&task)?.builtins.len();
404405
exec_scopes.insert_value(vars::N_BUILTINS, n_builtins);
@@ -408,7 +409,7 @@ pub fn setup_subtask_for_execution(
408409
let mut hint_extension = HintExtension::default();
409410

410411
let subtask_cairo1_hint_processor: Option<CairoHintProcessor<'_>>;
411-
match &task {
412+
match &*task {
412413
Task::Cairo0Program(cairo0_executable) => {
413414
if let Some(program_input) = cairo0_executable.program_input.as_ref() {
414415
new_task_locals.insert(PROGRAM_INPUT.to_string(), any_box![program_input.clone()]);
@@ -530,8 +531,8 @@ pub fn bootloader_validate_hash(
530531
return Ok(());
531532
}
532533

533-
let task: Task = exec_scopes.get(vars::TASK)?;
534-
let program = get_program_from_task(&task)?;
534+
let task: &Rc<Task> = exec_scopes.get_ref(vars::TASK)?;
535+
let program = get_program_from_task(task)?;
535536
let output_ptr = get_ptr_from_var_name("output_ptr", vm, ids_data, ap_tracking)?;
536537
let program_hash_ptr = (output_ptr + 1)?;
537538
let program_hash = vm.get_integer(program_hash_ptr)?.into_owned();
@@ -598,10 +599,10 @@ mod tests {
598599
/// pointers in the ids_data point to it.
599600
#[rstest]
600601
fn test_allocation_in_load_program_hint(fibonacci: Program) {
601-
let fibonacci_task = Task::Cairo0Program(Cairo0Executable {
602+
let fibonacci_task = Rc::new(Task::Cairo0Program(Cairo0Executable {
602603
program: fibonacci.clone(),
603604
program_input: None,
604-
});
605+
}));
605606
let (
606607
mut vm,
607608
ids_data,
@@ -674,10 +675,10 @@ mod tests {
674675
/// memory is checked in program_loader.rs tests.
675676
#[rstest]
676677
fn test_load_program(fibonacci: Program) {
677-
let fibonacci_task = Task::Cairo0Program(Cairo0Executable {
678+
let fibonacci_task = Rc::new(Task::Cairo0Program(Cairo0Executable {
678679
program: fibonacci.clone(),
679680
program_input: None,
680-
});
681+
}));
681682

682683
let (
683684
mut vm,
@@ -718,10 +719,10 @@ mod tests {
718719
/// extension, and that the output runner data is set correctly.
719720
#[rstest]
720721
fn test_call_task(fibonacci: Program) {
721-
let fibonacci_task = Task::Cairo0Program(Cairo0Executable {
722+
let fibonacci_task = Rc::new(Task::Cairo0Program(Cairo0Executable {
722723
program: fibonacci.clone(),
723724
program_input: None,
724-
});
725+
}));
725726
let (
726727
mut vm,
727728
ids_data,
@@ -757,12 +758,12 @@ mod tests {
757758
vm.builtin_runners
758759
.push(BuiltinRunner::Output(output_builtin));
759760

760-
let task = Task::Cairo0Program(Cairo0Executable {
761+
let task = Rc::new(Task::Cairo0Program(Cairo0Executable {
761762
program: fibonacci.clone(),
762763
program_input: None,
763-
});
764+
}));
764765

765-
exec_scopes.insert_box(vars::TASK, Box::new(task));
766+
exec_scopes.insert_value(vars::TASK, task);
766767

767768
let hint_data =
768769
HintProcessorData::new_default(String::from(EXECUTE_TASK_CALL_TASK), ids_data);
@@ -825,7 +826,7 @@ mod tests {
825826
/// the VM, to a similar state as in the execute_task function in execute_task.cairo.
826827
#[rstest]
827828
fn test_call_cairo_pie_task(fibonacci_pie: CairoPie) {
828-
let fibonacci_pie_task = Task::Pie(fibonacci_pie.clone());
829+
let fibonacci_pie_task = Rc::new(Task::Pie(fibonacci_pie.clone()));
829830
let (
830831
mut vm,
831832
ids_data,
@@ -874,7 +875,7 @@ mod tests {
874875
vm.builtin_runners
875876
.push(BuiltinRunner::Output(output_builtin));
876877

877-
let task = Task::Pie(fibonacci_pie.clone());
878+
let task = Rc::new(Task::Pie(fibonacci_pie.clone()));
878879
exec_scopes.insert_value(vars::TASK, task);
879880
let bootloader_program = get_simple_bootloader_program();
880881
exec_scopes.insert_value(vars::PROGRAM_DATA_BASE, program_header_ptr);
@@ -974,7 +975,7 @@ mod tests {
974975
let mut exec_scopes = ExecutionScopes::new();
975976

976977
exec_scopes.insert_value(vars::OUTPUT_RUNNER_DATA, Some(output_builtin_state.clone()));
977-
exec_scopes.insert_value(vars::TASK, fibonacci_task);
978+
exec_scopes.insert_value(vars::TASK, Rc::new(fibonacci_task));
978979
exec_scopes.insert_value(vars::FACT_TOPOLOGIES, Vec::<FactTopology>::new());
979980

980981
append_fact_topologies(&mut vm, &mut exec_scopes, &ids_data, &ap_tracking)
@@ -1057,7 +1058,7 @@ mod tests {
10571058
let mut exec_scopes = ExecutionScopes::new();
10581059
let n_builtins = builtin_usage_program.builtins_len();
10591060
exec_scopes.insert_value(vars::N_BUILTINS, n_builtins);
1060-
exec_scopes.insert_value(vars::TASK, task);
1061+
exec_scopes.insert_value(vars::TASK, Rc::new(task));
10611062

10621063
write_return_builtins_hint(&mut vm, &mut exec_scopes, &ids_data, &ap_tracking)
10631064
.expect("Hint failed unexpectedly");

crates/cairo-program-runner-lib/src/hints/load_cairo_pie.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,8 @@ pub fn extract_segment(maybe_relocatable: MaybeRelocatable) -> Result<isize, Rel
160160
///
161161
/// Makes it more convenient to access values in the Cairo PIE memory.
162162
fn build_cairo_pie_memory_map(memory: &CairoPieMemory) -> HashMap<Relocatable, &MaybeRelocatable> {
163-
let mut memory_map: HashMap<Relocatable, &MaybeRelocatable> = HashMap::new();
163+
let mut memory_map: HashMap<Relocatable, &MaybeRelocatable> =
164+
HashMap::with_capacity(memory.0.len());
164165

165166
for ((segment_index, offset), value) in memory.0.iter() {
166167
let address = Relocatable::from((*segment_index as isize, *offset));

crates/cairo-program-runner-lib/src/hints/simple_bootloader_hints.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,13 @@ pub fn setup_run_simple_bootloader_before_task_execution(
6060

6161
/// Implements
6262
/// %{ tasks = simple_bootloader_input.tasks %}
63-
pub fn set_tasks_variable(exec_scopes: &mut ExecutionScopes) -> Result<(), HintError> {
64-
let simple_bootloader_input: &SimpleBootloaderInput =
65-
exec_scopes.get_ref(vars::SIMPLE_BOOTLOADER_INPUT)?;
66-
exec_scopes.insert_value(vars::TASKS, simple_bootloader_input.tasks.clone());
67-
63+
///
64+
/// Note: The TASKS variable is not actually read anywhere in the Rust implementation.
65+
/// Tasks are accessed directly from SIMPLE_BOOTLOADER_INPUT when needed.
66+
/// This function exists only to maintain compatibility with the Cairo hint interface.
67+
pub fn set_tasks_variable(_exec_scopes: &mut ExecutionScopes) -> Result<(), HintError> {
68+
// Intentionally not cloning tasks - the TASKS variable is never read.
69+
// Tasks are accessed directly via SIMPLE_BOOTLOADER_INPUT.tasks when needed.
6870
Ok(())
6971
}
7072

crates/cairo-program-runner-lib/src/hints/types.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::collections::HashMap;
22
use std::path::PathBuf;
3+
use std::rc::Rc;
34
use std::str::FromStr;
45

56
use cairo_lang_casm::hints::Hint;
@@ -264,7 +265,9 @@ struct TaskSpecHelper {
264265

265266
#[derive(Debug, Clone, PartialEq)]
266267
pub struct TaskSpec {
267-
pub task: Task,
268+
/// Task wrapped in Rc to avoid expensive clones when reading it from execution scopes.
269+
/// CairoPie tasks can be several GB in size.
270+
pub task: Rc<Task>,
268271
pub program_hash_function: HashFunc,
269272
}
270273

@@ -372,19 +375,19 @@ impl<'de> Deserialize<'de> for TaskSpec {
372375
};
373376

374377
Ok(TaskSpec {
375-
task,
378+
task: Rc::new(task),
376379
program_hash_function: HashFunc::try_from(helper.program_hash_function)
377380
.map_err(|e| D::Error::custom(format!("Invalid program hash function: {e:?}")))?,
378381
})
379382
}
380383
}
381384

382385
impl TaskSpec {
383-
/// Retrieves a reference to the `Task` within the `TaskSpec`.
386+
/// Retrieves a reference to the `Rc<Task>` within the `TaskSpec`.
384387
///
385388
/// # Returns
386-
/// A reference to the `task` field, which is either a `Program` or `CairoPie`.
387-
pub fn load_task(&self) -> &Task {
389+
/// A reference to the `Rc<Task>` field, which wraps either a `Program` or `CairoPie`.
390+
pub fn load_task(&self) -> &Rc<Task> {
388391
&self.task
389392
}
390393
}

crates/cairo-program-runner-lib/src/test_utils.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::rc::Rc;
2+
13
use crate::hints::types::Task;
24
use crate::hints::vars;
35
use cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::HintProcessorData;
@@ -83,15 +85,15 @@ pub fn get_hint_codes_at_pc(hint_extension: &HintExtension, pc: Relocatable) ->
8385
/// The `task` is inserted into the execution scopes. `load_program_hint` should succeed after this
8486
/// function.
8587
pub fn prepare_vm_for_load_program_loading_test(
86-
task: Task,
88+
task: Rc<Task>,
8789
) -> (
8890
VirtualMachine,
8991
std::collections::HashMap<String, HintReference>,
9092
ExecutionScopes,
9193
ApTracking,
9294
usize, // expected_program_data_segment_index
9395
Relocatable, // program_header_ptr
94-
Task,
96+
Rc<Task>,
9597
) {
9698
let mut vm = VirtualMachine::new(false, false);
9799
vm.set_fp(3);

0 commit comments

Comments
 (0)