Skip to content

Commit a93adb9

Browse files
Add support for precompiling hints
1 parent f17b0e3 commit a93adb9

File tree

2 files changed

+158
-4
lines changed

2 files changed

+158
-4
lines changed

vm/src/vm/runners/cairo_runner.rs

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ pub struct CairoRunnerBuilder {
162162
// Set after loading instruction cache.
163163
// instructions: Vec<Option<Instruction>>,
164164
// Set after compiling hints.
165-
// hints: Vec<Rc<dyn Any>>,
165+
hints: Option<Vec<Rc<Box<dyn Any>>>>,
166166
}
167167

168168
impl CairoRunnerBuilder {
@@ -203,6 +203,7 @@ impl CairoRunnerBuilder {
203203
execution_base: None,
204204
memory: MemorySegmentManager::new(),
205205
loaded_program: false,
206+
hints: None,
206207
})
207208
}
208209

@@ -221,7 +222,7 @@ impl CairoRunnerBuilder {
221222
|| self.runner_mode == RunnerMode::ProofModeCairo1
222223
}
223224

224-
fn add_memory_segment(&mut self) -> Relocatable {
225+
pub fn add_memory_segment(&mut self) -> Relocatable {
225226
self.memory.add()
226227
}
227228

@@ -352,9 +353,12 @@ impl CairoRunnerBuilder {
352353
Ok(())
353354
}
354355

355-
pub fn initialize_segments(&mut self) {
356+
pub fn initialize_base_segments(&mut self) {
356357
self.program_base = Some(self.add_memory_segment());
357358
self.execution_base = Some(self.add_memory_segment());
359+
}
360+
361+
pub fn initialize_builtin_segments(&mut self) {
358362
for builtin_runner in self.builtin_runners.iter_mut() {
359363
builtin_runner.initialize_segments(&mut self.memory);
360364
}
@@ -372,6 +376,33 @@ impl CairoRunnerBuilder {
372376
Ok(())
373377
}
374378

379+
pub fn compile_hints(
380+
&mut self,
381+
hint_processor: &mut dyn HintProcessor,
382+
) -> Result<(), VirtualMachineError> {
383+
let constants = Rc::new(self.program.constants.clone());
384+
let references = &self.program.shared_program_data.reference_manager;
385+
let compiled_hints = self
386+
.program
387+
.shared_program_data
388+
.hints_collection
389+
.iter_hints()
390+
.map(|hint| {
391+
let hint = hint_processor.compile_hint(
392+
&hint.code,
393+
&hint.flow_tracking_data.ap_tracking,
394+
&hint.flow_tracking_data.reference_ids,
395+
references,
396+
constants.clone(),
397+
)?;
398+
399+
Ok(Rc::new(hint))
400+
})
401+
.collect::<Result<Vec<Rc<Box<dyn Any>>>, VirtualMachineError>>()?;
402+
self.hints = Some(compiled_hints);
403+
Ok(())
404+
}
405+
375406
pub fn build(self) -> Result<CairoRunner, RunnerError> {
376407
let mut vm = VirtualMachine::new(self.enable_trace, self.disable_trace_padding);
377408

@@ -401,6 +432,7 @@ impl CairoRunnerBuilder {
401432
relocated_trace: None,
402433
program: self.program,
403434
loaded_program: self.loaded_program,
435+
hints: self.hints,
404436
})
405437
}
406438
}
@@ -424,6 +456,7 @@ pub struct CairoRunner {
424456
pub exec_scopes: ExecutionScopes,
425457
pub relocated_trace: Option<Vec<RelocatedTraceEntry>>,
426458
loaded_program: bool,
459+
hints: Option<Vec<Rc<Box<dyn Any>>>>,
427460
}
428461

429462
#[derive(Clone, Debug, PartialEq)]
@@ -486,6 +519,7 @@ impl CairoRunner {
486519
},
487520
relocated_trace: None,
488521
loaded_program: false,
522+
hints: None,
489523
})
490524
}
491525

@@ -991,6 +1025,57 @@ impl CairoRunner {
9911025
Ok(())
9921026
}
9931027

