diff --git a/CHANGELOG.md b/CHANGELOG.md index a8c10f0fbc..c672581aab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ #### Upcoming Changes +* opt(breaking): Optimize Cairo 0 Execution [#2206](https://github.com/lambdaclass/cairo-vm/pull/2206) + #### [2.5.0] - 2025-09-11 * breaking: Store constants in Hint Data [#2191](https://github.com/lambdaclass/cairo-vm/pull/2191) diff --git a/vm/src/hint_processor/hint_processor_definition.rs b/vm/src/hint_processor/hint_processor_definition.rs index 60d57772ee..e21d7c860c 100644 --- a/vm/src/hint_processor/hint_processor_definition.rs +++ b/vm/src/hint_processor/hint_processor_definition.rs @@ -80,7 +80,7 @@ fn get_ids_data( reference_ids: &HashMap, references: &[HintReference], ) -> Result, VirtualMachineError> { - let mut ids_data = HashMap::::new(); + let mut ids_data = HashMap::::with_capacity(reference_ids.len()); for (path, ref_id) in reference_ids { let name = path .rsplit('.') diff --git a/vm/src/vm/vm_memory/memory.rs b/vm/src/vm/vm_memory/memory.rs index c3546f7d00..31f7477e3b 100644 --- a/vm/src/vm/vm_memory/memory.rs +++ b/vm/src/vm/vm_memory/memory.rs @@ -744,6 +744,58 @@ impl Memory { self.mark_as_accessed(key); Ok(()) } + + /// Inserts multiple values into contiguous memory addresses. + /// + /// If the address isn't contiguous with previously inserted data, memory gaps will be represented by NONE values + /// + /// Returns an error if: + /// - The segment index given by the address corresponds to a non-allocated segment. + /// - An inserted value is inconsistent with the current value at the memory cell + pub fn insert_all( + &mut self, + key: Relocatable, + vals: &[MaybeRelocatable], + ) -> Result<(), MemoryError> { + let segment = self.get_segment(key)?; + let (_, value_offset) = from_relocatable_to_indexes(key); + + // Allocate space for all new elements. + if segment.len() < value_offset + vals.len() { + segment.reserve(value_offset + vals.len() - segment.len()); + } + // Fill middle with NONE. + if segment.len() < value_offset { + segment.resize(value_offset, MemoryCell::NONE); + } + // Insert new elements. + let last_element_to_replace = segment.len().min(value_offset + vals.len()); + let replaced = segment.splice( + value_offset..last_element_to_replace, + vals.iter().map(|v| MemoryCell::new(v.clone())), + ); + + // Check for inconsistencies. + let inconsistent_cell = replaced.enumerate().find(|(idx, replaced)| { + replaced + .get_value() + .is_some_and(|replaced| replaced != vals[*idx]) + }); + if let Some((insertions_idx, current_value)) = inconsistent_cell { + return Err(MemoryError::InconsistentMemory(Box::new(( + (key + insertions_idx)?, + current_value.into(), + vals[insertions_idx].clone(), + )))); + } + + // Validate inserted memory cells + for i in 0..vals.len() { + self.validate_memory_cell((key + i)?)?; + } + + Ok(()) + } } impl From<&Memory> for CairoPieMemory { diff --git a/vm/src/vm/vm_memory/memory_segments.rs b/vm/src/vm/vm_memory/memory_segments.rs index e18e739346..504a038ac8 100644 --- a/vm/src/vm/vm_memory/memory_segments.rs +++ b/vm/src/vm/vm_memory/memory_segments.rs @@ -70,10 +70,8 @@ impl MemorySegmentManager { ptr: Relocatable, data: &[MaybeRelocatable], ) -> Result { - // Starting from the end ensures any necessary resize - // is performed once with enough room for everything - for (num, value) in data.iter().enumerate().rev() { - self.memory.insert((ptr + num)?, value)?; + if !data.is_empty() { + self.memory.insert_all(ptr, data)?; } (ptr + data.len()).map_err(MemoryError::Math) }