1use alloc::{
43 collections::BTreeMap,
44 string::{String, ToString},
45 sync::Arc,
46 vec::Vec,
47};
48
49#[cfg(feature = "serde")]
50use serde::{Deserialize, Serialize};
51
52use super::{AsmOpId, Decorator, DecoratorId, MastForestError, MastNodeId};
53use crate::{
54 LexicographicWord, Word,
55 mast::serialization::{
56 StringTable,
57 asm_op::{AsmOpDataBuilder, AsmOpInfo},
58 decorator::{DecoratorDataBuilder, DecoratorInfo},
59 },
60 operations::AssemblyOp,
61 serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
62 utils::{Idx, IndexVec},
63};
64
65mod asm_op_storage;
66pub use asm_op_storage::{AsmOpIndexError, OpToAsmOpId};
67
68mod decorator_storage;
69pub use decorator_storage::{
70 DecoratedLinks, DecoratedLinksIter, DecoratorIndexError, OpToDecoratorIds,
71};
72
73mod node_decorator_storage;
74pub use node_decorator_storage::NodeToDecoratorIds;
75
76#[derive(Debug, Clone, PartialEq, Eq)]
81#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
82pub struct DebugInfo {
83 decorators: IndexVec<DecoratorId, Decorator>,
85
86 op_decorator_storage: OpToDecoratorIds,
88
89 node_decorator_storage: NodeToDecoratorIds,
91
92 asm_ops: IndexVec<AsmOpId, AssemblyOp>,
94
95 asm_op_storage: OpToAsmOpId,
97
98 error_codes: BTreeMap<u64, Arc<str>>,
100
101 #[cfg_attr(feature = "serde", serde(skip))]
103 procedure_names: BTreeMap<LexicographicWord, Arc<str>>,
104}
105
106impl DebugInfo {
107 pub fn new() -> Self {
112 Self {
113 decorators: IndexVec::new(),
114 op_decorator_storage: OpToDecoratorIds::new(),
115 node_decorator_storage: NodeToDecoratorIds::new(),
116 asm_ops: IndexVec::new(),
117 asm_op_storage: OpToAsmOpId::new(),
118 error_codes: BTreeMap::new(),
119 procedure_names: BTreeMap::new(),
120 }
121 }
122
123 pub fn with_capacity(
125 decorators_capacity: usize,
126 nodes_capacity: usize,
127 operations_capacity: usize,
128 decorator_ids_capacity: usize,
129 ) -> Self {
130 Self {
131 decorators: IndexVec::with_capacity(decorators_capacity),
132 op_decorator_storage: OpToDecoratorIds::with_capacity(
133 nodes_capacity,
134 operations_capacity,
135 decorator_ids_capacity,
136 ),
137 node_decorator_storage: NodeToDecoratorIds::with_capacity(nodes_capacity, 0, 0),
138 asm_ops: IndexVec::new(),
139 asm_op_storage: OpToAsmOpId::new(),
140 error_codes: BTreeMap::new(),
141 procedure_names: BTreeMap::new(),
142 }
143 }
144
145 pub fn empty_for_nodes(num_nodes: usize) -> Self {
147 let node_indptr_for_op_idx = IndexVec::try_from(vec![0; num_nodes + 1])
148 .expect("num_nodes should not exceed u32::MAX");
149
150 let op_decorator_storage =
151 OpToDecoratorIds::from_components(Vec::new(), Vec::new(), node_indptr_for_op_idx)
152 .expect("Empty CSR structure should be valid");
153
154 Self {
155 decorators: IndexVec::new(),
156 op_decorator_storage,
157 node_decorator_storage: NodeToDecoratorIds::new(),
158 asm_ops: IndexVec::new(),
159 asm_op_storage: OpToAsmOpId::new(),
160 error_codes: BTreeMap::new(),
161 procedure_names: BTreeMap::new(),
162 }
163 }
164
165 pub fn is_empty(&self) -> bool {
171 self.decorators.is_empty()
172 && self.asm_ops.is_empty()
173 && self.error_codes.is_empty()
174 && self.procedure_names.is_empty()
175 }
176
177 pub fn clear(&mut self) {
182 self.clear_mappings();
183 self.decorators = IndexVec::new();
184 self.asm_ops = IndexVec::new();
185 self.asm_op_storage = OpToAsmOpId::new();
186 self.error_codes.clear();
187 self.procedure_names.clear();
188 }
189
190 pub fn num_decorators(&self) -> usize {
195 self.decorators.len()
196 }
197
198 pub fn decorators(&self) -> &[Decorator] {
200 self.decorators.as_slice()
201 }
202
203 pub fn decorator(&self, decorator_id: DecoratorId) -> Option<&Decorator> {
205 self.decorators.get(decorator_id)
206 }
207
208 pub fn before_enter_decorators(&self, node_id: MastNodeId) -> &[DecoratorId] {
210 self.node_decorator_storage.get_before_decorators(node_id)
211 }
212
213 pub fn after_exit_decorators(&self, node_id: MastNodeId) -> &[DecoratorId] {
215 self.node_decorator_storage.get_after_decorators(node_id)
216 }
217
218 pub fn decorators_for_operation(
220 &self,
221 node_id: MastNodeId,
222 local_op_idx: usize,
223 ) -> &[DecoratorId] {
224 self.op_decorator_storage
225 .decorator_ids_for_operation(node_id, local_op_idx)
226 .unwrap_or(&[])
227 }
228
229 pub(super) fn decorator_links_for_node(
231 &self,
232 node_id: MastNodeId,
233 ) -> Result<DecoratedLinks<'_>, DecoratorIndexError> {
234 self.op_decorator_storage.decorator_links_for_node(node_id)
235 }
236
237 pub fn add_decorator(&mut self, decorator: Decorator) -> Result<DecoratorId, MastForestError> {
242 self.decorators.push(decorator).map_err(|_| MastForestError::TooManyDecorators)
243 }
244
245 pub(super) fn decorator_mut(&mut self, decorator_id: DecoratorId) -> Option<&mut Decorator> {
247 if decorator_id.to_usize() < self.decorators.len() {
248 Some(&mut self.decorators[decorator_id])
249 } else {
250 None
251 }
252 }
253
254 pub(super) fn register_node_decorators(
260 &mut self,
261 node_id: MastNodeId,
262 before_enter: &[DecoratorId],
263 after_exit: &[DecoratorId],
264 ) {
265 self.node_decorator_storage
266 .add_node_decorators(node_id, before_enter, after_exit);
267 }
268
269 pub(crate) fn register_op_indexed_decorators(
273 &mut self,
274 node_id: MastNodeId,
275 decorators_info: Vec<(usize, DecoratorId)>,
276 ) -> Result<(), crate::mast::debuginfo::decorator_storage::DecoratorIndexError> {
277 self.op_decorator_storage.add_decorator_info_for_node(node_id, decorators_info)
278 }
279
280 pub fn clear_mappings(&mut self) {
284 self.op_decorator_storage = OpToDecoratorIds::new();
285 self.node_decorator_storage.clear();
286 }
287
288 pub fn num_asm_ops(&self) -> usize {
293 self.asm_ops.len()
294 }
295
296 pub fn asm_ops(&self) -> &[AssemblyOp] {
298 self.asm_ops.as_slice()
299 }
300
301 pub fn asm_op(&self, asm_op_id: AsmOpId) -> Option<&AssemblyOp> {
303 self.asm_ops.get(asm_op_id)
304 }
305
306 pub fn asm_op_for_operation(&self, node_id: MastNodeId, op_idx: usize) -> Option<&AssemblyOp> {
308 let asm_op_id = self.asm_op_storage.asm_op_id_for_operation(node_id, op_idx)?;
309 self.asm_ops.get(asm_op_id)
310 }
311
312 pub fn first_asm_op_for_node(&self, node_id: MastNodeId) -> Option<&AssemblyOp> {
314 let asm_op_id = self.asm_op_storage.first_asm_op_for_node(node_id)?;
315 self.asm_ops.get(asm_op_id)
316 }
317
318 pub fn add_asm_op(&mut self, asm_op: AssemblyOp) -> Result<AsmOpId, MastForestError> {
323 self.asm_ops.push(asm_op).map_err(|_| MastForestError::TooManyDecorators)
324 }
325
326 pub fn register_asm_ops(
332 &mut self,
333 node_id: MastNodeId,
334 num_operations: usize,
335 asm_ops: Vec<(usize, AsmOpId)>,
336 ) -> Result<(), AsmOpIndexError> {
337 self.asm_op_storage.add_asm_ops_for_node(node_id, num_operations, asm_ops)
338 }
339
340 pub(super) fn remap_asm_op_storage(&mut self, remapping: &BTreeMap<MastNodeId, MastNodeId>) {
345 self.asm_op_storage = self.asm_op_storage.remap_nodes(remapping);
346 }
347
348 pub fn error_message(&self, code: u64) -> Option<Arc<str>> {
353 self.error_codes.get(&code).cloned()
354 }
355
356 pub fn error_codes(&self) -> impl Iterator<Item = (&u64, &Arc<str>)> {
358 self.error_codes.iter()
359 }
360
361 pub fn insert_error_code(&mut self, code: u64, msg: Arc<str>) {
363 self.error_codes.insert(code, msg);
364 }
365
366 pub fn extend_error_codes<I>(&mut self, error_codes: I)
370 where
371 I: IntoIterator<Item = (u64, Arc<str>)>,
372 {
373 self.error_codes.extend(error_codes);
374 }
375
376 pub fn clear_error_codes(&mut self) {
380 self.error_codes.clear();
381 }
382
383 pub fn procedure_name(&self, digest: &Word) -> Option<&str> {
388 self.procedure_names.get(&LexicographicWord::from(*digest)).map(|s| s.as_ref())
389 }
390
391 pub fn procedure_names(&self) -> impl Iterator<Item = (Word, &Arc<str>)> {
393 self.procedure_names.iter().map(|(key, name)| (key.into_inner(), name))
394 }
395
396 pub fn num_procedure_names(&self) -> usize {
398 self.procedure_names.len()
399 }
400
401 pub fn insert_procedure_name(&mut self, digest: Word, name: Arc<str>) {
403 self.procedure_names.insert(LexicographicWord::from(digest), name);
404 }
405
406 pub fn extend_procedure_names<I>(&mut self, names: I)
408 where
409 I: IntoIterator<Item = (Word, Arc<str>)>,
410 {
411 self.procedure_names
412 .extend(names.into_iter().map(|(d, n)| (LexicographicWord::from(d), n)));
413 }
414
415 pub fn clear_procedure_names(&mut self) {
417 self.procedure_names.clear();
418 }
419
420 pub(super) fn validate(&self) -> Result<(), String> {
432 let decorator_count = self.decorators.len();
433 let asm_op_count = self.asm_ops.len();
434
435 self.op_decorator_storage.validate_csr(decorator_count)?;
437
438 self.node_decorator_storage.validate_csr(decorator_count)?;
440
441 self.asm_op_storage.validate_csr(asm_op_count)?;
443
444 Ok(())
445 }
446
447 #[cfg(test)]
452 pub(crate) fn op_decorator_storage(&self) -> &OpToDecoratorIds {
453 &self.op_decorator_storage
454 }
455}
456
457impl Serializable for DebugInfo {
458 fn write_into<W: ByteWriter>(&self, target: &mut W) {
459 let mut decorator_data_builder = DecoratorDataBuilder::new();
461 for decorator in self.decorators.iter() {
462 decorator_data_builder.add_decorator(decorator);
463 }
464 let (decorator_data, decorator_infos, string_table) = decorator_data_builder.finalize();
465
466 decorator_data.write_into(target);
467 string_table.write_into(target);
468 decorator_infos.write_into(target);
469
470 let error_codes: BTreeMap<u64, String> =
472 self.error_codes.iter().map(|(k, v)| (*k, v.to_string())).collect();
473 error_codes.write_into(target);
474
475 self.op_decorator_storage.write_into(target);
480
481 self.node_decorator_storage.write_into(target);
483
484 let procedure_names: BTreeMap<Word, String> =
486 self.procedure_names().map(|(k, v)| (k, v.to_string())).collect();
487 procedure_names.write_into(target);
488
489 let mut asm_op_data_builder = AsmOpDataBuilder::new();
491 for asm_op in self.asm_ops.iter() {
492 asm_op_data_builder.add_asm_op(asm_op);
493 }
494 let (asm_op_data, asm_op_infos, asm_op_string_table) = asm_op_data_builder.finalize();
495
496 asm_op_data.write_into(target);
497 asm_op_string_table.write_into(target);
498 asm_op_infos.write_into(target);
499
500 self.asm_op_storage.write_into(target);
502 }
503}
504
505impl Deserializable for DebugInfo {
506 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
507 let decorator_data: Vec<u8> = Deserializable::read_from(source)?;
509 let string_table: StringTable = Deserializable::read_from(source)?;
510 let decorator_infos: Vec<DecoratorInfo> = Deserializable::read_from(source)?;
511
512 let mut decorators = IndexVec::new();
514 for decorator_info in decorator_infos {
515 let decorator = decorator_info.try_into_decorator(&string_table, &decorator_data)?;
516 decorators.push(decorator).map_err(|_| {
517 DeserializationError::InvalidValue(
518 "Failed to add decorator to IndexVec".to_string(),
519 )
520 })?;
521 }
522
523 let error_codes_raw: BTreeMap<u64, String> = Deserializable::read_from(source)?;
525 let error_codes: BTreeMap<u64, Arc<str>> =
526 error_codes_raw.into_iter().map(|(k, v)| (k, Arc::from(v.as_str()))).collect();
527
528 let op_decorator_storage = OpToDecoratorIds::read_from(source, decorators.len())?;
530
531 let node_decorator_storage = NodeToDecoratorIds::read_from(source, decorators.len())?;
533
534 let procedure_names_raw: BTreeMap<Word, String> = Deserializable::read_from(source)?;
538 let procedure_names: BTreeMap<LexicographicWord, Arc<str>> = procedure_names_raw
539 .into_iter()
540 .map(|(k, v)| (LexicographicWord::from(k), Arc::from(v.as_str())))
541 .collect();
542
543 let asm_op_data: Vec<u8> = Deserializable::read_from(source)?;
545 let asm_op_string_table: StringTable = Deserializable::read_from(source)?;
546 let asm_op_infos: Vec<AsmOpInfo> = Deserializable::read_from(source)?;
547
548 let mut asm_ops = IndexVec::new();
550 for asm_op_info in asm_op_infos {
551 let asm_op = asm_op_info.try_into_asm_op(&asm_op_string_table, &asm_op_data)?;
552 asm_ops.push(asm_op).map_err(|_| {
553 DeserializationError::InvalidValue(
554 "Failed to add AssemblyOp to IndexVec".to_string(),
555 )
556 })?;
557 }
558
559 let asm_op_storage = OpToAsmOpId::read_from(source, asm_ops.len())?;
561
562 let debug_info = DebugInfo {
564 decorators,
565 op_decorator_storage,
566 node_decorator_storage,
567 asm_ops,
568 asm_op_storage,
569 error_codes,
570 procedure_names,
571 };
572
573 debug_info.validate().map_err(|e| {
574 DeserializationError::InvalidValue(format!("DebugInfo validation failed: {}", e))
575 })?;
576
577 Ok(debug_info)
578 }
579}
580
581impl Default for DebugInfo {
582 fn default() -> Self {
583 Self::new()
584 }
585}