1use alloc::{sync::Arc, vec::Vec};
2use core::ops::ControlFlow;
3
4use miden_core::{
5 Word,
6 mast::{MastForest, MastNodeId},
7 program::{Kernel, MIN_STACK_DEPTH, Program, StackOutputs},
8};
9use miden_mast_package::debug_info::{
10 DebugSourceGraphLookupError, DebugSourceNodeId, PackageDebugInfo,
11};
12use tracing::instrument;
13
14use super::{
15 FastProcessor, NoopTracer,
16 external::maybe_use_caller_error_context,
17 step::{BreakReason, NeverStopper, ResumeContext, StepStopper},
18};
19use crate::{
20 ExecutionError, ExecutionOutput, Host, LoadedMastForest, Stopper, SyncHost, TraceBuildInputs,
21 continuation_stack::ContinuationStack,
22 errors::{
23 MapExecErr, MapExecErrNoCtx, PackageSourceDebugContext, malformed_mast_forest_with_context,
24 },
25 execution::{
26 InternalBreakReason, execute_impl, finish_emit_op_execution,
27 finish_load_mast_forest_from_dyn_start, finish_load_mast_forest_from_external,
28 },
29 trace::execution_tracer::ExecutionTracer,
30 tracer::Tracer,
31};
32
33impl FastProcessor {
34 pub fn execute_sync(
39 self,
40 program: &Program,
41 host: &mut impl SyncHost,
42 ) -> Result<ExecutionOutput, ExecutionError> {
43 self.execute_with_tracer_sync(program, host, &mut NoopTracer)
44 }
45
46 pub fn execute_with_package_debug_info_sync(
53 self,
54 program: &Program,
55 package_debug_info: &PackageDebugInfo,
56 host: &mut impl SyncHost,
57 ) -> Result<ExecutionOutput, ExecutionError> {
58 self.execute_with_package_debug_info_and_tracer_sync(
59 program,
60 package_debug_info,
61 None,
62 host,
63 &mut NoopTracer,
64 )
65 }
66
67 pub fn execute_with_package_debug_info_at_source_node_sync(
74 self,
75 program: &Program,
76 package_debug_info: &PackageDebugInfo,
77 entrypoint_source_node_id: DebugSourceNodeId,
78 host: &mut impl SyncHost,
79 ) -> Result<ExecutionOutput, ExecutionError> {
80 self.execute_with_package_debug_info_and_tracer_sync(
81 program,
82 package_debug_info,
83 Some(entrypoint_source_node_id),
84 host,
85 &mut NoopTracer,
86 )
87 }
88
89 #[inline(always)]
91 pub async fn execute(
92 self,
93 program: &Program,
94 host: &mut impl Host,
95 ) -> Result<ExecutionOutput, ExecutionError> {
96 self.execute_with_tracer(program, host, &mut NoopTracer).await
97 }
98
99 #[inline(always)]
104 pub async fn execute_with_package_debug_info(
105 self,
106 program: &Program,
107 package_debug_info: &PackageDebugInfo,
108 host: &mut impl Host,
109 ) -> Result<ExecutionOutput, ExecutionError> {
110 self.execute_with_package_debug_info_and_tracer(
111 program,
112 package_debug_info,
113 None,
114 host,
115 &mut NoopTracer,
116 )
117 .await
118 }
119
120 #[inline(always)]
122 pub async fn execute_with_package_debug_info_at_source_node(
123 self,
124 program: &Program,
125 package_debug_info: &PackageDebugInfo,
126 entrypoint_source_node_id: DebugSourceNodeId,
127 host: &mut impl Host,
128 ) -> Result<ExecutionOutput, ExecutionError> {
129 self.execute_with_package_debug_info_and_tracer(
130 program,
131 package_debug_info,
132 Some(entrypoint_source_node_id),
133 host,
134 &mut NoopTracer,
135 )
136 .await
137 }
138
139 #[instrument(name = "execute_trace_inputs_sync", skip_all)]
161 pub fn execute_trace_inputs_sync(
162 self,
163 program: &Program,
164 host: &mut impl SyncHost,
165 ) -> Result<TraceBuildInputs, ExecutionError> {
166 let mut tracer = ExecutionTracer::new(
167 self.options.core_trace_fragment_size(),
168 self.options.max_stack_depth(),
169 );
170 let execution_output = self.execute_with_tracer_sync(program, host, &mut tracer)?;
171 Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer))
172 }
173
174 #[instrument(name = "execute_trace_inputs_with_package_debug_info_sync", skip_all)]
177 pub fn execute_trace_inputs_with_package_debug_info_sync(
178 self,
179 program: &Program,
180 package_debug_info: &PackageDebugInfo,
181 host: &mut impl SyncHost,
182 ) -> Result<TraceBuildInputs, ExecutionError> {
183 let mut tracer = ExecutionTracer::new(
184 self.options.core_trace_fragment_size(),
185 self.options.max_stack_depth(),
186 );
187 let execution_output = self.execute_with_package_debug_info_and_tracer_sync(
188 program,
189 package_debug_info,
190 None,
191 host,
192 &mut tracer,
193 )?;
194 Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer))
195 }
196
197 #[instrument(
201 name = "execute_trace_inputs_with_package_debug_info_at_source_node_sync",
202 skip_all
203 )]
204 pub fn execute_trace_inputs_with_package_debug_info_at_source_node_sync(
205 self,
206 program: &Program,
207 package_debug_info: &PackageDebugInfo,
208 entrypoint_source_node_id: DebugSourceNodeId,
209 host: &mut impl SyncHost,
210 ) -> Result<TraceBuildInputs, ExecutionError> {
211 let mut tracer = ExecutionTracer::new(
212 self.options.core_trace_fragment_size(),
213 self.options.max_stack_depth(),
214 );
215 let execution_output = self.execute_with_package_debug_info_and_tracer_sync(
216 program,
217 package_debug_info,
218 Some(entrypoint_source_node_id),
219 host,
220 &mut tracer,
221 )?;
222 Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer))
223 }
224
225 #[inline(always)]
227 #[instrument(name = "execute_trace_inputs", skip_all)]
228 pub async fn execute_trace_inputs(
229 self,
230 program: &Program,
231 host: &mut impl Host,
232 ) -> Result<TraceBuildInputs, ExecutionError> {
233 let mut tracer = ExecutionTracer::new(
234 self.options.core_trace_fragment_size(),
235 self.options.max_stack_depth(),
236 );
237 let execution_output = self.execute_with_tracer(program, host, &mut tracer).await?;
238 Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer))
239 }
240
241 #[cfg(any(test, feature = "testing"))]
243 #[inline(always)]
244 #[instrument(name = "execute_trace_inputs_with_package_debug_info", skip_all)]
245 pub async fn execute_trace_inputs_with_package_debug_info(
246 self,
247 program: &Program,
248 package_debug_info: &PackageDebugInfo,
249 host: &mut impl Host,
250 ) -> Result<TraceBuildInputs, ExecutionError> {
251 let mut tracer = ExecutionTracer::new(
252 self.options.core_trace_fragment_size(),
253 self.options.max_stack_depth(),
254 );
255 let execution_output = self
256 .execute_with_package_debug_info_and_tracer(
257 program,
258 package_debug_info,
259 None,
260 host,
261 &mut tracer,
262 )
263 .await?;
264 Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer))
265 }
266
267 #[cfg(any(test, feature = "testing"))]
270 #[inline(always)]
271 #[instrument(name = "execute_trace_inputs_with_package_debug_info_at_source_node", skip_all)]
272 pub async fn execute_trace_inputs_with_package_debug_info_at_source_node(
273 self,
274 program: &Program,
275 package_debug_info: &PackageDebugInfo,
276 entrypoint_source_node_id: DebugSourceNodeId,
277 host: &mut impl Host,
278 ) -> Result<TraceBuildInputs, ExecutionError> {
279 let mut tracer = ExecutionTracer::new(
280 self.options.core_trace_fragment_size(),
281 self.options.max_stack_depth(),
282 );
283 let execution_output = self
284 .execute_with_package_debug_info_and_tracer(
285 program,
286 package_debug_info,
287 Some(entrypoint_source_node_id),
288 host,
289 &mut tracer,
290 )
291 .await?;
292 Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer))
293 }
294
295 pub async fn execute_with_tracer<T>(
297 mut self,
298 program: &Program,
299 host: &mut impl Host,
300 tracer: &mut T,
301 ) -> Result<ExecutionOutput, ExecutionError>
302 where
303 T: Tracer<Processor = Self, Forest = Arc<MastForest>>,
304 {
305 let mut continuation_stack = ContinuationStack::new(program);
306 let mut current_forest = program.mast_forest().clone();
307 let mut package_debug_info = None;
308
309 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
310 let flow = self
311 .execute_impl_async(
312 &mut continuation_stack,
313 &mut current_forest,
314 program.kernel(),
315 host,
316 tracer,
317 &NeverStopper,
318 &mut package_debug_info,
319 )
320 .await;
321 Self::execution_result_from_flow(flow, self)
322 }
323
324 async fn execute_with_package_debug_info_and_tracer<T>(
327 mut self,
328 program: &Program,
329 package_debug_info: &PackageDebugInfo,
330 entrypoint_source_node_id: Option<DebugSourceNodeId>,
331 host: &mut impl Host,
332 tracer: &mut T,
333 ) -> Result<ExecutionOutput, ExecutionError>
334 where
335 T: Tracer<Processor = Self, Forest = Arc<MastForest>>,
336 {
337 let mut continuation_stack = Self::source_aware_continuation_stack(
338 program,
339 package_debug_info,
340 entrypoint_source_node_id,
341 )?;
342 let mut current_forest = program.mast_forest().clone();
343 let mut package_debug_info = Some(Arc::new(package_debug_info.clone()));
344
345 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
346 let flow = self
347 .execute_impl_async(
348 &mut continuation_stack,
349 &mut current_forest,
350 program.kernel(),
351 host,
352 tracer,
353 &NeverStopper,
354 &mut package_debug_info,
355 )
356 .await;
357 Self::execution_result_from_flow(flow, self)
358 }
359
360 pub fn execute_with_tracer_sync<T>(
362 mut self,
363 program: &Program,
364 host: &mut impl SyncHost,
365 tracer: &mut T,
366 ) -> Result<ExecutionOutput, ExecutionError>
367 where
368 T: Tracer<Processor = Self, Forest = Arc<MastForest>>,
369 {
370 let mut continuation_stack = ContinuationStack::new(program);
371 let mut current_forest = program.mast_forest().clone();
372 let mut package_debug_info = None;
373
374 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
375 let flow = self.execute_impl(
376 &mut continuation_stack,
377 &mut current_forest,
378 program.kernel(),
379 host,
380 tracer,
381 &NeverStopper,
382 &mut package_debug_info,
383 );
384 Self::execution_result_from_flow(flow, self)
385 }
386
387 fn execute_with_package_debug_info_and_tracer_sync<T>(
390 mut self,
391 program: &Program,
392 package_debug_info: &PackageDebugInfo,
393 entrypoint_source_node_id: Option<DebugSourceNodeId>,
394 host: &mut impl SyncHost,
395 tracer: &mut T,
396 ) -> Result<ExecutionOutput, ExecutionError>
397 where
398 T: Tracer<Processor = Self, Forest = Arc<MastForest>>,
399 {
400 let mut continuation_stack = Self::source_aware_continuation_stack(
401 program,
402 package_debug_info,
403 entrypoint_source_node_id,
404 )?;
405 let mut current_forest = program.mast_forest().clone();
406 let mut package_debug_info = Some(Arc::new(package_debug_info.clone()));
407
408 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
409 let flow = self.execute_impl(
410 &mut continuation_stack,
411 &mut current_forest,
412 program.kernel(),
413 host,
414 tracer,
415 &NeverStopper,
416 &mut package_debug_info,
417 );
418 Self::execution_result_from_flow(flow, self)
419 }
420
421 pub fn step_sync(
423 &mut self,
424 host: &mut impl SyncHost,
425 resume_ctx: ResumeContext,
426 ) -> Result<Option<ResumeContext>, ExecutionError> {
427 let ResumeContext {
428 mut current_forest,
429 mut continuation_stack,
430 kernel,
431 mut package_debug_info,
432 } = resume_ctx;
433
434 let flow = self.execute_impl(
435 &mut continuation_stack,
436 &mut current_forest,
437 &kernel,
438 host,
439 &mut NoopTracer,
440 &StepStopper,
441 &mut package_debug_info,
442 );
443 Self::resume_context_from_flow(
444 flow,
445 continuation_stack,
446 current_forest,
447 kernel,
448 package_debug_info,
449 )
450 }
451
452 pub fn step_with_package_debug_info_sync(
454 &mut self,
455 host: &mut impl SyncHost,
456 resume_ctx: ResumeContext,
457 package_debug_info: &PackageDebugInfo,
458 ) -> Result<Option<ResumeContext>, ExecutionError> {
459 let ResumeContext {
460 mut current_forest,
461 mut continuation_stack,
462 kernel,
463 package_debug_info: mut active_package_debug_info,
464 } = resume_ctx;
465 Self::ensure_source_aware_step_context(
466 &mut continuation_stack,
467 &mut active_package_debug_info,
468 package_debug_info,
469 )?;
470
471 let flow = self.execute_impl(
472 &mut continuation_stack,
473 &mut current_forest,
474 &kernel,
475 host,
476 &mut NoopTracer,
477 &StepStopper,
478 &mut active_package_debug_info,
479 );
480 Self::resume_context_from_flow(
481 flow,
482 continuation_stack,
483 current_forest,
484 kernel,
485 active_package_debug_info,
486 )
487 }
488
489 #[inline(always)]
491 pub async fn step(
492 &mut self,
493 host: &mut impl Host,
494 resume_ctx: ResumeContext,
495 ) -> Result<Option<ResumeContext>, ExecutionError> {
496 let ResumeContext {
497 mut current_forest,
498 mut continuation_stack,
499 kernel,
500 mut package_debug_info,
501 } = resume_ctx;
502
503 let flow = self
504 .execute_impl_async(
505 &mut continuation_stack,
506 &mut current_forest,
507 &kernel,
508 host,
509 &mut NoopTracer,
510 &StepStopper,
511 &mut package_debug_info,
512 )
513 .await;
514 Self::resume_context_from_flow(
515 flow,
516 continuation_stack,
517 current_forest,
518 kernel,
519 package_debug_info,
520 )
521 }
522
523 #[inline(always)]
525 pub async fn step_with_package_debug_info(
526 &mut self,
527 host: &mut impl Host,
528 resume_ctx: ResumeContext,
529 package_debug_info: &PackageDebugInfo,
530 ) -> Result<Option<ResumeContext>, ExecutionError> {
531 let ResumeContext {
532 mut current_forest,
533 mut continuation_stack,
534 kernel,
535 package_debug_info: mut active_package_debug_info,
536 } = resume_ctx;
537 Self::ensure_source_aware_step_context(
538 &mut continuation_stack,
539 &mut active_package_debug_info,
540 package_debug_info,
541 )?;
542
543 let flow = self
544 .execute_impl_async(
545 &mut continuation_stack,
546 &mut current_forest,
547 &kernel,
548 host,
549 &mut NoopTracer,
550 &StepStopper,
551 &mut active_package_debug_info,
552 )
553 .await;
554 Self::resume_context_from_flow(
555 flow,
556 continuation_stack,
557 current_forest,
558 kernel,
559 active_package_debug_info,
560 )
561 }
562
563 #[inline(always)]
565 fn trace_build_inputs_from_parts(
566 program: &Program,
567 execution_output: ExecutionOutput,
568 tracer: ExecutionTracer,
569 ) -> TraceBuildInputs {
570 TraceBuildInputs::from_execution(
571 program,
572 execution_output,
573 tracer.into_trace_generation_context(),
574 )
575 }
576
577 pub(super) fn source_aware_continuation_stack(
578 program: &Program,
579 package_debug_info: &PackageDebugInfo,
580 entrypoint_source_node_id: Option<DebugSourceNodeId>,
581 ) -> Result<ContinuationStack<Arc<MastForest>>, ExecutionError> {
582 if let Some(source_node_id) = entrypoint_source_node_id {
583 let Some(source_node) = package_debug_info.source_node(source_node_id) else {
584 return Err(ExecutionError::Internal(
585 "package debug source graph is missing the entrypoint source node",
586 ));
587 };
588 if source_node.exec_node != program.entrypoint() {
589 return Err(ExecutionError::Internal(
590 "package debug entrypoint source node does not match the program entrypoint",
591 ));
592 }
593
594 return Ok(ContinuationStack::new_with_source_node_id(program, source_node_id));
595 }
596
597 let Some(source_node_id) = package_debug_info
598 .unique_source_root_for_exec_node(program.entrypoint())
599 .map_err(|_| {
600 ExecutionError::Internal(
601 "package debug source graph has ambiguous or malformed entrypoint roots",
602 )
603 })?
604 else {
605 return Ok(ContinuationStack::new_with_optional_source_node_id(program, None));
606 };
607
608 Ok(ContinuationStack::new_with_source_node_id(program, source_node_id))
609 }
610
611 #[cfg(any(test, feature = "testing"))]
612 fn source_aware_resume_context(
613 &mut self,
614 program: &Program,
615 package_debug_info: &PackageDebugInfo,
616 entrypoint_source_node_id: Option<DebugSourceNodeId>,
617 ) -> Result<ResumeContext, ExecutionError> {
618 self.advice
619 .extend_map(program.mast_forest().advice_map())
620 .map_exec_err_no_ctx()?;
621
622 Ok(ResumeContext {
623 current_forest: program.mast_forest().clone(),
624 continuation_stack: Self::source_aware_continuation_stack(
625 program,
626 package_debug_info,
627 entrypoint_source_node_id,
628 )?,
629 kernel: program.kernel().clone(),
630 package_debug_info: Some(Arc::new(package_debug_info.clone())),
631 })
632 }
633
634 fn ensure_source_aware_step_context(
635 continuation_stack: &mut ContinuationStack<Arc<MastForest>>,
636 package_debug_info: &mut Option<Arc<PackageDebugInfo>>,
637 supplied_package_debug_info: &PackageDebugInfo,
638 ) -> Result<(), ExecutionError> {
639 if package_debug_info.is_none() {
640 *package_debug_info = Some(Arc::new(supplied_package_debug_info.clone()));
641 }
642
643 if !continuation_stack.tracks_source_nodes() {
644 let source_node_id = Self::source_root_for_next_continuation(
645 continuation_stack,
646 package_debug_info.as_deref().expect("package debug info was just initialized"),
647 )?;
648 continuation_stack.start_tracking_source_nodes(source_node_id);
649 }
650
651 Ok(())
652 }
653
654 fn source_root_for_next_continuation(
655 continuation_stack: &ContinuationStack<Arc<MastForest>>,
656 package_debug_info: &PackageDebugInfo,
657 ) -> Result<Option<DebugSourceNodeId>, ExecutionError> {
658 let Some((continuation, _)) = continuation_stack.peek_continuation_with_source_node_id()
659 else {
660 return Ok(None);
661 };
662
663 let Some(exec_node) = continuation.exec_node() else {
664 return Ok(None);
665 };
666
667 package_debug_info.unique_source_root_for_exec_node(exec_node).map_err(|_| {
668 ExecutionError::Internal(
669 "package debug source graph has ambiguous or malformed continuation roots",
670 )
671 })
672 }
673
674 #[inline(always)]
676 fn resume_context_from_flow(
677 flow: ControlFlow<BreakReason<Arc<MastForest>>, StackOutputs>,
678 mut continuation_stack: ContinuationStack<Arc<MastForest>>,
679 current_forest: Arc<MastForest>,
680 kernel: Kernel,
681 package_debug_info: Option<Arc<PackageDebugInfo>>,
682 ) -> Result<Option<ResumeContext>, ExecutionError> {
683 match flow {
684 ControlFlow::Continue(_) => Ok(None),
685 ControlFlow::Break(break_reason) => match break_reason {
686 BreakReason::Err(err) => Err(err),
687 BreakReason::Stopped(maybe_continuation) => {
688 if let Some((continuation, source_node_id)) = maybe_continuation {
689 continuation_stack.push_with_source_node_id(continuation, source_node_id);
690 }
691
692 Ok(Some(ResumeContext {
693 current_forest,
694 continuation_stack,
695 kernel,
696 package_debug_info,
697 }))
698 },
699 },
700 }
701 }
702
703 #[inline(always)]
705 fn current_stack_outputs(&self) -> StackOutputs {
706 StackOutputs::new(
707 &self.stack[self.stack_bot_idx..self.stack_top_idx]
708 .iter()
709 .rev()
710 .copied()
711 .collect::<Vec<_>>(),
712 )
713 .unwrap()
714 }
715
716 fn execute_impl<S, T>(
722 &mut self,
723 continuation_stack: &mut ContinuationStack<Arc<MastForest>>,
724 current_forest: &mut Arc<MastForest>,
725 kernel: &Kernel,
726 host: &mut impl SyncHost,
727 tracer: &mut T,
728 stopper: &S,
729 package_debug_info: &mut Option<Arc<PackageDebugInfo>>,
730 ) -> ControlFlow<BreakReason<Arc<MastForest>>, StackOutputs>
731 where
732 S: Stopper<Processor = Self, Forest = Arc<MastForest>>,
733 T: Tracer<Processor = Self, Forest = Arc<MastForest>>,
734 {
735 while let ControlFlow::Break(internal_break_reason) = execute_impl(
736 self,
737 continuation_stack,
738 current_forest,
739 kernel,
740 host,
741 tracer,
742 stopper,
743 package_debug_info,
744 ) {
745 let current_package_debug_info = package_debug_info.as_deref();
746 let source_aware_execution =
747 current_package_debug_info.is_some() || continuation_stack.tracks_source_nodes();
748 match internal_break_reason {
749 InternalBreakReason::User(break_reason) => return ControlFlow::Break(break_reason),
750 InternalBreakReason::Emit { op_idx, continuation, source_node_id } => {
751 self.op_emit_sync(host, op_idx, current_package_debug_info, source_node_id)?;
752
753 finish_emit_op_execution(
754 continuation,
755 source_node_id,
756 self,
757 continuation_stack,
758 current_forest,
759 tracer,
760 stopper,
761 )?;
762 },
763 InternalBreakReason::LoadMastForestFromDyn { callee_hash, source_node_id } => {
764 let (root_id, new_forest, new_package_debug_info, new_source_node_id) =
765 match self.load_mast_forest_sync(
766 callee_hash,
767 host,
768 current_package_debug_info,
769 source_node_id,
770 source_aware_execution,
771 ) {
772 Ok(result) => result,
773 Err(err) => return ControlFlow::Break(BreakReason::Err(err)),
774 };
775
776 finish_load_mast_forest_from_dyn_start(
777 root_id,
778 new_forest,
779 new_package_debug_info,
780 new_source_node_id,
781 self,
782 current_forest,
783 package_debug_info,
784 continuation_stack,
785 tracer,
786 stopper,
787 )?;
788 },
789 InternalBreakReason::LoadMastForestFromExternal {
790 external_node_id,
791 procedure_hash,
792 source_node_id,
793 } => {
794 let (root_id, new_forest, new_package_debug_info, new_source_node_id) =
795 match self.load_mast_forest_sync(
796 procedure_hash,
797 host,
798 current_package_debug_info,
799 source_node_id,
800 source_aware_execution,
801 ) {
802 Ok(result) => result,
803 Err(err) => {
804 let maybe_enriched_err = maybe_use_caller_error_context(
805 err,
806 continuation_stack,
807 current_package_debug_info,
808 host,
809 );
810 return ControlFlow::Break(BreakReason::Err(maybe_enriched_err));
811 },
812 };
813
814 finish_load_mast_forest_from_external(
815 root_id,
816 new_forest,
817 new_package_debug_info,
818 new_source_node_id,
819 external_node_id,
820 current_forest,
821 package_debug_info,
822 continuation_stack,
823 tracer,
824 )?;
825 },
826 }
827 }
828
829 match StackOutputs::new(
830 &self.stack[self.stack_bot_idx..self.stack_top_idx]
831 .iter()
832 .rev()
833 .copied()
834 .collect::<Vec<_>>(),
835 ) {
836 Ok(stack_outputs) => ControlFlow::Continue(stack_outputs),
837 Err(_) => ControlFlow::Break(BreakReason::Err(ExecutionError::OutputStackOverflow(
838 self.stack_top_idx - self.stack_bot_idx - MIN_STACK_DEPTH,
839 ))),
840 }
841 }
842
843 async fn execute_impl_async<S, T>(
844 &mut self,
845 continuation_stack: &mut ContinuationStack<Arc<MastForest>>,
846 current_forest: &mut Arc<MastForest>,
847 kernel: &Kernel,
848 host: &mut impl Host,
849 tracer: &mut T,
850 stopper: &S,
851 package_debug_info: &mut Option<Arc<PackageDebugInfo>>,
852 ) -> ControlFlow<BreakReason<Arc<MastForest>>, StackOutputs>
853 where
854 S: Stopper<Processor = Self, Forest = Arc<MastForest>>,
855 T: Tracer<Processor = Self, Forest = Arc<MastForest>>,
856 {
857 while let ControlFlow::Break(internal_break_reason) = execute_impl(
858 self,
859 continuation_stack,
860 current_forest,
861 kernel,
862 host,
863 tracer,
864 stopper,
865 package_debug_info,
866 ) {
867 let current_package_debug_info = package_debug_info.as_deref();
868 let source_aware_execution =
869 current_package_debug_info.is_some() || continuation_stack.tracks_source_nodes();
870 match internal_break_reason {
871 InternalBreakReason::User(break_reason) => return ControlFlow::Break(break_reason),
872 InternalBreakReason::Emit { op_idx, continuation, source_node_id } => {
873 self.op_emit(host, op_idx, current_package_debug_info, source_node_id).await?;
874
875 finish_emit_op_execution(
876 continuation,
877 source_node_id,
878 self,
879 continuation_stack,
880 current_forest,
881 tracer,
882 stopper,
883 )?;
884 },
885 InternalBreakReason::LoadMastForestFromDyn { callee_hash, source_node_id } => {
886 let (root_id, new_forest, new_package_debug_info, new_source_node_id) =
887 match self
888 .load_mast_forest(
889 callee_hash,
890 host,
891 current_package_debug_info,
892 source_node_id,
893 source_aware_execution,
894 )
895 .await
896 {
897 Ok(result) => result,
898 Err(err) => return ControlFlow::Break(BreakReason::Err(err)),
899 };
900
901 finish_load_mast_forest_from_dyn_start(
902 root_id,
903 new_forest,
904 new_package_debug_info,
905 new_source_node_id,
906 self,
907 current_forest,
908 package_debug_info,
909 continuation_stack,
910 tracer,
911 stopper,
912 )?;
913 },
914 InternalBreakReason::LoadMastForestFromExternal {
915 external_node_id,
916 procedure_hash,
917 source_node_id,
918 } => {
919 let (root_id, new_forest, new_package_debug_info, new_source_node_id) =
920 match self
921 .load_mast_forest(
922 procedure_hash,
923 host,
924 current_package_debug_info,
925 source_node_id,
926 source_aware_execution,
927 )
928 .await
929 {
930 Ok(result) => result,
931 Err(err) => {
932 let maybe_enriched_err = maybe_use_caller_error_context(
933 err,
934 continuation_stack,
935 current_package_debug_info,
936 host,
937 );
938 return ControlFlow::Break(BreakReason::Err(maybe_enriched_err));
939 },
940 };
941
942 finish_load_mast_forest_from_external(
943 root_id,
944 new_forest,
945 new_package_debug_info,
946 new_source_node_id,
947 external_node_id,
948 current_forest,
949 package_debug_info,
950 continuation_stack,
951 tracer,
952 )?;
953 },
954 }
955 }
956
957 match StackOutputs::new(
958 &self.stack[self.stack_bot_idx..self.stack_top_idx]
959 .iter()
960 .rev()
961 .copied()
962 .collect::<Vec<_>>(),
963 ) {
964 Ok(stack_outputs) => ControlFlow::Continue(stack_outputs),
965 Err(_) => ControlFlow::Break(BreakReason::Err(ExecutionError::OutputStackOverflow(
966 self.stack_top_idx - self.stack_bot_idx - MIN_STACK_DEPTH,
967 ))),
968 }
969 }
970
971 fn load_mast_forest_sync(
975 &mut self,
976 node_digest: Word,
977 host: &mut impl SyncHost,
978 package_debug_info: Option<&PackageDebugInfo>,
979 source_node_id: Option<DebugSourceNodeId>,
980 source_aware_execution: bool,
981 ) -> Result<
982 (
983 MastNodeId,
984 Arc<MastForest>,
985 Option<Arc<PackageDebugInfo>>,
986 Option<DebugSourceNodeId>,
987 ),
988 ExecutionError,
989 > {
990 let loaded_mast_forest = host.get_mast_forest(&node_digest).ok_or_else(|| {
991 match (package_debug_info, source_node_id) {
992 (Some(debug_info), Some(source_node_id)) => {
993 crate::errors::procedure_not_found_with_package_source_context(
994 node_digest,
995 PackageSourceDebugContext::new(debug_info, source_node_id),
996 host,
997 )
998 },
999 _ => crate::errors::procedure_not_found_with_context(node_digest),
1000 }
1001 })?;
1002 let mast_forest = loaded_mast_forest.mast_forest().clone();
1003
1004 let root_id = mast_forest.find_procedure_root(node_digest).ok_or_else(|| {
1005 let context = match (package_debug_info, source_node_id) {
1006 (Some(debug_info), Some(source_node_id)) => {
1007 Some(PackageSourceDebugContext::new(debug_info, source_node_id))
1008 },
1009 _ => None,
1010 };
1011 malformed_mast_forest_with_context(node_digest, context, host)
1012 })?;
1013
1014 self.advice.extend_map(mast_forest.advice_map()).map_exec_err()?;
1015 let (loaded_package_debug_info, loaded_source_node_id) =
1016 Self::loaded_package_source_context(
1017 &loaded_mast_forest,
1018 root_id,
1019 source_aware_execution,
1020 )?;
1021
1022 Ok((root_id, mast_forest, loaded_package_debug_info, loaded_source_node_id))
1023 }
1024
1025 async fn load_mast_forest(
1026 &mut self,
1027 node_digest: Word,
1028 host: &mut impl Host,
1029 package_debug_info: Option<&PackageDebugInfo>,
1030 source_node_id: Option<DebugSourceNodeId>,
1031 source_aware_execution: bool,
1032 ) -> Result<
1033 (
1034 MastNodeId,
1035 Arc<MastForest>,
1036 Option<Arc<PackageDebugInfo>>,
1037 Option<DebugSourceNodeId>,
1038 ),
1039 ExecutionError,
1040 > {
1041 let loaded_mast_forest = if let Some(mast_forest) = host.get_mast_forest(&node_digest).await
1042 {
1043 mast_forest
1044 } else {
1045 return Err(match (package_debug_info, source_node_id) {
1046 (Some(debug_info), Some(source_node_id)) => {
1047 crate::errors::procedure_not_found_with_package_source_context(
1048 node_digest,
1049 PackageSourceDebugContext::new(debug_info, source_node_id),
1050 host,
1051 )
1052 },
1053 _ => crate::errors::procedure_not_found_with_context(node_digest),
1054 });
1055 };
1056 let mast_forest = loaded_mast_forest.mast_forest().clone();
1057
1058 let root_id = mast_forest.find_procedure_root(node_digest).ok_or_else(|| {
1059 let context = match (package_debug_info, source_node_id) {
1060 (Some(debug_info), Some(source_node_id)) => {
1061 Some(PackageSourceDebugContext::new(debug_info, source_node_id))
1062 },
1063 _ => None,
1064 };
1065 malformed_mast_forest_with_context(node_digest, context, host)
1066 })?;
1067
1068 self.advice.extend_map(mast_forest.advice_map()).map_exec_err()?;
1069 let (loaded_package_debug_info, loaded_source_node_id) =
1070 Self::loaded_package_source_context(
1071 &loaded_mast_forest,
1072 root_id,
1073 source_aware_execution,
1074 )?;
1075
1076 Ok((root_id, mast_forest, loaded_package_debug_info, loaded_source_node_id))
1077 }
1078
1079 fn loaded_package_source_context(
1080 loaded_mast_forest: &LoadedMastForest,
1081 root_id: MastNodeId,
1082 source_aware_execution: bool,
1083 ) -> Result<(Option<Arc<PackageDebugInfo>>, Option<DebugSourceNodeId>), ExecutionError> {
1084 if !source_aware_execution {
1085 return Ok((None, None));
1086 }
1087
1088 let Some(package_debug_info) = loaded_mast_forest
1089 .package_debug_info()
1090 .map_err(|_| ExecutionError::Internal("loaded package debug info is malformed"))?
1091 else {
1092 return Ok((None, None));
1093 };
1094
1095 let source_node_id = match package_debug_info.unique_source_root_for_exec_node(root_id) {
1096 Ok(source_node_id) => source_node_id,
1097 Err(DebugSourceGraphLookupError::AmbiguousRoot { .. }) => None,
1098 Err(_) => {
1099 return Err(ExecutionError::Internal(
1100 "loaded package debug source graph has malformed entrypoint roots",
1101 ));
1102 },
1103 };
1104
1105 Ok((Some(package_debug_info), source_node_id))
1106 }
1107
1108 pub fn execute_by_step_sync(
1110 mut self,
1111 program: &Program,
1112 host: &mut impl SyncHost,
1113 ) -> Result<StackOutputs, ExecutionError> {
1114 let mut current_resume_ctx = self.get_initial_resume_context(program)?;
1115
1116 loop {
1117 match self.step_sync(host, current_resume_ctx)? {
1118 Some(next_resume_ctx) => {
1119 current_resume_ctx = next_resume_ctx;
1120 },
1121 None => break Ok(self.current_stack_outputs()),
1122 }
1123 }
1124 }
1125
1126 #[cfg(any(test, feature = "testing"))]
1129 pub fn execute_by_step_with_package_debug_info_sync(
1130 mut self,
1131 program: &Program,
1132 package_debug_info: &PackageDebugInfo,
1133 host: &mut impl SyncHost,
1134 ) -> Result<StackOutputs, ExecutionError> {
1135 let mut current_resume_ctx =
1136 self.source_aware_resume_context(program, package_debug_info, None)?;
1137
1138 loop {
1139 match self.step_with_package_debug_info_sync(
1140 host,
1141 current_resume_ctx,
1142 package_debug_info,
1143 )? {
1144 Some(next_resume_ctx) => {
1145 current_resume_ctx = next_resume_ctx;
1146 },
1147 None => break Ok(self.current_stack_outputs()),
1148 }
1149 }
1150 }
1151
1152 #[cfg(any(test, feature = "testing"))]
1155 pub fn execute_by_step_with_package_debug_info_at_source_node_sync(
1156 mut self,
1157 program: &Program,
1158 package_debug_info: &PackageDebugInfo,
1159 entrypoint_source_node_id: DebugSourceNodeId,
1160 host: &mut impl SyncHost,
1161 ) -> Result<StackOutputs, ExecutionError> {
1162 let mut current_resume_ctx = self.source_aware_resume_context(
1163 program,
1164 package_debug_info,
1165 Some(entrypoint_source_node_id),
1166 )?;
1167
1168 loop {
1169 match self.step_with_package_debug_info_sync(
1170 host,
1171 current_resume_ctx,
1172 package_debug_info,
1173 )? {
1174 Some(next_resume_ctx) => {
1175 current_resume_ctx = next_resume_ctx;
1176 },
1177 None => break Ok(self.current_stack_outputs()),
1178 }
1179 }
1180 }
1181
1182 #[inline(always)]
1184 pub async fn execute_by_step(
1185 mut self,
1186 program: &Program,
1187 host: &mut impl Host,
1188 ) -> Result<StackOutputs, ExecutionError> {
1189 let mut current_resume_ctx = self.get_initial_resume_context(program)?;
1190 let mut processor = self;
1191
1192 loop {
1193 match processor.step(host, current_resume_ctx).await? {
1194 Some(next_resume_ctx) => {
1195 current_resume_ctx = next_resume_ctx;
1196 },
1197 None => break Ok(processor.current_stack_outputs()),
1198 }
1199 }
1200 }
1201
1202 #[cfg(any(test, feature = "testing"))]
1204 #[inline(always)]
1205 pub async fn execute_by_step_with_package_debug_info(
1206 mut self,
1207 program: &Program,
1208 package_debug_info: &PackageDebugInfo,
1209 host: &mut impl Host,
1210 ) -> Result<StackOutputs, ExecutionError> {
1211 let mut current_resume_ctx =
1212 self.source_aware_resume_context(program, package_debug_info, None)?;
1213 let mut processor = self;
1214
1215 loop {
1216 match processor
1217 .step_with_package_debug_info(host, current_resume_ctx, package_debug_info)
1218 .await?
1219 {
1220 Some(next_resume_ctx) => {
1221 current_resume_ctx = next_resume_ctx;
1222 },
1223 None => break Ok(processor.current_stack_outputs()),
1224 }
1225 }
1226 }
1227
1228 #[cfg(any(test, feature = "testing"))]
1231 #[inline(always)]
1232 pub async fn execute_by_step_with_package_debug_info_at_source_node(
1233 mut self,
1234 program: &Program,
1235 package_debug_info: &PackageDebugInfo,
1236 entrypoint_source_node_id: DebugSourceNodeId,
1237 host: &mut impl Host,
1238 ) -> Result<StackOutputs, ExecutionError> {
1239 let mut current_resume_ctx = self.source_aware_resume_context(
1240 program,
1241 package_debug_info,
1242 Some(entrypoint_source_node_id),
1243 )?;
1244 let mut processor = self;
1245
1246 loop {
1247 match processor
1248 .step_with_package_debug_info(host, current_resume_ctx, package_debug_info)
1249 .await?
1250 {
1251 Some(next_resume_ctx) => {
1252 current_resume_ctx = next_resume_ctx;
1253 },
1254 None => break Ok(processor.current_stack_outputs()),
1255 }
1256 }
1257 }
1258
1259 #[cfg(any(test, feature = "testing"))]
1263 pub fn execute_mut_sync(
1264 &mut self,
1265 program: &Program,
1266 host: &mut impl SyncHost,
1267 ) -> Result<StackOutputs, ExecutionError> {
1268 let mut continuation_stack = ContinuationStack::new(program);
1269 let mut current_forest = program.mast_forest().clone();
1270 let mut package_debug_info = None;
1271
1272 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
1273
1274 let flow = self.execute_impl(
1275 &mut continuation_stack,
1276 &mut current_forest,
1277 program.kernel(),
1278 host,
1279 &mut NoopTracer,
1280 &NeverStopper,
1281 &mut package_debug_info,
1282 );
1283 Self::stack_result_from_flow(flow)
1284 }
1285
1286 #[cfg(any(test, feature = "testing"))]
1288 #[inline(always)]
1289 pub async fn execute_mut(
1290 &mut self,
1291 program: &Program,
1292 host: &mut impl Host,
1293 ) -> Result<StackOutputs, ExecutionError> {
1294 let mut continuation_stack = ContinuationStack::new(program);
1295 let mut current_forest = program.mast_forest().clone();
1296 let mut package_debug_info = None;
1297
1298 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
1299
1300 let flow = self
1301 .execute_impl_async(
1302 &mut continuation_stack,
1303 &mut current_forest,
1304 program.kernel(),
1305 host,
1306 &mut NoopTracer,
1307 &NeverStopper,
1308 &mut package_debug_info,
1309 )
1310 .await;
1311 Self::stack_result_from_flow(flow)
1312 }
1313}