1use alloc::{
43 collections::BTreeMap,
44 string::{String, ToString},
45 sync::Arc,
46 vec::Vec,
47};
48
49use miden_debug_types::{FileLineCol, Location};
50#[cfg(feature = "serde")]
51use serde::{Deserialize, Serialize};
52
53use super::{AsmOpId, Decorator, DecoratorId, MastForestError, MastNodeId};
54use crate::{
55 LexicographicWord, Word,
56 mast::serialization::{
57 StringTable,
58 asm_op::{AsmOpDataBuilder, AsmOpInfo},
59 decorator::{DecoratorDataBuilder, DecoratorInfo},
60 },
61 operations::{AssemblyOp, DebugVarInfo},
62 serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
63 utils::{Idx, IndexVec},
64};
65
66mod asm_op_storage;
67pub use asm_op_storage::{AsmOpIndexError, OpToAsmOpId};
68
69mod decorator_storage;
70pub use decorator_storage::{
71 DecoratedLinks, DecoratedLinksIter, DecoratorIndexError, OpToDecoratorIds,
72};
73
74mod debug_var_storage;
75pub use debug_var_storage::{DebugVarId, OpToDebugVarIds};
76
77mod node_decorator_storage;
78pub use node_decorator_storage::NodeToDecoratorIds;
79
80#[derive(Debug, Clone, PartialEq, Eq)]
85#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
86pub struct DebugInfo {
87 decorators: IndexVec<DecoratorId, Decorator>,
89
90 op_decorator_storage: OpToDecoratorIds,
92
93 node_decorator_storage: NodeToDecoratorIds,
95
96 asm_ops: IndexVec<AsmOpId, AssemblyOp>,
98
99 asm_op_storage: OpToAsmOpId,
101
102 debug_vars: IndexVec<DebugVarId, DebugVarInfo>,
104
105 op_debug_var_storage: OpToDebugVarIds,
107
108 error_codes: BTreeMap<u64, Arc<str>>,
110
111 #[cfg_attr(feature = "serde", serde(skip))]
113 procedure_names: BTreeMap<LexicographicWord, Arc<str>>,
114}
115
116impl DebugInfo {
117 pub fn new() -> Self {
122 Self {
123 decorators: IndexVec::new(),
124 op_decorator_storage: OpToDecoratorIds::new(),
125 node_decorator_storage: NodeToDecoratorIds::new(),
126 asm_ops: IndexVec::new(),
127 asm_op_storage: OpToAsmOpId::new(),
128 debug_vars: IndexVec::new(),
129 op_debug_var_storage: OpToDebugVarIds::new(),
130 error_codes: BTreeMap::new(),
131 procedure_names: BTreeMap::new(),
132 }
133 }
134
135 pub fn with_capacity(
137 decorators_capacity: usize,
138 nodes_capacity: usize,
139 operations_capacity: usize,
140 decorator_ids_capacity: usize,
141 ) -> Self {
142 Self {
143 decorators: IndexVec::with_capacity(decorators_capacity),
144 op_decorator_storage: OpToDecoratorIds::with_capacity(
145 nodes_capacity,
146 operations_capacity,
147 decorator_ids_capacity,
148 ),
149 node_decorator_storage: NodeToDecoratorIds::with_capacity(nodes_capacity, 0, 0),
150 asm_ops: IndexVec::new(),
151 asm_op_storage: OpToAsmOpId::new(),
152 debug_vars: IndexVec::new(),
153 op_debug_var_storage: OpToDebugVarIds::new(),
154 error_codes: BTreeMap::new(),
155 procedure_names: BTreeMap::new(),
156 }
157 }
158
159 pub fn empty_for_nodes(num_nodes: usize) -> Self {
161 let node_indptr_for_op_idx = IndexVec::try_from(vec![0; num_nodes + 1])
162 .expect("num_nodes should not exceed u32::MAX");
163
164 let op_decorator_storage =
165 OpToDecoratorIds::from_components(Vec::new(), Vec::new(), node_indptr_for_op_idx)
166 .expect("Empty CSR structure should be valid");
167
168 Self {
169 decorators: IndexVec::new(),
170 op_decorator_storage,
171 node_decorator_storage: NodeToDecoratorIds::new(),
172 asm_ops: IndexVec::new(),
173 asm_op_storage: OpToAsmOpId::new(),
174 debug_vars: IndexVec::new(),
175 op_debug_var_storage: OpToDebugVarIds::new(),
176 error_codes: BTreeMap::new(),
177 procedure_names: BTreeMap::new(),
178 }
179 }
180
181 pub fn is_empty(&self) -> bool {
187 self.decorators.is_empty()
188 && self.asm_ops.is_empty()
189 && self.debug_vars.is_empty()
190 && self.error_codes.is_empty()
191 && self.procedure_names.is_empty()
192 }
193
194 pub fn clear(&mut self) {
200 self.clear_mappings();
201 self.decorators = IndexVec::new();
202 self.asm_ops = IndexVec::new();
203 self.asm_op_storage = OpToAsmOpId::new();
204 self.debug_vars = IndexVec::new();
205 self.op_debug_var_storage.clear();
206 self.error_codes.clear();
207 self.procedure_names.clear();
208 }
209
210 pub fn num_decorators(&self) -> usize {
215 self.decorators.len()
216 }
217
218 pub fn decorators(&self) -> &[Decorator] {
220 self.decorators.as_slice()
221 }
222
223 pub fn decorator(&self, decorator_id: DecoratorId) -> Option<&Decorator> {
225 self.decorators.get(decorator_id)
226 }
227
228 pub fn before_enter_decorators(&self, node_id: MastNodeId) -> &[DecoratorId] {
230 self.node_decorator_storage.get_before_decorators(node_id)
231 }
232
233 pub fn after_exit_decorators(&self, node_id: MastNodeId) -> &[DecoratorId] {
235 self.node_decorator_storage.get_after_decorators(node_id)
236 }
237
238 pub fn decorators_for_operation(
240 &self,
241 node_id: MastNodeId,
242 local_op_idx: usize,
243 ) -> &[DecoratorId] {
244 self.op_decorator_storage
245 .decorator_ids_for_operation(node_id, local_op_idx)
246 .unwrap_or(&[])
247 }
248
249 pub(super) fn decorator_links_for_node(
251 &self,
252 node_id: MastNodeId,
253 ) -> Result<DecoratedLinks<'_>, DecoratorIndexError> {
254 self.op_decorator_storage.decorator_links_for_node(node_id)
255 }
256
257 pub fn num_debug_vars(&self) -> usize {
262 self.debug_vars.len()
263 }
264
265 pub fn debug_vars(&self) -> &[DebugVarInfo] {
267 self.debug_vars.as_slice()
268 }
269
270 pub fn debug_var(&self, debug_var_id: DebugVarId) -> Option<&DebugVarInfo> {
272 self.debug_vars.get(debug_var_id)
273 }
274
275 pub fn debug_vars_for_operation(
277 &self,
278 node_id: MastNodeId,
279 local_op_idx: usize,
280 ) -> &[DebugVarId] {
281 self.op_debug_var_storage
282 .debug_var_ids_for_operation(node_id, local_op_idx)
283 .unwrap_or(&[])
284 }
285
286 pub fn add_decorator(&mut self, decorator: Decorator) -> Result<DecoratorId, MastForestError> {
291 self.decorators.push(decorator).map_err(|_| MastForestError::TooManyDecorators)
292 }
293
294 pub(super) fn decorator_mut(&mut self, decorator_id: DecoratorId) -> Option<&mut Decorator> {
296 if decorator_id.to_usize() < self.decorators.len() {
297 Some(&mut self.decorators[decorator_id])
298 } else {
299 None
300 }
301 }
302
303 pub(super) fn register_node_decorators(
309 &mut self,
310 node_id: MastNodeId,
311 before_enter: &[DecoratorId],
312 after_exit: &[DecoratorId],
313 ) {
314 self.node_decorator_storage
315 .add_node_decorators(node_id, before_enter, after_exit);
316 }
317
318 pub(crate) fn register_op_indexed_decorators(
322 &mut self,
323 node_id: MastNodeId,
324 decorators_info: Vec<(usize, DecoratorId)>,
325 ) -> Result<(), crate::mast::debuginfo::decorator_storage::DecoratorIndexError> {
326 self.op_decorator_storage.add_decorator_info_for_node(node_id, decorators_info)
327 }
328
329 pub fn clear_mappings(&mut self) {
333 self.op_decorator_storage = OpToDecoratorIds::new();
334 self.node_decorator_storage.clear();
335 }
336
337 pub fn num_asm_ops(&self) -> usize {
342 self.asm_ops.len()
343 }
344
345 pub fn asm_ops(&self) -> &[AssemblyOp] {
347 self.asm_ops.as_slice()
348 }
349
350 pub fn asm_op(&self, asm_op_id: AsmOpId) -> Option<&AssemblyOp> {
352 self.asm_ops.get(asm_op_id)
353 }
354
355 pub fn asm_op_for_operation(&self, node_id: MastNodeId, op_idx: usize) -> Option<&AssemblyOp> {
357 let asm_op_id = self.asm_op_storage.asm_op_id_for_operation(node_id, op_idx)?;
358 self.asm_ops.get(asm_op_id)
359 }
360
361 pub fn first_asm_op_for_node(&self, node_id: MastNodeId) -> Option<&AssemblyOp> {
363 let asm_op_id = self.asm_op_storage.first_asm_op_for_node(node_id)?;
364 self.asm_ops.get(asm_op_id)
365 }
366
367 pub fn add_asm_op(&mut self, asm_op: AssemblyOp) -> Result<AsmOpId, MastForestError> {
372 self.asm_ops.push(asm_op).map_err(|_| MastForestError::TooManyDecorators)
373 }
374
375 pub fn rewrite_source_locations(
377 &mut self,
378 mut rewrite_location: impl FnMut(Location) -> Location,
379 mut rewrite_file_line_col: impl FnMut(FileLineCol) -> FileLineCol,
380 ) {
381 for asm_op in self.asm_ops.iter_mut() {
382 if let Some(location) = asm_op.location().cloned() {
383 asm_op.set_location(rewrite_location(location));
384 }
385 }
386
387 for debug_var in self.debug_vars.iter_mut() {
388 if let Some(location) = debug_var.location().cloned() {
389 debug_var.set_location(rewrite_file_line_col(location));
390 }
391 }
392 }
393
394 pub fn register_asm_ops(
400 &mut self,
401 node_id: MastNodeId,
402 num_operations: usize,
403 asm_ops: Vec<(usize, AsmOpId)>,
404 ) -> Result<(), AsmOpIndexError> {
405 self.asm_op_storage.add_asm_ops_for_node(node_id, num_operations, asm_ops)
406 }
407
408 pub(super) fn remap_asm_op_storage(&mut self, remapping: &BTreeMap<MastNodeId, MastNodeId>) {
413 self.asm_op_storage = self.asm_op_storage.remap_nodes(remapping);
414 }
415
416 pub fn add_debug_var(
421 &mut self,
422 debug_var: DebugVarInfo,
423 ) -> Result<DebugVarId, MastForestError> {
424 self.debug_vars.push(debug_var).map_err(|_| MastForestError::TooManyDecorators)
425 }
426
427 pub fn register_op_indexed_debug_vars(
431 &mut self,
432 node_id: MastNodeId,
433 debug_vars_info: Vec<(usize, DebugVarId)>,
434 ) -> Result<(), crate::mast::debuginfo::decorator_storage::DecoratorIndexError> {
435 self.op_debug_var_storage.add_debug_var_info_for_node(node_id, debug_vars_info)
436 }
437
438 pub fn error_message(&self, code: u64) -> Option<Arc<str>> {
443 self.error_codes.get(&code).cloned()
444 }
445
446 pub fn error_codes(&self) -> impl Iterator<Item = (&u64, &Arc<str>)> {
448 self.error_codes.iter()
449 }
450
451 pub fn insert_error_code(&mut self, code: u64, msg: Arc<str>) {
453 self.error_codes.insert(code, msg);
454 }
455
456 pub fn extend_error_codes<I>(&mut self, error_codes: I)
460 where
461 I: IntoIterator<Item = (u64, Arc<str>)>,
462 {
463 self.error_codes.extend(error_codes);
464 }
465
466 pub fn clear_error_codes(&mut self) {
470 self.error_codes.clear();
471 }
472
473 pub fn procedure_name(&self, digest: &Word) -> Option<&str> {
478 self.procedure_names.get(&LexicographicWord::from(*digest)).map(|s| s.as_ref())
479 }
480
481 pub fn procedure_names(&self) -> impl Iterator<Item = (Word, &Arc<str>)> {
483 self.procedure_names.iter().map(|(key, name)| (key.into_inner(), name))
484 }
485
486 pub fn num_procedure_names(&self) -> usize {
488 self.procedure_names.len()
489 }
490
491 pub fn insert_procedure_name(&mut self, digest: Word, name: Arc<str>) {
493 self.procedure_names.insert(LexicographicWord::from(digest), name);
494 }
495
496 pub fn extend_procedure_names<I>(&mut self, names: I)
498 where
499 I: IntoIterator<Item = (Word, Arc<str>)>,
500 {
501 self.procedure_names
502 .extend(names.into_iter().map(|(d, n)| (LexicographicWord::from(d), n)));
503 }
504
505 pub fn clear_procedure_names(&mut self) {
507 self.procedure_names.clear();
508 }
509
510 pub(super) fn validate(&self) -> Result<(), String> {
524 let decorator_count = self.decorators.len();
525 let asm_op_count = self.asm_ops.len();
526
527 self.op_decorator_storage.validate_csr(decorator_count)?;
529
530 self.node_decorator_storage.validate_csr(decorator_count)?;
532
533 self.asm_op_storage.validate_csr(asm_op_count)?;
535
536 let debug_var_count = self.debug_vars.len();
538 self.op_debug_var_storage.validate_csr(debug_var_count)?;
539
540 Ok(())
541 }
542
543 #[cfg(test)]
548 pub(crate) fn op_decorator_storage(&self) -> &OpToDecoratorIds {
549 &self.op_decorator_storage
550 }
551}
552
553impl Serializable for DebugInfo {
554 fn write_into<W: ByteWriter>(&self, target: &mut W) {
555 let mut decorator_data_builder = DecoratorDataBuilder::new();
557 for decorator in self.decorators.iter() {
558 decorator_data_builder.add_decorator(decorator);
559 }
560 let (decorator_data, decorator_infos, string_table) = decorator_data_builder.finalize();
561
562 decorator_data.write_into(target);
563 string_table.write_into(target);
564 decorator_infos.write_into(target);
565
566 let error_codes: BTreeMap<u64, String> =
568 self.error_codes.iter().map(|(k, v)| (*k, v.to_string())).collect();
569 error_codes.write_into(target);
570
571 self.op_decorator_storage.write_into(target);
576
577 self.node_decorator_storage.write_into(target);
579
580 let procedure_names: BTreeMap<Word, String> =
582 self.procedure_names().map(|(k, v)| (k, v.to_string())).collect();
583 procedure_names.write_into(target);
584
585 let mut asm_op_data_builder = AsmOpDataBuilder::new();
587 for asm_op in self.asm_ops.iter() {
588 asm_op_data_builder.add_asm_op(asm_op);
589 }
590 let (asm_op_data, asm_op_infos, asm_op_string_table) = asm_op_data_builder.finalize();
591
592 asm_op_data.write_into(target);
593 asm_op_string_table.write_into(target);
594 asm_op_infos.write_into(target);
595
596 self.asm_op_storage.write_into(target);
598
599 self.debug_vars.write_into(target);
601
602 self.op_debug_var_storage.write_into(target);
604 }
605}
606
607impl Deserializable for DebugInfo {
608 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
609 let decorator_data: Vec<u8> = Deserializable::read_from(source)?;
611 let string_table: StringTable = Deserializable::read_from(source)?;
612 let decorator_infos: Vec<DecoratorInfo> = Deserializable::read_from(source)?;
613
614 let mut decorators = IndexVec::new();
616 for decorator_info in decorator_infos {
617 let decorator = decorator_info.try_into_decorator(&string_table, &decorator_data)?;
618 decorators.push(decorator).map_err(|_| {
619 DeserializationError::InvalidValue(
620 "Failed to add decorator to IndexVec".to_string(),
621 )
622 })?;
623 }
624
625 let error_codes_raw: BTreeMap<u64, String> = Deserializable::read_from(source)?;
627 let error_codes: BTreeMap<u64, Arc<str>> =
628 error_codes_raw.into_iter().map(|(k, v)| (k, Arc::from(v.as_str()))).collect();
629
630 let op_decorator_storage = OpToDecoratorIds::read_from(source, decorators.len())?;
632
633 let node_decorator_storage = NodeToDecoratorIds::read_from(source, decorators.len())?;
635
636 let procedure_names_raw: BTreeMap<Word, String> = Deserializable::read_from(source)?;
640 let procedure_names: BTreeMap<LexicographicWord, Arc<str>> = procedure_names_raw
641 .into_iter()
642 .map(|(k, v)| (LexicographicWord::from(k), Arc::from(v.as_str())))
643 .collect();
644
645 let asm_op_data: Vec<u8> = Deserializable::read_from(source)?;
647 let asm_op_string_table: StringTable = Deserializable::read_from(source)?;
648 let asm_op_infos: Vec<AsmOpInfo> = Deserializable::read_from(source)?;
649
650 let mut asm_ops = IndexVec::new();
652 for asm_op_info in asm_op_infos {
653 let asm_op = asm_op_info.try_into_asm_op(&asm_op_string_table, &asm_op_data)?;
654 asm_ops.push(asm_op).map_err(|_| {
655 DeserializationError::InvalidValue(
656 "Failed to add AssemblyOp to IndexVec".to_string(),
657 )
658 })?;
659 }
660
661 let asm_op_storage = OpToAsmOpId::read_from(source, asm_ops.len())?;
663
664 let debug_vars: IndexVec<DebugVarId, DebugVarInfo> = Deserializable::read_from(source)?;
666
667 let op_debug_var_storage = OpToDebugVarIds::read_from(source, debug_vars.len())?;
669
670 let debug_info = DebugInfo {
672 decorators,
673 op_decorator_storage,
674 node_decorator_storage,
675 asm_ops,
676 asm_op_storage,
677 debug_vars,
678 op_debug_var_storage,
679 error_codes,
680 procedure_names,
681 };
682
683 debug_info.validate().map_err(|e| {
684 DeserializationError::InvalidValue(format!("DebugInfo validation failed: {}", e))
685 })?;
686
687 Ok(debug_info)
688 }
689}
690
691impl Default for DebugInfo {
692 fn default() -> Self {
693 Self::new()
694 }
695}