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_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<(), crate::mast::debuginfo::decorator_storage::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<(), crate::mast::debuginfo::decorator_storage::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(&LexicographicWord::from(*digest)).map(|s| s.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.into_inner(), 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(LexicographicWord::from(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
521 .extend(names.into_iter().map(|(d, n)| (LexicographicWord::from(d), n)));
522 }
523
524 pub fn clear_procedure_names(&mut self) {
526 self.procedure_names.clear();
527 }
528
529 pub(super) fn validate(&self) -> Result<(), String> {
543 let decorator_count = self.decorators.len();
544 let asm_op_count = self.asm_ops.len();
545
546 self.op_decorator_storage.validate_csr(decorator_count)?;
548
549 self.node_decorator_storage.validate_csr(decorator_count)?;
551
552 self.asm_op_storage.validate_csr(asm_op_count)?;
554
555 let debug_var_count = self.debug_vars.len();
557 self.op_debug_var_storage.validate_csr(debug_var_count)?;
558
559 Ok(())
560 }
561
562 #[cfg(test)]
567 pub(crate) fn op_decorator_storage(&self) -> &OpToDecoratorIds {
568 &self.op_decorator_storage
569 }
570}
571
572impl Serializable for DebugInfo {
573 fn write_into<W: ByteWriter>(&self, target: &mut W) {
574 let mut decorator_data_builder = DecoratorDataBuilder::new();
576 for decorator in self.decorators.iter() {
577 decorator_data_builder.add_decorator(decorator);
578 }
579 let (decorator_data, decorator_infos, string_table) = decorator_data_builder.finalize();
580
581 decorator_data.write_into(target);
582 string_table.write_into(target);
583 decorator_infos.write_into(target);
584
585 let error_codes: BTreeMap<u64, String> =
587 self.error_codes.iter().map(|(k, v)| (*k, v.to_string())).collect();
588 error_codes.write_into(target);
589
590 self.op_decorator_storage.write_into(target);
595
596 self.node_decorator_storage.write_into(target);
598
599 let procedure_names: BTreeMap<Word, String> =
601 self.procedure_names().map(|(k, v)| (k, v.to_string())).collect();
602 procedure_names.write_into(target);
603
604 let mut asm_op_data_builder = AsmOpDataBuilder::new();
606 for asm_op in self.asm_ops.iter() {
607 asm_op_data_builder.add_asm_op(asm_op);
608 }
609 let (asm_op_data, asm_op_infos, asm_op_string_table) = asm_op_data_builder.finalize();
610
611 asm_op_data.write_into(target);
612 asm_op_string_table.write_into(target);
613 asm_op_infos.write_into(target);
614
615 self.asm_op_storage.write_into(target);
617
618 self.debug_vars.write_into(target);
620
621 self.op_debug_var_storage.write_into(target);
623 }
624}
625
626impl Deserializable for DebugInfo {
627 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
628 let decorator_data: Vec<u8> = Deserializable::read_from(source)?;
630 let string_table: StringTable = Deserializable::read_from(source)?;
631 let decorator_infos: Vec<DecoratorInfo> = Deserializable::read_from(source)?;
632
633 let mut decorators = IndexVec::new();
635 for decorator_info in decorator_infos {
636 let decorator = decorator_info.try_into_decorator(&string_table, &decorator_data)?;
637 decorators.push(decorator).map_err(|_| {
638 DeserializationError::InvalidValue(
639 "Failed to add decorator to IndexVec".to_string(),
640 )
641 })?;
642 }
643
644 let error_codes_raw: BTreeMap<u64, String> = Deserializable::read_from(source)?;
646 let error_codes: BTreeMap<u64, Arc<str>> =
647 error_codes_raw.into_iter().map(|(k, v)| (k, Arc::from(v.as_str()))).collect();
648
649 let op_decorator_storage = OpToDecoratorIds::read_from(source, decorators.len())?;
651
652 let node_decorator_storage = NodeToDecoratorIds::read_from(source, decorators.len())?;
654
655 let procedure_names_raw: BTreeMap<Word, String> = Deserializable::read_from(source)?;
659 let procedure_names: BTreeMap<LexicographicWord, Arc<str>> = procedure_names_raw
660 .into_iter()
661 .map(|(k, v)| (LexicographicWord::from(k), Arc::from(v.as_str())))
662 .collect();
663
664 let asm_op_data: Vec<u8> = Deserializable::read_from(source)?;
666 let asm_op_string_table: StringTable = Deserializable::read_from(source)?;
667 let asm_op_infos: Vec<AsmOpInfo> = Deserializable::read_from(source)?;
668
669 let mut asm_ops = IndexVec::new();
671 for asm_op_info in asm_op_infos {
672 let asm_op = asm_op_info.try_into_asm_op(&asm_op_string_table, &asm_op_data)?;
673 asm_ops.push(asm_op).map_err(|_| {
674 DeserializationError::InvalidValue(
675 "Failed to add AssemblyOp to IndexVec".to_string(),
676 )
677 })?;
678 }
679
680 let asm_op_storage = OpToAsmOpId::read_from(source, asm_ops.len())?;
682
683 let debug_vars: IndexVec<DebugVarId, DebugVarInfo> = Deserializable::read_from(source)?;
685
686 let op_debug_var_storage = OpToDebugVarIds::read_from(source, debug_vars.len())?;
688
689 let debug_info = DebugInfo {
691 decorators,
692 op_decorator_storage,
693 node_decorator_storage,
694 asm_ops,
695 asm_op_storage,
696 debug_vars,
697 op_debug_var_storage,
698 error_codes,
699 procedure_names,
700 };
701
702 debug_info.validate().map_err(|e| {
703 DeserializationError::InvalidValue(format!("DebugInfo validation failed: {}", e))
704 })?;
705
706 Ok(debug_info)
707 }
708}
709
710impl Default for DebugInfo {
711 fn default() -> Self {
712 Self::new()
713 }
714}