Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow running instructions from pcs outside the program segment #1493

Merged
merged 30 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b0073a1
Add back RelocataedTrace struct
fmoletta Nov 23, 2023
f85e52c
Move relocated trace back to runner
fmoletta Nov 23, 2023
9f093ac
Remove trace relocation from vm
fmoletta Nov 23, 2023
ab9eb1a
Fix test
fmoletta Nov 23, 2023
f61c82c
Update tests
fmoletta Nov 23, 2023
c47c41c
clippy
fmoletta Nov 23, 2023
def1bbe
clippy
fmoletta Nov 23, 2023
94393f1
Remove dbg print + add changelog entry
fmoletta Nov 23, 2023
f3436d5
Add test check
fmoletta Nov 23, 2023
1a81ed1
Add test check
fmoletta Nov 23, 2023
54c4ac2
Add missing wasm import
fmoletta Nov 23, 2023
c024166
Merge branch 'main' of github.com:lambdaclass/cairo-vm into revert-tr…
fmoletta Nov 23, 2023
83335e6
Only use instruction cache when running from program segment
fmoletta Nov 24, 2023
dd7994d
Add test
fmoletta Nov 24, 2023
ef9f9e5
Merge branch 'revert-trace-optimization' into run-instruction-from-ot…
fmoletta Nov 24, 2023
df19f11
Update test
fmoletta Nov 24, 2023
8a527c5
Add unit tests
fmoletta Nov 24, 2023
90720ee
Fmt
fmoletta Nov 24, 2023
add9934
Add changelog entry
fmoletta Nov 24, 2023
200dd7a
Fix pr num
fmoletta Nov 24, 2023
da24777
Merge branch 'revert-trace-optimization' into run-instruction-from-ot…
fmoletta Nov 24, 2023
aad4dc9
Make relocate_trace public
fmoletta Nov 24, 2023
5c517d8
List breaking changes
fmoletta Nov 24, 2023
8ca276f
List pr purpose in changelog
fmoletta Nov 24, 2023
4ff9c3a
Merge branch 'revert-trace-optimization' into run-instruction-from-ot…
fmoletta Nov 24, 2023
97b98ba
Merge branch 'main' into run-instruction-from-other-pc
fmoletta Nov 27, 2023
a71142f
Merge branch 'main' into run-instruction-from-other-pc
fmoletta Nov 27, 2023
cea1104
Merge branch 'run-instruction-from-other-pc' of github.com:lambdaclas…
fmoletta Nov 28, 2023
b175a3c
Fix tests
fmoletta Nov 28, 2023
2a3a0fb
Merge branch 'main' into run-instruction-from-other-pc
pefontana Nov 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#### Upcoming Changes

