diff --git a/assembly/src/assembler/instruction/mod.rs b/assembly/src/assembler/instruction/mod.rs index 69ad85bff5..dce40e6550 100644 --- a/assembly/src/assembler/instruction/mod.rs +++ b/assembly/src/assembler/instruction/mod.rs @@ -4,7 +4,7 @@ use super::{ }; use crate::utils::bound_into_included_u64; use core::ops::RangeBounds; -use vm_core::{DebugOptions, Decorator, FieldElement, StarkField}; +use vm_core::{Decorator, FieldElement, StarkField}; mod adv_ops; mod crypto_ops; @@ -339,7 +339,7 @@ impl Assembler { Instruction::Debug(options) => { if self.in_debug_mode() { - span.push_decorator(process_debug_options(ctx, options)?) + span.push_decorator(Decorator::Debug(*options)) } Ok(None) } @@ -409,17 +409,17 @@ where }) } -/// Returns a [Decorator::Debug] instance created with information about number of procedure -/// locals. -fn process_debug_options( - ctx: &AssemblyContext, - options: &DebugOptions, -) -> Result { - let num_locals = ctx.num_proc_locals() as u32; - match options { - DebugOptions::LocalInterval(start, end, _) => { - Ok(Decorator::Debug(DebugOptions::LocalInterval(*start, *end, num_locals))) - } - _ => Ok(Decorator::Debug(*options)), - } -} +// / Returns a [Decorator::Debug] instance created with information about number of procedure +// / locals. +// fn process_debug_options( +// ctx: &AssemblyContext, +// options: &DebugOptions, +// ) -> Result { +// let num_locals = ctx.num_proc_locals(); +// match options { +// DebugOptions::LocalInterval(start, end, _) => { +// Ok(Decorator::Debug(DebugOptions::LocalInterval(*start, *end, num_locals))) +// } +// _ => Ok(Decorator::Debug(*options)), +// } +// } diff --git a/assembly/src/ast/mod.rs b/assembly/src/ast/mod.rs index f423d1b6f1..fd0be51d18 100644 --- a/assembly/src/ast/mod.rs +++ b/assembly/src/ast/mod.rs @@ -176,6 +176,7 @@ impl ProgramAst { local_procs: LocalProcMap::default(), reexported_procs: ReExportedProcMap::default(), local_constants, + num_procs_local: 0, }; context.parse_procedures(&mut tokens, false)?; @@ -450,6 +451,7 @@ impl ModuleAst { local_procs: LocalProcMap::default(), reexported_procs: ReExportedProcMap::default(), local_constants, + num_procs_local: 0, }; context.parse_procedures(&mut tokens, true)?; diff --git a/assembly/src/ast/nodes/serde/debug.rs b/assembly/src/ast/nodes/serde/debug.rs index d00b04e261..27db78bf4d 100644 --- a/assembly/src/ast/nodes/serde/debug.rs +++ b/assembly/src/ast/nodes/serde/debug.rs @@ -22,9 +22,9 @@ pub fn write_options_into(target: &mut W, options: &DebugOptions) } DebugOptions::LocalInterval(start, end, num_locals) => { target.write_u8(LOCAL_INTERVAL); - target.write_u32(*start); - target.write_u32(*end); - target.write_u32(*num_locals); + target.write_u16(*start); + target.write_u16(*end); + target.write_u16(*num_locals); } } } @@ -49,9 +49,9 @@ pub fn read_options_from( Ok(DebugOptions::MemInterval(n, m)) } LOCAL_INTERVAL => { - let n = source.read_u32()?; - let m = source.read_u32()?; - let num_locals = source.read_u32()?; + let n = source.read_u16()?; + let m = source.read_u16()?; + let num_locals = source.read_u16()?; Ok(DebugOptions::LocalInterval(n, m, num_locals)) } val => Err(DeserializationError::InvalidValue(val.to_string())), diff --git a/assembly/src/ast/parsers/context.rs b/assembly/src/ast/parsers/context.rs index f8ac5b1280..8bea81a0ca 100644 --- a/assembly/src/ast/parsers/context.rs +++ b/assembly/src/ast/parsers/context.rs @@ -15,6 +15,7 @@ pub struct ParserContext<'a> { pub local_procs: LocalProcMap, pub reexported_procs: ReExportedProcMap, pub local_constants: LocalConstMap, + pub num_procs_local: u16, } impl ParserContext<'_> { @@ -290,9 +291,13 @@ impl ParserContext<'_> { None }; + self.num_procs_local = num_locals; + // parse procedure body let body = self.parse_body(tokens, false)?; + self.num_procs_local = 0; + // consume the 'end' token match tokens.read() { None => { @@ -623,7 +628,7 @@ impl ParserContext<'_> { // ----- debug decorators ------------------------------------------------------------- "breakpoint" => simple_instruction(op, Breakpoint), - "debug" => debug::parse_debug(op), + "debug" => debug::parse_debug(op, self.num_procs_local), // ----- catch all -------------------------------------------------------------------- _ => Err(ParsingError::invalid_op(op)), diff --git a/assembly/src/ast/parsers/debug.rs b/assembly/src/ast/parsers/debug.rs index 4d7d3852e6..0710bb706e 100644 --- a/assembly/src/ast/parsers/debug.rs +++ b/assembly/src/ast/parsers/debug.rs @@ -14,7 +14,7 @@ use vm_core::DebugOptions; /// # Errors /// Returns an error if the instruction token contains a wrong number of parameters, or if /// the provided parameters are not valid. -pub fn parse_debug(op: &Token) -> Result { +pub fn parse_debug(op: &Token, num_procs_local: u16) -> Result { debug_assert_eq!(op.parts()[0], "debug"); if op.num_parts() < 2 { return Err(ParsingError::missing_param(op, "debug.stack.")); @@ -46,18 +46,18 @@ pub fn parse_debug(op: &Token) -> Result { _ => return Err(ParsingError::extra_param(op)), }, "local" => match op.num_parts() { - 2 => DebugOptions::LocalInterval(0, 2u32.pow(16), 0), + 2 => DebugOptions::LocalInterval(0, u16::MAX, num_procs_local), 3 => { - let n: u32 = parse_checked_param(op, 2, 0..=u16::MAX as u32)?; - DebugOptions::LocalInterval(n, n, 0) + let n: u16 = parse_checked_param(op, 2, 0..=u16::MAX)?; + DebugOptions::LocalInterval(n, n, num_procs_local) } 4 => { - let n: u32 = parse_checked_param(op, 2, 0..=u16::MAX as u32)?; - let m: u32 = parse_checked_param(op, 3, 0..=u16::MAX as u32)?; + let n: u16 = parse_checked_param(op, 2, 0..=u16::MAX)?; + let m: u16 = parse_checked_param(op, 3, 0..=u16::MAX)?; if m < n { return Err(ParsingError::invalid_param_with_reason(op, 3, "the index of the end of the interval must be greater than the index of its beginning")); } - DebugOptions::LocalInterval(n, m, 0) + DebugOptions::LocalInterval(n, m, num_procs_local) } _ => return Err(ParsingError::extra_param(op)), }, diff --git a/core/src/operations/decorators/debug.rs b/core/src/operations/decorators/debug.rs index a84c2f478d..90f276abc1 100644 --- a/core/src/operations/decorators/debug.rs +++ b/core/src/operations/decorators/debug.rs @@ -25,7 +25,7 @@ pub enum DebugOptions { /// /// First parameter specifies the starting address, second -- the ending address, and the third /// specifies the overall number of locals. - LocalInterval(u32, u32, u32), + LocalInterval(u16, u16, u16), } impl fmt::Display for DebugOptions { diff --git a/processor/src/host/debug.rs b/processor/src/host/debug.rs index 27b34d7d7e..5695fd1d20 100644 --- a/processor/src/host/debug.rs +++ b/processor/src/host/debug.rs @@ -1,6 +1,6 @@ use super::ProcessState; use crate::Vec; -use vm_core::{utils::string::ToString, DebugOptions, StarkField, Word}; +use vm_core::{DebugOptions, StarkField, Word}; // DEBUG HANDLER // ================================================================================================ @@ -22,7 +22,7 @@ pub fn print_debug_info(process: &S, options: &DebugOptions) { printer.print_mem_interval(process, *n, *m); } DebugOptions::LocalInterval(n, m, num_locals) => { - printer.print_local_interval(process, (*n, *m), *num_locals); + printer.print_local_interval(process, (*n as u32, *m as u32), *num_locals as u32); } } } @@ -71,7 +71,8 @@ impl Printer { /// Prints the whole memory state at the cycle `clk` in context `ctx`. fn print_mem_all(&self, process: &S) { let mem = process.get_mem_state(self.ctx); - let padding = mem.iter().fold(0, |max, value| word_elem_max_len(Some(value.1)).max(max)); + let padding = + mem.iter().fold(0, |max, value| word_elem_max_len(Some(value.1)).max(max)) as usize; println!("Memory state before step {} for the context {}:", self.clk, self.ctx); @@ -119,7 +120,7 @@ impl Printer { let local_memory_offset = self.fmp - num_locals + 1; // in case start index is 0 and end index is 2^16, we should print all available locals. - let (start, end) = if interval.0 == 0 && interval.1 == 2u32.pow(16) { + let (start, end) = if interval.0 == 0 && interval.1 == u16::MAX as u32 { (0, num_locals - 1) } else { interval @@ -129,7 +130,7 @@ impl Printer { .push((index, process.get_mem_value(self.ctx, index + local_memory_offset))) } - if interval.0 == 0 && interval.1 == 2u32.pow(16) { + if interval.0 == 0 && interval.1 == u16::MAX as u32 { println!("Local state before step {} for the context {}:", self.clk, self.ctx) } else if interval.0 == interval.1 { println!( @@ -155,7 +156,8 @@ impl Printer { /// If `is_local` is true, the output addresses are formatted as decimal values, otherwise as hex /// strings. fn print_interval(mem_interval: Vec<(u32, Option)>, is_local: bool) { - let padding = mem_interval.iter().fold(0, |max, value| word_elem_max_len(value.1).max(max)); + let padding = + mem_interval.iter().fold(0, |max, value| word_elem_max_len(value.1).max(max)) as usize; // print the main part of the memory (wihtout the last value) for (addr, value) in mem_interval.iter().take(mem_interval.len() - 1) { @@ -182,42 +184,19 @@ fn print_mem_address( if let Some(value) = value { if is_last { if is_local { - println!( - "└── {addr:>5}: [{:>width$}, {:>width$}, {:>width$}, {:>width$}]\n", - value[0].as_int(), - value[1].as_int(), - value[2].as_int(), - value[3].as_int(), - width = padding - ) + print!("└── {addr:>5}: "); } else { - println!( - "└── {addr:#010x}: [{:>width$}, {:>width$}, {:>width$}, {:>width$}]\n", - value[0].as_int(), - value[1].as_int(), - value[2].as_int(), - value[3].as_int(), - width = padding - ) + print!("└── {addr:#010x}: "); } - } else if is_local { - println!( - "├── {addr:>5}: [{:>width$}, {:>width$}, {:>width$}, {:>width$}]", - value[0].as_int(), - value[1].as_int(), - value[2].as_int(), - value[3].as_int(), - width = padding - ) + print_word(value, padding); + println!(); } else { - println!( - "├── {addr:#010x}: [{:>width$}, {:>width$}, {:>width$}, {:>width$}]", - value[0].as_int(), - value[1].as_int(), - value[2].as_int(), - value[3].as_int(), - width = padding - ) + if is_local { + print!("├── {addr:>5}: "); + } else { + print!("├── {addr:#010x}: "); + } + print_word(value, padding); } } else if is_last { if is_local { @@ -232,10 +211,23 @@ fn print_mem_address( } } +/// Prints the provided Word with specified padding. +fn print_word(value: Word, padding: usize) { + println!( + "[{:>width$}, {:>width$}, {:>width$}, {:>width$}]", + value[0].as_int(), + value[1].as_int(), + value[2].as_int(), + value[3].as_int(), + width = padding + ) +} + /// Returns the maximum length among the word elements. -fn word_elem_max_len(word: Option) -> usize { +fn word_elem_max_len(word: Option) -> u32 { if let Some(word) = word { - word.iter().fold(0, |max, value| value.as_int().to_string().len().max(max)) + word.iter() + .fold(0, |max, value| (value.as_int().checked_ilog10().unwrap_or(1) + 1).max(max)) } else { 0 }