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 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<Word, 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_node(&self, node_id: MastNodeId) -> Vec<(usize, DebugVarId)> {
278 self.op_debug_var_storage.debug_vars_for_node(node_id)
279 }
280
281 pub fn debug_vars_for_operation(
283 &self,
284 node_id: MastNodeId,
285 local_op_idx: usize,
286 ) -> &[DebugVarId] {
287 self.op_debug_var_storage
288 .debug_var_ids_for_operation(node_id, local_op_idx)
289 .unwrap_or(&[])
290 }
291
292 pub fn add_decorator(&mut self, decorator: Decorator) -> Result<DecoratorId, MastForestError> {
297 self.decorators.push(decorator).map_err(|_| MastForestError::TooManyDecorators)
298 }
299
300 pub(super) fn decorator_mut(&mut self, decorator_id: DecoratorId) -> Option<&mut Decorator> {
302 if decorator_id.to_usize() < self.decorators.len() {
303 Some(&mut self.decorators[decorator_id])
304 } else {
305 None
306 }
307 }
308
309 pub(super) fn register_node_decorators(
315 &mut self,
316 node_id: MastNodeId,
317 before_enter: &[DecoratorId],
318 after_exit: &[DecoratorId],
319 ) {
320 self.node_decorator_storage
321 .add_node_decorators(node_id, before_enter, after_exit);
322 }
323
324 pub(crate) fn register_op_indexed_decorators(
328 &mut self,
329 node_id: MastNodeId,
330 decorators_info: Vec<(usize, DecoratorId)>,
331 ) -> Result<(), DecoratorIndexError> {
332 self.op_decorator_storage.add_decorator_info_for_node(node_id, decorators_info)
333 }
334
335 pub fn clear_mappings(&mut self) {
339 self.op_decorator_storage = OpToDecoratorIds::new();
340 self.node_decorator_storage.clear();
341 }
342
343 pub fn num_asm_ops(&self) -> usize {
348 self.asm_ops.len()
349 }
350
351 pub fn asm_ops(&self) -> &[AssemblyOp] {
353 self.asm_ops.as_slice()
354 }
355
356 pub fn asm_op(&self, asm_op_id: AsmOpId) -> Option<&AssemblyOp> {
358 self.asm_ops.get(asm_op_id)
359 }
360
361 pub fn asm_op_for_operation(&self, node_id: MastNodeId, op_idx: usize) -> Option<&AssemblyOp> {
363 let asm_op_id = self.asm_op_storage.asm_op_id_for_operation(node_id, op_idx)?;
364 self.asm_ops.get(asm_op_id)
365 }
366
367 pub fn first_asm_op_for_node(&self, node_id: MastNodeId) -> Option<&AssemblyOp> {
369 let asm_op_id = self.asm_op_storage.first_asm_op_for_node(node_id)?;
370 self.asm_ops.get(asm_op_id)
371 }
372
373 pub fn asm_ops_for_node(&self, node_id: MastNodeId) -> Vec<(usize, AsmOpId)> {
375 self.asm_op_storage.asm_ops_for_node(node_id)
376 }
377
378 pub fn add_asm_op(&mut self, asm_op: AssemblyOp) -> Result<AsmOpId, MastForestError> {
383 self.asm_ops.push(asm_op).map_err(|_| MastForestError::TooManyDecorators)
384 }
385
386 pub fn rewrite_source_locations(
388 &mut self,
389 mut rewrite_location: impl FnMut(Location) -> Location,
390 mut rewrite_file_line_col: impl FnMut(FileLineCol) -> FileLineCol,
391 ) {
392 for asm_op in self.asm_ops.iter_mut() {
393 if let Some(location) = asm_op.location().cloned() {
394 asm_op.set_location(rewrite_location(location));
395 }
396 }
397
398 for debug_var in self.debug_vars.iter_mut() {
399 if let Some(location) = debug_var.location().cloned() {
400 debug_var.set_location(rewrite_file_line_col(location));
401 }
402 }
403 }
404
405 pub fn register_asm_ops(
411 &mut self,
412 node_id: MastNodeId,
413 num_operations: usize,
414 asm_ops: Vec<(usize, AsmOpId)>,
415 ) -> Result<(), AsmOpIndexError> {
416 self.asm_op_storage.add_asm_ops_for_node(node_id, num_operations, asm_ops)
417 }
418
419 pub(super) fn remap_asm_op_storage(&mut self, remapping: &BTreeMap<MastNodeId, MastNodeId>) {
424 self.asm_op_storage = self.asm_op_storage.remap_nodes(remapping);
425 }
426
427 pub(super) fn remap_debug_var_storage(&mut self, remapping: &BTreeMap<MastNodeId, MastNodeId>) {
432 self.op_debug_var_storage = self.op_debug_var_storage.remap_nodes(remapping);
433 }
434
435 pub fn add_debug_var(
440 &mut self,
441 debug_var: DebugVarInfo,
442 ) -> Result<DebugVarId, MastForestError> {
443 self.debug_vars.push(debug_var).map_err(|_| MastForestError::TooManyDecorators)
444 }
445
446 pub fn register_op_indexed_debug_vars(
450 &mut self,
451 node_id: MastNodeId,
452 debug_vars_info: Vec<(usize, DebugVarId)>,
453 ) -> Result<(), DecoratorIndexError> {
454 self.op_debug_var_storage.add_debug_var_info_for_node(node_id, debug_vars_info)
455 }
456
457 pub fn error_message(&self, code: u64) -> Option<Arc<str>> {
462 self.error_codes.get(&code).cloned()
463 }
464
465 pub fn error_codes(&self) -> impl Iterator<Item = (&u64, &Arc<str>)> {
467 self.error_codes.iter()
468 }
469
470 pub fn insert_error_code(&mut self, code: u64, msg: Arc<str>) {
472 self.error_codes.insert(code, msg);
473 }
474
475 pub fn extend_error_codes<I>(&mut self, error_codes: I)
479 where
480 I: IntoIterator<Item = (u64, Arc<str>)>,
481 {
482 self.error_codes.extend(error_codes);
483 }
484
485 pub fn clear_error_codes(&mut self) {
489 self.error_codes.clear();
490 }
491
492 pub fn procedure_name(&self, digest: &Word) -> Option<&str> {
497 self.procedure_names.get(digest).map(AsRef::as_ref)
498 }
499
500 pub fn procedure_names(&self) -> impl Iterator<Item = (Word, &Arc<str>)> {
502 self.procedure_names.iter().map(|(key, name)| (*key, name))
503 }
504
505 pub fn num_procedure_names(&self) -> usize {
507 self.procedure_names.len()
508 }
509
510 pub fn insert_procedure_name(&mut self, digest: Word, name: Arc<str>) {
512 self.procedure_names.insert(digest, name);
513 }
514
515 pub fn extend_procedure_names<I>(&mut self, names: I)
517 where
518 I: IntoIterator<Item = (Word, Arc<str>)>,
519 {
520 self.procedure_names.extend(names);
521 }
522
523 pub fn clear_procedure_names(&mut self) {
525 self.procedure_names.clear();
526 }
527
528 pub(super) fn validate(&self) -> Result<(), String> {
542 let decorator_count = self.decorators.len();
543 let asm_op_count = self.asm_ops.len();
544
545 self.op_decorator_storage.validate_csr(decorator_count)?;
547
548 self.node_decorator_storage.validate_csr(decorator_count)?;
550
551 self.asm_op_storage.validate_csr(asm_op_count)?;
553
554 let debug_var_count = self.debug_vars.len();
556 self.op_debug_var_storage.validate_csr(debug_var_count)?;
557
558 Ok(())
559 }
560
561 #[cfg(test)]
566 pub(crate) fn op_decorator_storage(&self) -> &OpToDecoratorIds {
567 &self.op_decorator_storage
568 }
569
570 #[cfg(test)]
572 pub(crate) fn node_decorator_storage(&self) -> &NodeToDecoratorIds {
573 &self.node_decorator_storage
574 }
575}
576
577impl Serializable for DebugInfo {
578 fn write_into<W: ByteWriter>(&self, target: &mut W) {
579 let mut decorator_data_builder = DecoratorDataBuilder::new();
581 for decorator in self.decorators.iter() {
582 decorator_data_builder.add_decorator(decorator);
583 }
584 let (decorator_data, decorator_infos, string_table) = decorator_data_builder.finalize();
585
586 decorator_data.write_into(target);
587 string_table.write_into(target);
588 decorator_infos.write_into(target);
589
590 let error_codes: BTreeMap<u64, String> =
592 self.error_codes.iter().map(|(k, v)| (*k, v.to_string())).collect();
593 error_codes.write_into(target);
594
595 self.op_decorator_storage.write_into(target);
600
601 self.node_decorator_storage.write_into(target);
603
604 let procedure_names: BTreeMap<Word, String> =
606 self.procedure_names().map(|(k, v)| (k, v.to_string())).collect();
607 procedure_names.write_into(target);
608
609 let mut asm_op_data_builder = AsmOpDataBuilder::new();
611 for asm_op in self.asm_ops.iter() {
612 asm_op_data_builder.add_asm_op(asm_op);
613 }
614 let (asm_op_data, asm_op_infos, asm_op_string_table) = asm_op_data_builder.finalize();
615
616 asm_op_data.write_into(target);
617 asm_op_string_table.write_into(target);
618 asm_op_infos.write_into(target);
619
620 self.asm_op_storage.write_into(target);
622
623 self.debug_vars.write_into(target);
625
626 self.op_debug_var_storage.write_into(target);
628 }
629}
630
631impl Deserializable for DebugInfo {
632 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
633 let decorator_data: Vec<u8> = Deserializable::read_from(source)?;
635 let string_table: StringTable = Deserializable::read_from(source)?;
636 let decorator_infos: Vec<DecoratorInfo> = Deserializable::read_from(source)?;
637
638 let mut decorators = IndexVec::new();
640 for decorator_info in decorator_infos {
641 let decorator = decorator_info.try_into_decorator(&string_table, &decorator_data)?;
642 decorators.push(decorator).map_err(|_| {
643 DeserializationError::InvalidValue(
644 "Failed to add decorator to IndexVec".to_string(),
645 )
646 })?;
647 }
648
649 let error_codes_raw: BTreeMap<u64, String> = Deserializable::read_from(source)?;
651 let error_codes: BTreeMap<u64, Arc<str>> =
652 error_codes_raw.into_iter().map(|(k, v)| (k, Arc::from(v.as_str()))).collect();
653
654 let op_decorator_storage = OpToDecoratorIds::read_from(source, decorators.len())?;
656
657 let node_decorator_storage = NodeToDecoratorIds::read_from(source, decorators.len())?;
659
660 let procedure_names_raw: BTreeMap<Word, String> = Deserializable::read_from(source)?;
664 let procedure_names: BTreeMap<Word, Arc<str>> = procedure_names_raw
665 .into_iter()
666 .map(|(k, v)| (k, Arc::from(v.as_str())))
667 .collect();
668
669 let asm_op_data: Vec<u8> = Deserializable::read_from(source)?;
671 let asm_op_string_table: StringTable = Deserializable::read_from(source)?;
672 let asm_op_infos: Vec<AsmOpInfo> = Deserializable::read_from(source)?;
673
674 let mut asm_ops = IndexVec::new();
676 for asm_op_info in asm_op_infos {
677 let asm_op = asm_op_info.try_into_asm_op(&asm_op_string_table, &asm_op_data)?;
678 asm_ops.push(asm_op).map_err(|_| {
679 DeserializationError::InvalidValue(
680 "Failed to add AssemblyOp to IndexVec".to_string(),
681 )
682 })?;
683 }
684
685 let asm_op_storage = OpToAsmOpId::read_from(source, asm_ops.len())?;
687
688 let debug_vars: IndexVec<DebugVarId, DebugVarInfo> = Deserializable::read_from(source)?;
690
691 let op_debug_var_storage = OpToDebugVarIds::read_from(source, debug_vars.len())?;
693
694 let debug_info = DebugInfo {
696 decorators,
697 op_decorator_storage,
698 node_decorator_storage,
699 asm_ops,
700 asm_op_storage,
701 debug_vars,
702 op_debug_var_storage,
703 error_codes,
704 procedure_names,
705 };
706
707 debug_info.validate().map_err(|e| {
708 DeserializationError::InvalidValue(format!("DebugInfo validation failed: {e}"))
709 })?;
710
711 Ok(debug_info)
712 }
713}
714
715impl Default for DebugInfo {
716 fn default() -> Self {
717 Self::new()
718 }
719}