* feat: Allow running instructions from pcs outside the program segement [#1493](https://github.com/lambdaclass/cairo-vm/pull/14923)

* BREAKING: Partially Revert `Optimize trace relocation #906` [#1492](https://github.com/lambdaclass/cairo-vm/pull/1492)

* Remove methods `VirtualMachine::get_relocated_trace`& `VirtualMachine::relocate_trace`.
Expand Down
24 changes: 8 additions & 16 deletions fuzzer/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

220 changes: 204 additions & 16 deletions vm/src/vm/vm_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,27 +454,41 @@ impl VirtualMachine {
}

pub fn step_instruction(&mut self) -> Result<(), VirtualMachineError> {
let pc = self.run_context.pc.offset;
if self.run_context.pc.segment_index == 0 {
// Run instructions from program segment, using instruction cache
let pc = self.run_context.pc.offset;

if self.segments.memory.data[0].len() <= pc {
return Err(MemoryError::UnknownMemoryCell(Box::new((0, pc).into())))?;
}
if self.segments.memory.data[0].len() <= pc {
return Err(MemoryError::UnknownMemoryCell(Box::new((0, pc).into())))?;
}

let mut inst_cache = core::mem::take(&mut self.instruction_cache);
inst_cache.resize((pc + 1).max(inst_cache.len()), None);
let mut inst_cache = core::mem::take(&mut self.instruction_cache);
inst_cache.resize((pc + 1).max(inst_cache.len()), None);

let instruction = inst_cache.get_mut(pc).unwrap();
if instruction.is_none() {
*instruction = Some(self.decode_current_instruction()?);
}
let instruction = instruction.as_ref().unwrap();
if !self.skip_instruction_execution {
self.run_instruction(instruction)?;
let instruction = inst_cache.get_mut(pc).unwrap();
if instruction.is_none() {
*instruction = Some(self.decode_current_instruction()?);
}
let instruction = instruction.as_ref().unwrap();

if !self.skip_instruction_execution {
self.run_instruction(instruction)?;
} else {
self.run_context.pc += instruction.size();
self.skip_instruction_execution = false;
}
self.instruction_cache = inst_cache;
} else {
self.run_context.pc += instruction.size();
self.skip_instruction_execution = false;
// Run instructions from programs loaded in other segments, without instruction cache
let instruction = self.decode_current_instruction()?;

if !self.skip_instruction_execution {
self.run_instruction(&instruction)?;
} else {
self.run_context.pc += instruction.size();
self.skip_instruction_execution = false;
}
}
self.instruction_cache = inst_cache;
Ok(())
}

Expand Down Expand Up @@ -4268,4 +4282,178 @@ mod tests {
.is_err());
}
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
/// Test for a simple program execution
/// Used program code:
/// func main():
/// let a = 1
/// let b = 2
/// let c = a + b
/// return()
/// end
/// Memory taken from original vm
/// {RelocatableValue(segment_index=0, offset=0): 2345108766317314046,
/// RelocatableValue(segment_index=1, offset=0): RelocatableValue(segment_index=2, offset=0),
/// RelocatableValue(segment_index=1, offset=1): RelocatableValue(segment_index=3, offset=0)}
/// Current register values:
/// AP 1:2
/// FP 1:2
/// PC 0:0
fn test_step_for_preset_memory_program_loaded_into_user_segment() {
let mut vm = vm!(true);

let mut hint_processor = BuiltinHintProcessor::new_empty();

run_context!(vm, 0, 2, 2);

vm.segments = segments![
((2, 0), 2345108766317314046_u64), // Load program into new segment
((1, 0), (2, 0)),
((1, 1), (3, 0))
];
// set starting pc on new segemt to run loaded program
vm.run_context.pc.segment_index = 2;

assert_matches!(
vm.step(
&mut hint_processor,
exec_scopes_ref!(),
&Vec::new(),
&HashMap::new()
),
Ok(())
);
let trace = vm.trace.unwrap();
trace_check(&trace, &[((2, 0).into(), 2, 2)]);

assert_eq!(vm.run_context.pc, Relocatable::from((3, 0)));
assert_eq!(vm.run_context.ap, 2);
assert_eq!(vm.run_context.fp, 0);

//Check that the following addresses have been accessed:
// Addresses have been copied from python execution:
let mem = vm.segments.memory.data;
assert!(mem[1][0].as_ref().unwrap().is_accessed());
assert!(mem[1][1].as_ref().unwrap().is_accessed());
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
/*
Test for a simple program execution
Used program code:
func myfunc(a: felt) -> (r: felt):
let b = a * 2
return(b)
end
func main():
let a = 1
let b = myfunc(a)
return()
end
Memory taken from original vm:
{RelocatableValue(segment_index=0, offset=0): 5207990763031199744,
RelocatableValue(segment_index=0, offset=1): 2,
RelocatableValue(segment_index=0, offset=2): 2345108766317314046,
RelocatableValue(segment_index=0, offset=3): 5189976364521848832,
RelocatableValue(segment_index=0, offset=4): 1,
RelocatableValue(segment_index=0, offset=5): 1226245742482522112,
RelocatableValue(segment_index=0, offset=6): 3618502788666131213697322783095070105623107215331596699973092056135872020476,
RelocatableValue(segment_index=0, offset=7): 2345108766317314046,
RelocatableValue(segment_index=1, offset=0): RelocatableValue(segment_index=2, offset=0),
RelocatableValue(segment_index=1, offset=1): RelocatableValue(segment_index=3, offset=0)}
Current register values:
AP 1:2
FP 1:2
PC 0:3
Final Pc (not executed): 3:0
This program consists of 5 steps
*/
fn test_step_for_preset_memory_function_call_program_loaded_into_user_segment() {
let mut vm = vm!(true);

run_context!(vm, 3, 2, 2);
// set starting pc on new segemt to run loaded program
vm.run_context.pc.segment_index = 4;

//Insert values into memory
vm.segments.memory =
memory![
// Load program into new segment
((4, 0), 5207990763031199744_i64),
((4, 1), 2),
((4, 2), 2345108766317314046_i64),
((4, 3), 5189976364521848832_i64),
((4, 4), 1),
((4, 5), 1226245742482522112_i64),
(
(4, 6),
("3618502788666131213697322783095070105623107215331596699973092056135872020476",10)
),
((4, 7), 2345108766317314046_i64),
((1, 0), (2, 0)),
((1, 1), (3, 0))
];

let final_pc = Relocatable::from((3, 0));
let mut hint_processor = BuiltinHintProcessor::new_empty();
//Run steps
while vm.run_context.pc != final_pc {
assert_matches!(
vm.step(
&mut hint_processor,
exec_scopes_ref!(),
&Vec::new(),
&HashMap::new()
),
Ok(())
);
}

//Check final register values
assert_eq!(vm.run_context.pc, Relocatable::from((3, 0)));

assert_eq!(vm.run_context.ap, 6);

assert_eq!(vm.run_context.fp, 0);
//Check each TraceEntry in trace
let trace = vm.trace.unwrap();
assert_eq!(trace.len(), 5);
trace_check(
&trace,
&[
((4, 3).into(), 2, 2),
((4, 5).into(), 3, 2),
((4, 0).into(), 5, 5),
((4, 2).into(), 6, 5),
((4, 7).into(), 6, 2),
],
);
//Check that the following addresses have been accessed:
// Addresses have been copied from python execution:
let mem = &vm.segments.memory.data;
assert!(mem[4][1].as_ref().unwrap().is_accessed());
assert!(mem[4][4].as_ref().unwrap().is_accessed());
assert!(mem[4][6].as_ref().unwrap().is_accessed());
assert!(mem[1][0].as_ref().unwrap().is_accessed());
assert!(mem[1][1].as_ref().unwrap().is_accessed());
assert!(mem[1][2].as_ref().unwrap().is_accessed());
assert!(mem[1][3].as_ref().unwrap().is_accessed());
assert!(mem[1][4].as_ref().unwrap().is_accessed());
assert!(mem[1][5].as_ref().unwrap().is_accessed());
assert_eq!(
vm.segments
.memory
.get_amount_of_accessed_addresses_for_segment(4),
Some(3)
);
assert_eq!(
vm.segments
.memory
.get_amount_of_accessed_addresses_for_segment(1),
Some(6)
);
}
}