Skip to content

Commit 22c71ef

Browse files
committed
feat: preserve loaded package debug info
1 parent 3e5b595 commit 22c71ef

22 files changed

Lines changed: 932 additions & 146 deletions

File tree

crates/lib/core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ impl From<&CoreLibrary> for HostLibrary {
111111
fn from(core_lib: &CoreLibrary) -> Self {
112112
Self {
113113
mast_forest: core_lib.mast_forest().clone(),
114+
package_debug_info: Ok(None),
114115
handlers: core_lib.handlers(),
115116
}
116117
}

crates/lib/core/tests/debug.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ fn run(source: &str, advice: AdviceInputs) -> (String, ExecutionOutput) {
6969
let buf = Arc::new(Mutex::new(String::new()));
7070
let host_lib = HostLibrary {
7171
mast_forest: core_lib.mast_forest().clone(),
72+
package_debug_info: Ok(None),
7273
handlers: debug_handlers_with_writer(SharedBuf(buf.clone())),
7374
};
7475
let mut host = DefaultHost::default().with_library(host_lib).expect("failed to load host lib");
@@ -293,6 +294,7 @@ fn print_mem_rejects_out_of_bounds_range_end() {
293294
.unwrap_program();
294295
let host_lib = HostLibrary {
295296
mast_forest: core_lib.mast_forest().clone(),
297+
package_debug_info: Ok(None),
296298
handlers: debug_handlers_with_writer(SharedBuf(Arc::new(Mutex::new(String::new())))),
297299
};
298300
let mut host = DefaultHost::default().with_library(host_lib).expect("failed to load host lib");
@@ -335,6 +337,7 @@ fn print_mem_rejects_oversized_range() {
335337
.unwrap_program();
336338
let host_lib = HostLibrary {
337339
mast_forest: core_lib.mast_forest().clone(),
340+
package_debug_info: Ok(None),
338341
handlers: debug_handlers_with_writer(SharedBuf(Arc::new(Mutex::new(String::new())))),
339342
};
340343
let mut host = DefaultHost::default().with_library(host_lib).expect("failed to load host lib");
@@ -377,6 +380,7 @@ fn print_mem_rejects_full_range() {
377380
.unwrap_program();
378381
let host_lib = HostLibrary {
379382
mast_forest: core_lib.mast_forest().clone(),
383+
package_debug_info: Ok(None),
380384
handlers: debug_handlers_with_writer(SharedBuf(Arc::new(Mutex::new(String::new())))),
381385
};
382386
let mut host = DefaultHost::default().with_library(host_lib).expect("failed to load host lib");
@@ -580,6 +584,7 @@ fn debug_handlers_compose_with_default_core_handlers() {
580584
handlers.extend(advice_debug_handlers());
581585
let host_lib = HostLibrary {
582586
mast_forest: core_lib.mast_forest().clone(),
587+
package_debug_info: Ok(None),
583588
handlers,
584589
};
585590
let mut host = DefaultHost::default().with_library(host_lib).expect("failed to load host lib");
@@ -649,6 +654,7 @@ fn noop_debug_handlers_run_print_stack_without_output() {
649654
.unwrap_program();
650655
let host_lib = HostLibrary {
651656
mast_forest: core_lib.mast_forest().clone(),
657+
package_debug_info: Ok(None),
652658
handlers: noop_debug_handlers(),
653659
};
654660
let mut host = DefaultHost::default().with_library(host_lib).expect("failed to load host lib");

processor/src/continuation_stack.rs

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use alloc::vec::Vec;
1+
use alloc::{sync::Arc, vec::Vec};
22

33
use miden_core::{mast::MastNodeId, program::Program};
4-
use miden_mast_package::debug_info::DebugSourceNodeId;
4+
use miden_mast_package::debug_info::{DebugSourceNodeId, PackageDebugInfo};
55

66
/// A hint for the initial size of the continuation stack.
77
const CONTINUATION_STACK_SIZE_HINT: usize = 64;
@@ -55,7 +55,10 @@ pub enum Continuation<F> {
5555
///
5656
/// When we encounter an `ExternalNode`, we enter the corresponding MAST forest directly, and
5757
/// push an `EnterForest` continuation to restore the previous forest when done.
58-
EnterForest(F),
58+
EnterForest {
59+
forest: F,
60+
package_debug_info: Option<Arc<PackageDebugInfo>>,
61+
},
5962
}
6063

6164
impl<F> Continuation<F> {
@@ -82,7 +85,23 @@ impl<F> Continuation<F> {
8285
| Respan { node_id: _, batch_index: _ }
8386
| FinishBasicBlock(_) => true,
8487

85-
EnterForest(_) => false,
88+
EnterForest { .. } => false,
89+
}
90+
}
91+
92+
#[cfg(any(test, feature = "testing"))]
93+
pub(crate) fn exec_node(&self) -> Option<MastNodeId> {
94+
match self {
95+
Self::StartNode(node_id)
96+
| Self::FinishJoin(node_id)
97+
| Self::FinishSplit(node_id)
98+
| Self::FinishLoop(node_id)
99+
| Self::FinishCall(node_id)
100+
| Self::FinishDyn(node_id)
101+
| Self::ResumeBasicBlock { node_id, .. }
102+
| Self::Respan { node_id, .. }
103+
| Self::FinishBasicBlock(node_id) => Some(*node_id),
104+
Self::EnterForest { .. } => None,
86105
}
87106
}
88107
}
@@ -123,12 +142,19 @@ impl<F> ContinuationStack<F> {
123142
pub(crate) fn new_with_source_node_id(
124143
program: &Program,
125144
source_node_id: DebugSourceNodeId,
145+
) -> Self {
146+
Self::new_with_optional_source_node_id(program, Some(source_node_id))
147+
}
148+
149+
pub(crate) fn new_with_optional_source_node_id(
150+
program: &Program,
151+
source_node_id: Option<DebugSourceNodeId>,
126152
) -> Self {
127153
let mut stack = Vec::with_capacity(CONTINUATION_STACK_SIZE_HINT);
128154
stack.push(Continuation::StartNode(program.entrypoint()));
129155

130156
let mut source_node_ids = Vec::with_capacity(CONTINUATION_STACK_SIZE_HINT);
131-
source_node_ids.push(Some(source_node_id));
157+
source_node_ids.push(source_node_id);
132158

133159
Self {
134160
stack,
@@ -159,7 +185,15 @@ impl<F> ContinuationStack<F> {
159185
/// # Arguments
160186
/// * `forest` - The MAST forest to enter
161187
pub fn push_enter_forest(&mut self, forest: F) {
162-
self.stack.push(Continuation::EnterForest(forest));
188+
self.push_enter_forest_with_package_debug_info(forest, None);
189+
}
190+
191+
pub(crate) fn push_enter_forest_with_package_debug_info(
192+
&mut self,
193+
forest: F,
194+
package_debug_info: Option<Arc<PackageDebugInfo>>,
195+
) {
196+
self.stack.push(Continuation::EnterForest { forest, package_debug_info });
163197
self.push_source_node_id(None);
164198
}
165199

@@ -232,6 +266,19 @@ impl<F> ContinuationStack<F> {
232266
}
233267
}
234268

269+
#[cfg(any(test, feature = "testing"))]
270+
pub(crate) fn start_tracking_source_nodes(
271+
&mut self,
272+
next_source_node_id: Option<DebugSourceNodeId>,
273+
) {
274+
let mut source_node_ids = Vec::with_capacity(self.stack.len());
275+
source_node_ids.resize(self.stack.len(), None);
276+
if let Some(source_node_id) = source_node_ids.last_mut() {
277+
*source_node_id = next_source_node_id;
278+
}
279+
self.source_node_ids = Some(source_node_ids);
280+
}
281+
235282
// PUBLIC ACCESSORS
236283
// --------------------------------------------------------------------------------------------
237284

@@ -260,6 +307,10 @@ impl<F> ContinuationStack<F> {
260307
Some((continuation, source_node_id))
261308
}
262309

310+
pub(crate) fn tracks_source_nodes(&self) -> bool {
311+
self.source_node_ids.is_some()
312+
}
313+
263314
/// Returns an iterator over the continuations on the stack that will execute in the next clock
264315
/// cycle.
265316
///
@@ -324,12 +375,15 @@ mod tests {
324375
// Push an incrementing continuation first (bottom of stack)
325376
stack.push_continuation(Continuation::StartNode(MastNodeId::new_unchecked(0)));
326377
// Push a non-incrementing continuation on top
327-
stack.push_continuation(Continuation::EnterForest(Arc::new(MastForest::new())));
378+
stack.push_continuation(Continuation::EnterForest {
379+
forest: Arc::new(MastForest::new()),
380+
package_debug_info: None,
381+
});
328382

329383
let result: Vec<_> = stack.iter_continuations_for_next_clock().collect();
330384
// Should return: EnterForest (non-incrementing), then StartNode (first incrementing)
331385
assert_eq!(result.len(), 2);
332-
assert!(matches!(result[0], Continuation::EnterForest(_)));
386+
assert!(matches!(result[0], Continuation::EnterForest { .. }));
333387
assert!(matches!(result[1], Continuation::StartNode(_)));
334388
}
335389

@@ -339,14 +393,20 @@ mod tests {
339393
// Push an incrementing continuation first (bottom of stack)
340394
stack.push_continuation(Continuation::StartNode(MastNodeId::new_unchecked(0)));
341395
// Push two non-incrementing continuations on top
342-
stack.push_continuation(Continuation::EnterForest(Arc::new(MastForest::new())));
343-
stack.push_continuation(Continuation::EnterForest(Arc::new(MastForest::new())));
396+
stack.push_continuation(Continuation::EnterForest {
397+
forest: Arc::new(MastForest::new()),
398+
package_debug_info: None,
399+
});
400+
stack.push_continuation(Continuation::EnterForest {
401+
forest: Arc::new(MastForest::new()),
402+
package_debug_info: None,
403+
});
344404

345405
let result: Vec<_> = stack.iter_continuations_for_next_clock().collect();
346406
// Should return: EnterForest, EnterForest, StartNode
347407
assert_eq!(result.len(), 3);
348-
assert!(matches!(result[0], Continuation::EnterForest(_)));
349-
assert!(matches!(result[1], Continuation::EnterForest(_)));
408+
assert!(matches!(result[0], Continuation::EnterForest { .. }));
409+
assert!(matches!(result[1], Continuation::EnterForest { .. }));
350410
assert!(matches!(result[2], Continuation::StartNode(_)));
351411
}
352412
}

processor/src/execution/basic_block.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use miden_mast_package::debug_info::DebugSourceNodeId;
55
use crate::{
66
BaseHost, BreakReason, Stopper,
77
continuation_stack::{Continuation, ContinuationStack},
8+
errors::PackageSourceDebugContext,
89
execution::{
910
ExecutionState, InternalBreakReason, execute_op, finalize_clock_cycle_with_continuation,
1011
finalize_clock_cycle_with_continuation_and_op_helpers,
@@ -281,13 +282,20 @@ where
281282
},
282283
_ => {
283284
// If the operation is not an Emit, we execute it normally.
285+
let source_debug_info = state.source_debug_info.clone();
286+
let package_source_context = source_debug_info.as_deref().map(|debug_info| {
287+
PackageSourceDebugContext::new_optional(
288+
debug_info,
289+
state.current_source_node_id(),
290+
)
291+
});
284292
match execute_op(
285293
state.processor,
286294
op,
287295
op_idx_in_block,
288296
state.host,
289297
state.tracer,
290-
state.package_source_context(),
298+
package_source_context,
291299
) {
292300
Ok(operation_helpers) => operation_helpers,
293301
Err(err) => {

processor/src/execution/dyn.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
use alloc::sync::Arc;
12
use core::ops::ControlFlow;
23

34
use miden_core::{FMP_ADDR, FMP_INIT_VALUE};
5+
use miden_mast_package::debug_info::{DebugSourceNodeId, PackageDebugInfo};
46

57
use crate::{
68
BaseHost, BreakReason, ContextId, MapExecErr, Stopper,
@@ -105,7 +107,7 @@ where
105107
// host).
106108
match current_forest.find_procedure_root(callee_hash) {
107109
Some(callee_id) => {
108-
let source_node_id = match state.source_debug_info {
110+
let source_node_id = match &state.source_debug_info {
109111
Some(source_debug_info) => source_debug_info
110112
.unique_source_root_for_exec_node(callee_id)
111113
.unwrap_or_default(),
@@ -254,8 +256,11 @@ where
254256
pub fn finish_load_mast_forest_from_dyn_start<P, S, T, F>(
255257
root_id: MastNodeId,
256258
new_forest: F,
259+
new_package_debug_info: Option<Arc<PackageDebugInfo>>,
260+
new_source_node_id: Option<DebugSourceNodeId>,
257261
processor: &mut P,
258262
current_forest: &mut F,
263+
current_package_debug_info: &mut Option<Arc<PackageDebugInfo>>,
259264
continuation_stack: &mut ContinuationStack<F>,
260265
tracer: &mut T,
261266
stopper: &S,
@@ -268,15 +273,19 @@ where
268273
{
269274
// Save the old forest: the continuation from start_clock_cycle references nodes in it.
270275
let old_forest = current_forest.clone();
276+
let old_package_debug_info = current_package_debug_info.clone();
271277

272278
// Push current forest to the continuation stack so that we can return to it
273-
continuation_stack.push_enter_forest(current_forest.clone());
279+
continuation_stack
280+
.push_enter_forest_with_package_debug_info(current_forest.clone(), old_package_debug_info);
274281

275282
// Push the root node of the external MAST forest onto the continuation stack.
276-
continuation_stack.push_start_node(root_id);
283+
continuation_stack
284+
.push_with_source_node_id(Continuation::StartNode(root_id), new_source_node_id);
277285

278286
// Set the new MAST forest as current
279287
*current_forest = new_forest;
288+
*current_package_debug_info = new_package_debug_info;
280289

281290
// Finalize the clock cycle corresponding to the DYN or DYNCALL operation. We pass the old
282291
// forest because the continuation was set during start_clock_cycle, which referenced the old

processor/src/execution/external.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
use alloc::sync::Arc;
12
use core::ops::ControlFlow;
23

3-
use miden_mast_package::debug_info::DebugSourceNodeId;
4+
use miden_mast_package::debug_info::{DebugSourceNodeId, PackageDebugInfo};
45

56
use crate::{
67
BreakReason,
@@ -54,8 +55,11 @@ where
5455
pub fn finish_load_mast_forest_from_external<F, T>(
5556
resolved_node_id_new_forest: MastNodeId,
5657
new_mast_forest: F,
58+
new_package_debug_info: Option<Arc<PackageDebugInfo>>,
59+
new_source_node_id: Option<DebugSourceNodeId>,
5760
external_node_id_old_forest: MastNodeId,
5861
current_forest: &mut F,
62+
current_package_debug_info: &mut Option<Arc<PackageDebugInfo>>,
5963
continuation_stack: &mut ContinuationStack<F>,
6064
tracer: &mut T,
6165
) -> ControlFlow<BreakReason<F>>
@@ -83,18 +87,21 @@ where
8387

8488
tracer.record_mast_forest_resolution(resolved_node_id_new_forest, &new_mast_forest);
8589

90+
let old_package_debug_info = current_package_debug_info.clone();
91+
8692
// Push current forest to the continuation stack so that we can return to it
87-
continuation_stack.push_enter_forest(old_forest.clone());
93+
continuation_stack
94+
.push_enter_forest_with_package_debug_info(old_forest.clone(), old_package_debug_info);
8895

8996
// Push the root node of the external MAST forest onto the continuation stack.
90-
//
91-
// Caller package debug info describes the forest that contained the `External` node, not the
92-
// loaded forest. The loaded root therefore starts without a source sidecar here.
93-
continuation_stack
94-
.push_with_source_node_id(Continuation::StartNode(resolved_node_id_new_forest), None);
97+
continuation_stack.push_with_source_node_id(
98+
Continuation::StartNode(resolved_node_id_new_forest),
99+
new_source_node_id,
100+
);
95101

96102
// Update the current forest to the new MAST forest.
97103
*current_forest = new_mast_forest;
104+
*current_package_debug_info = new_package_debug_info;
98105

99106
// Note that executing an External node does not end the clock cycle, so we do not finalize the
100107
// clock cycle here.
@@ -137,12 +144,16 @@ mod tests {
137144
let mut continuation_stack =
138145
ContinuationStack::new_with_source_node_id(&program, caller_source_node_id);
139146
let mut tracer = NoopTracer;
147+
let mut package_debug_info = None;
140148

141149
let result = finish_load_mast_forest_from_external(
142150
target_id,
143151
new_mast_forest,
152+
None,
153+
None,
144154
external_id,
145155
&mut current_forest,
156+
&mut package_debug_info,
146157
&mut continuation_stack,
147158
&mut tracer,
148159
);
@@ -154,7 +165,7 @@ mod tests {
154165
);
155166
assert_matches!(
156167
continuation_stack.pop_continuation_with_source_node_id(),
157-
Some((Continuation::EnterForest(_), None))
168+
Some((Continuation::EnterForest { .. }, None))
158169
);
159170
assert_matches!(
160171
continuation_stack.pop_continuation_with_source_node_id(),

0 commit comments

Comments
 (0)