1028+
pub fn run_until_pc_v2(
1029+
&mut self,
1030+
address: Relocatable,
1031+
hint_processor: &mut dyn HintProcessor,
1032+
) -> Result<(), VirtualMachineError> {
1033+
let references = &self.program.shared_program_data.reference_manager;
1034+
#[cfg_attr(not(feature = "extensive_hints"), allow(unused_mut))]
1035+
let mut hint_data = if let Some(hints) = self.hints.take() {
1036+
hints
1037+
} else {
1038+
self.get_hint_data(references, hint_processor)?
1039+
.into_iter()
1040+
.map(Rc::new)
1041+
.collect()
1042+
};
1043+
#[cfg(feature = "extensive_hints")]
1044+
let mut hint_ranges = self
1045+
.program
1046+
.shared_program_data
1047+
.hints_collection
1048+
.hints_ranges
1049+
.clone();
1050+
while self.vm.get_pc() != address && !hint_processor.consumed() {
1051+
self.vm.step_v2(
1052+
hint_processor,
1053+
&mut self.exec_scopes,
1054+
#[cfg(feature = "extensive_hints")]
1055+
&mut hint_data,
1056+
#[cfg(not(feature = "extensive_hints"))]
1057+
self.program
1058+
.shared_program_data
1059+
.hints_collection
1060+
.get_hint_range_for_pc(self.vm.get_pc().offset)
1061+
.and_then(|range| {
1062+
range.and_then(|(start, length)| hint_data.get(start..start + length.get()))
1063+
})
1064+
.unwrap_or(&[]),
1065+
#[cfg(feature = "extensive_hints")]
1066+
&mut hint_ranges,
1067+
)?;
1068+
1069+
hint_processor.consume_step();
1070+
}
1071+
1072+
if self.vm.get_pc() != address {
1073+
return Err(VirtualMachineError::UnfinishedExecution);
1074+
}
1075+
1076+
Ok(())
1077+
}
1078+
9941079
/// Execute an exact number of steps on the program from the actual position.
9951080
pub fn run_for_steps(
9961081
&mut self,

vm/src/vm/vm_core.rs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::math_utils::signed_felt;
2-
use crate::stdlib::{any::Any, borrow::Cow, collections::HashMap, prelude::*};
2+
use crate::stdlib::{any::Any, borrow::Cow, collections::HashMap, prelude::*, rc::Rc};
33
use crate::types::builtin_name::BuiltinName;
44
#[cfg(feature = "extensive_hints")]
55
use crate::types::program::HintRange;
@@ -535,6 +535,21 @@ impl VirtualMachine {
535535
Ok(())
536536
}
537537

538+
#[cfg(not(feature = "extensive_hints"))]
539+
pub fn step_hint_v2(
540+
&mut self,
541+
hint_processor: &mut dyn HintProcessor,
542+
exec_scopes: &mut ExecutionScopes,
543+
hint_datas: &[Rc<Box<dyn Any>>],
544+
) -> Result<(), VirtualMachineError> {
545+
for (hint_index, hint_data) in hint_datas.iter().enumerate() {
546+
hint_processor
547+
.execute_hint(self, exec_scopes, hint_data.as_ref())
548+
.map_err(|err| VirtualMachineError::Hint(Box::new((hint_index, err))))?
549+
}
550+
Ok(())
551+
}
552+
538553
#[cfg(feature = "extensive_hints")]
539554
pub fn step_hint(
540555
&mut self,
@@ -568,6 +583,39 @@ impl VirtualMachine {
568583
Ok(())
569584
}
570585

586+
#[cfg(feature = "extensive_hints")]
587+
pub fn step_hint_v2(
588+
&mut self,
589+
hint_processor: &mut dyn HintProcessor,
590+
exec_scopes: &mut ExecutionScopes,
591+
hint_datas: &mut Vec<Rc<Box<dyn Any>>>,
592+
hint_ranges: &mut HashMap<Relocatable, HintRange>,
593+
) -> Result<(), VirtualMachineError> {
594+
// Check if there is a hint range for the current pc
595+
if let Some((s, l)) = hint_ranges.get(&self.run_context.pc) {
596+
// Re-binding to avoid mutability problems
597+
let s = *s;
598+
// Execute each hint for the given range
599+
for idx in s..(s + l.get()) {
600+
let hint_data = hint_datas
601+
.get(idx)
602+
.ok_or(VirtualMachineError::Unexpected)?
603+
.as_ref();
604+
let hint_extension = hint_processor
605+
.execute_hint_extensive(self, exec_scopes, hint_data)
606+
.map_err(|err| VirtualMachineError::Hint(Box::new((idx - s, err))))?;
607+
// Update the hint_ranges & hint_datas with the hints added by the executed hint
608+
for (hint_pc, hints) in hint_extension {
609+
if let Ok(len) = NonZeroUsize::try_from(hints.len()) {
610+
hint_ranges.insert(hint_pc, (hint_datas.len(), len));
611+
hint_datas.extend(hints.into_iter().map(Rc::new));
612+
}
613+
}
614+
}
615+
}
616+
Ok(())
617+
}
618+
571619
pub fn step_instruction(&mut self) -> Result<(), VirtualMachineError> {
572620
if self.run_context.pc.segment_index == 0 {
573621
// Run instructions from program segment, using instruction cache
@@ -633,6 +681,27 @@ impl VirtualMachine {
633681
Ok(())
634682
}
635683

684+
pub fn step_v2(
685+
&mut self,
686+
hint_processor: &mut dyn HintProcessor,
687+
exec_scopes: &mut ExecutionScopes,
688+
#[cfg(feature = "extensive_hints")] hint_datas: &mut Vec<Rc<Box<dyn Any>>>,
689+
#[cfg(not(feature = "extensive_hints"))] hint_datas: &[Rc<Box<dyn Any>>],
690+
#[cfg(feature = "extensive_hints")] hint_ranges: &mut HashMap<Relocatable, HintRange>,
691+
) -> Result<(), VirtualMachineError> {
692+
self.step_hint_v2(
693+
hint_processor,
694+
exec_scopes,
695+
hint_datas,
696+
#[cfg(feature = "extensive_hints")]
697+
hint_ranges,
698+
)?;
699+
700+
self.step_instruction()?;
701+
702+
Ok(())
703+
}
704+
636705
fn compute_op0_deductions(
637706
&self,
638707
op0_addr: Relocatable,

0 commit comments

Comments
 (0)