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 #[cfg(any(test, feature = "testing"))]
454 pub fn step_with_package_debug_info_sync(
455 &mut self,
456 host: &mut impl SyncHost,
457 resume_ctx: ResumeContext,
458 package_debug_info: &PackageDebugInfo,
459 ) -> Result<Option<ResumeContext>, ExecutionError> {
460 let ResumeContext {
461 mut current_forest,
462 mut continuation_stack,
463 kernel,
464 package_debug_info: mut active_package_debug_info,
465 } = resume_ctx;
466 Self::ensure_source_aware_step_context(
467 &mut continuation_stack,
468 &mut active_package_debug_info,
469 package_debug_info,
470 )?;
471
472 let flow = self.execute_impl(
473 &mut continuation_stack,
474 &mut current_forest,
475 &kernel,
476 host,
477 &mut NoopTracer,
478 &StepStopper,
479 &mut active_package_debug_info,
480 );
481 Self::resume_context_from_flow(
482 flow,
483 continuation_stack,
484 current_forest,
485 kernel,
486 active_package_debug_info,
487 )
488 }
489
490 #[inline(always)]
492 pub async fn step(
493 &mut self,
494 host: &mut impl Host,
495 resume_ctx: ResumeContext,
496 ) -> Result<Option<ResumeContext>, ExecutionError> {
497 let ResumeContext {
498 mut current_forest,
499 mut continuation_stack,
500 kernel,
501 mut package_debug_info,
502 } = resume_ctx;
503
504 let flow = self
505 .execute_impl_async(
506 &mut continuation_stack,
507 &mut current_forest,
508 &kernel,
509 host,
510 &mut NoopTracer,
511 &StepStopper,
512 &mut package_debug_info,
513 )
514 .await;
515 Self::resume_context_from_flow(
516 flow,
517 continuation_stack,
518 current_forest,
519 kernel,
520 package_debug_info,
521 )
522 }
523
524 #[cfg(any(test, feature = "testing"))]
526 #[inline(always)]
527 pub async fn step_with_package_debug_info(
528 &mut self,
529 host: &mut impl Host,
530 resume_ctx: ResumeContext,
531 package_debug_info: &PackageDebugInfo,
532 ) -> Result<Option<ResumeContext>, ExecutionError> {
533 let ResumeContext {
534 mut current_forest,
535 mut continuation_stack,
536 kernel,
537 package_debug_info: mut active_package_debug_info,
538 } = resume_ctx;
539 Self::ensure_source_aware_step_context(
540 &mut continuation_stack,
541 &mut active_package_debug_info,
542 package_debug_info,
543 )?;
544
545 let flow = self
546 .execute_impl_async(
547 &mut continuation_stack,
548 &mut current_forest,
549 &kernel,
550 host,
551 &mut NoopTracer,
552 &StepStopper,
553 &mut active_package_debug_info,
554 )
555 .await;
556 Self::resume_context_from_flow(
557 flow,
558 continuation_stack,
559 current_forest,
560 kernel,
561 active_package_debug_info,
562 )
563 }
564
565 #[inline(always)]
567 fn trace_build_inputs_from_parts(
568 program: &Program,
569 execution_output: ExecutionOutput,
570 tracer: ExecutionTracer,
571 ) -> TraceBuildInputs {
572 TraceBuildInputs::from_execution(
573 program,
574 execution_output,
575 tracer.into_trace_generation_context(),
576 )
577 }
578
579 fn source_aware_continuation_stack(
580 program: &Program,
581 package_debug_info: &PackageDebugInfo,
582 entrypoint_source_node_id: Option<DebugSourceNodeId>,
583 ) -> Result<ContinuationStack<Arc<MastForest>>, ExecutionError> {
584 if let Some(source_node_id) = entrypoint_source_node_id {
585 let Some(source_node) = package_debug_info.source_node(source_node_id) else {
586 return Err(ExecutionError::Internal(
587 "package debug source graph is missing the entrypoint source node",
588 ));
589 };
590 if source_node.exec_node != program.entrypoint() {
591 return Err(ExecutionError::Internal(
592 "package debug entrypoint source node does not match the program entrypoint",
593 ));
594 }
595
596 return Ok(ContinuationStack::new_with_source_node_id(program, source_node_id));
597 }
598
599 let Some(source_node_id) = package_debug_info
600 .unique_source_root_for_exec_node(program.entrypoint())
601 .map_err(|_| {
602 ExecutionError::Internal(
603 "package debug source graph has ambiguous or malformed entrypoint roots",
604 )
605 })?
606 else {
607 return Ok(ContinuationStack::new_with_optional_source_node_id(program, None));
608 };
609
610 Ok(ContinuationStack::new_with_source_node_id(program, source_node_id))
611 }
612
613 #[cfg(any(test, feature = "testing"))]
614 fn source_aware_resume_context(
615 &mut self,
616 program: &Program,
617 package_debug_info: &PackageDebugInfo,
618 entrypoint_source_node_id: Option<DebugSourceNodeId>,
619 ) -> Result<ResumeContext, ExecutionError> {
620 self.advice
621 .extend_map(program.mast_forest().advice_map())
622 .map_exec_err_no_ctx()?;
623
624 Ok(ResumeContext {
625 current_forest: program.mast_forest().clone(),
626 continuation_stack: Self::source_aware_continuation_stack(
627 program,
628 package_debug_info,
629 entrypoint_source_node_id,
630 )?,
631 kernel: program.kernel().clone(),
632 package_debug_info: Some(Arc::new(package_debug_info.clone())),
633 })
634 }
635
636 #[cfg(any(test, feature = "testing"))]
637 fn ensure_source_aware_step_context(
638 continuation_stack: &mut ContinuationStack<Arc<MastForest>>,
639 package_debug_info: &mut Option<Arc<PackageDebugInfo>>,
640 supplied_package_debug_info: &PackageDebugInfo,
641 ) -> Result<(), ExecutionError> {
642 if package_debug_info.is_none() {
643 *package_debug_info = Some(Arc::new(supplied_package_debug_info.clone()));
644 }
645
646 if !continuation_stack.tracks_source_nodes() {
647 let source_node_id = Self::source_root_for_next_continuation(
648 continuation_stack,
649 package_debug_info.as_deref().expect("package debug info was just initialized"),
650 )?;
651 continuation_stack.start_tracking_source_nodes(source_node_id);
652 }
653
654 Ok(())
655 }
656
657 #[cfg(any(test, feature = "testing"))]
658 fn source_root_for_next_continuation(
659 continuation_stack: &ContinuationStack<Arc<MastForest>>,
660 package_debug_info: &PackageDebugInfo,
661 ) -> Result<Option<DebugSourceNodeId>, ExecutionError> {
662 let Some((continuation, _)) = continuation_stack.peek_continuation_with_source_node_id()
663 else {
664 return Ok(None);
665 };
666
667 let Some(exec_node) = continuation.exec_node() else {
668 return Ok(None);
669 };
670
671 package_debug_info.unique_source_root_for_exec_node(exec_node).map_err(|_| {
672 ExecutionError::Internal(
673 "package debug source graph has ambiguous or malformed continuation roots",
674 )
675 })
676 }
677
678 #[inline(always)]
680 fn resume_context_from_flow(
681 flow: ControlFlow<BreakReason<Arc<MastForest>>, StackOutputs>,
682 mut continuation_stack: ContinuationStack<Arc<MastForest>>,
683 current_forest: Arc<MastForest>,
684 kernel: Kernel,
685 package_debug_info: Option<Arc<PackageDebugInfo>>,
686 ) -> Result<Option<ResumeContext>, ExecutionError> {
687 match flow {
688 ControlFlow::Continue(_) => Ok(None),
689 ControlFlow::Break(break_reason) => match break_reason {
690 BreakReason::Err(err) => Err(err),
691 BreakReason::Stopped(maybe_continuation) => {
692 if let Some((continuation, source_node_id)) = maybe_continuation {
693 continuation_stack.push_with_source_node_id(continuation, source_node_id);
694 }
695
696 Ok(Some(ResumeContext {
697 current_forest,
698 continuation_stack,
699 kernel,
700 package_debug_info,
701 }))
702 },
703 },
704 }
705 }
706
707 #[inline(always)]
709 fn current_stack_outputs(&self) -> StackOutputs {
710 StackOutputs::new(
711 &self.stack[self.stack_bot_idx..self.stack_top_idx]
712 .iter()
713 .rev()
714 .copied()
715 .collect::<Vec<_>>(),
716 )
717 .unwrap()
718 }
719
720 fn execute_impl<S, T>(
726 &mut self,
727 continuation_stack: &mut ContinuationStack<Arc<MastForest>>,
728 current_forest: &mut Arc<MastForest>,
729 kernel: &Kernel,
730 host: &mut impl SyncHost,
731 tracer: &mut T,
732 stopper: &S,
733 package_debug_info: &mut Option<Arc<PackageDebugInfo>>,
734 ) -> ControlFlow<BreakReason<Arc<MastForest>>, StackOutputs>
735 where
736 S: Stopper<Processor = Self, Forest = Arc<MastForest>>,
737 T: Tracer<Processor = Self, Forest = Arc<MastForest>>,
738 {
739 while let ControlFlow::Break(internal_break_reason) = execute_impl(
740 self,
741 continuation_stack,
742 current_forest,
743 kernel,
744 host,
745 tracer,
746 stopper,
747 package_debug_info,
748 ) {
749 let current_package_debug_info = package_debug_info.as_deref();
750 let source_aware_execution =
751 current_package_debug_info.is_some() || continuation_stack.tracks_source_nodes();
752 match internal_break_reason {
753 InternalBreakReason::User(break_reason) => return ControlFlow::Break(break_reason),
754 InternalBreakReason::Emit { op_idx, continuation, source_node_id } => {
755 self.op_emit_sync(host, op_idx, current_package_debug_info, source_node_id)?;
756
757 finish_emit_op_execution(
758 continuation,
759 source_node_id,
760 self,
761 continuation_stack,
762 current_forest,
763 tracer,
764 stopper,
765 )?;
766 },
767 InternalBreakReason::LoadMastForestFromDyn { callee_hash, source_node_id } => {
768 let (root_id, new_forest, new_package_debug_info, new_source_node_id) =
769 match self.load_mast_forest_sync(
770 callee_hash,
771 host,
772 current_package_debug_info,
773 source_node_id,
774 source_aware_execution,
775 ) {
776 Ok(result) => result,
777 Err(err) => return ControlFlow::Break(BreakReason::Err(err)),
778 };
779
780 finish_load_mast_forest_from_dyn_start(
781 root_id,
782 new_forest,
783 new_package_debug_info,
784 new_source_node_id,
785 self,
786 current_forest,
787 package_debug_info,
788 continuation_stack,
789 tracer,
790 stopper,
791 )?;
792 },
793 InternalBreakReason::LoadMastForestFromExternal {
794 external_node_id,
795 procedure_hash,
796 source_node_id,
797 } => {
798 let (root_id, new_forest, new_package_debug_info, new_source_node_id) =
799 match self.load_mast_forest_sync(
800 procedure_hash,
801 host,
802 current_package_debug_info,
803 source_node_id,
804 source_aware_execution,
805 ) {
806 Ok(result) => result,
807 Err(err) => {
808 let maybe_enriched_err = maybe_use_caller_error_context(
809 err,
810 continuation_stack,
811 current_package_debug_info,
812 host,
813 );
814 return ControlFlow::Break(BreakReason::Err(maybe_enriched_err));
815 },
816 };
817
818 finish_load_mast_forest_from_external(
819 root_id,
820 new_forest,
821 new_package_debug_info,
822 new_source_node_id,
823 external_node_id,
824 current_forest,
825 package_debug_info,
826 continuation_stack,
827 tracer,
828 )?;
829 },
830 }
831 }
832
833 match StackOutputs::new(
834 &self.stack[self.stack_bot_idx..self.stack_top_idx]
835 .iter()
836 .rev()
837 .copied()
838 .collect::<Vec<_>>(),
839 ) {
840 Ok(stack_outputs) => ControlFlow::Continue(stack_outputs),
841 Err(_) => ControlFlow::Break(BreakReason::Err(ExecutionError::OutputStackOverflow(
842 self.stack_top_idx - self.stack_bot_idx - MIN_STACK_DEPTH,
843 ))),
844 }
845 }
846
847 async fn execute_impl_async<S, T>(
848 &mut self,
849 continuation_stack: &mut ContinuationStack<Arc<MastForest>>,
850 current_forest: &mut Arc<MastForest>,
851 kernel: &Kernel,
852 host: &mut impl Host,
853 tracer: &mut T,
854 stopper: &S,
855 package_debug_info: &mut Option<Arc<PackageDebugInfo>>,
856 ) -> ControlFlow<BreakReason<Arc<MastForest>>, StackOutputs>
857 where
858 S: Stopper<Processor = Self, Forest = Arc<MastForest>>,
859 T: Tracer<Processor = Self, Forest = Arc<MastForest>>,
860 {
861 while let ControlFlow::Break(internal_break_reason) = execute_impl(
862 self,
863 continuation_stack,
864 current_forest,
865 kernel,
866 host,
867 tracer,
868 stopper,
869 package_debug_info,
870 ) {
871 let current_package_debug_info = package_debug_info.as_deref();
872 let source_aware_execution =
873 current_package_debug_info.is_some() || continuation_stack.tracks_source_nodes();
874 match internal_break_reason {
875 InternalBreakReason::User(break_reason) => return ControlFlow::Break(break_reason),
876 InternalBreakReason::Emit { op_idx, continuation, source_node_id } => {
877 self.op_emit(host, op_idx, current_package_debug_info, source_node_id).await?;
878
879 finish_emit_op_execution(
880 continuation,
881 source_node_id,
882 self,
883 continuation_stack,
884 current_forest,
885 tracer,
886 stopper,
887 )?;
888 },
889 InternalBreakReason::LoadMastForestFromDyn { callee_hash, source_node_id } => {
890 let (root_id, new_forest, new_package_debug_info, new_source_node_id) =
891 match self
892 .load_mast_forest(
893 callee_hash,
894 host,
895 current_package_debug_info,
896 source_node_id,
897 source_aware_execution,
898 )
899 .await
900 {
901 Ok(result) => result,
902 Err(err) => return ControlFlow::Break(BreakReason::Err(err)),
903 };
904
905 finish_load_mast_forest_from_dyn_start(
906 root_id,
907 new_forest,
908 new_package_debug_info,
909 new_source_node_id,
910 self,
911 current_forest,
912 package_debug_info,
913 continuation_stack,
914 tracer,
915 stopper,
916 )?;
917 },
918 InternalBreakReason::LoadMastForestFromExternal {
919 external_node_id,
920 procedure_hash,
921 source_node_id,
922 } => {
923 let (root_id, new_forest, new_package_debug_info, new_source_node_id) =
924 match self
925 .load_mast_forest(
926 procedure_hash,
927 host,
928 current_package_debug_info,
929 source_node_id,
930 source_aware_execution,
931 )
932 .await
933 {
934 Ok(result) => result,
935 Err(err) => {
936 let maybe_enriched_err = maybe_use_caller_error_context(
937 err,
938 continuation_stack,
939 current_package_debug_info,
940 host,
941 );
942 return ControlFlow::Break(BreakReason::Err(maybe_enriched_err));
943 },
944 };
945
946 finish_load_mast_forest_from_external(
947 root_id,
948 new_forest,
949 new_package_debug_info,
950 new_source_node_id,
951 external_node_id,
952 current_forest,
953 package_debug_info,
954 continuation_stack,
955 tracer,
956 )?;
957 },
958 }
959 }
960
961 match StackOutputs::new(
962 &self.stack[self.stack_bot_idx..self.stack_top_idx]
963 .iter()
964 .rev()
965 .copied()
966 .collect::<Vec<_>>(),
967 ) {
968 Ok(stack_outputs) => ControlFlow::Continue(stack_outputs),
969 Err(_) => ControlFlow::Break(BreakReason::Err(ExecutionError::OutputStackOverflow(
970 self.stack_top_idx - self.stack_bot_idx - MIN_STACK_DEPTH,
971 ))),
972 }
973 }
974
975 fn load_mast_forest_sync(
979 &mut self,
980 node_digest: Word,
981 host: &mut impl SyncHost,
982 package_debug_info: Option<&PackageDebugInfo>,
983 source_node_id: Option<DebugSourceNodeId>,
984 source_aware_execution: bool,
985 ) -> Result<
986 (
987 MastNodeId,
988 Arc<MastForest>,
989 Option<Arc<PackageDebugInfo>>,
990 Option<DebugSourceNodeId>,
991 ),
992 ExecutionError,
993 > {
994 let loaded_mast_forest = host.get_mast_forest(&node_digest).ok_or_else(|| {
995 match (package_debug_info, source_node_id) {
996 (Some(debug_info), Some(source_node_id)) => {
997 crate::errors::procedure_not_found_with_package_source_context(
998 node_digest,
999 PackageSourceDebugContext::new(debug_info, source_node_id),
1000 host,
1001 )
1002 },
1003 _ => crate::errors::procedure_not_found_with_context(node_digest),
1004 }
1005 })?;
1006 let mast_forest = loaded_mast_forest.mast_forest().clone();
1007
1008 let root_id = mast_forest.find_procedure_root(node_digest).ok_or_else(|| {
1009 let context = match (package_debug_info, source_node_id) {
1010 (Some(debug_info), Some(source_node_id)) => {
1011 Some(PackageSourceDebugContext::new(debug_info, source_node_id))
1012 },
1013 _ => None,
1014 };
1015 malformed_mast_forest_with_context(node_digest, context, host)
1016 })?;
1017
1018 self.advice.extend_map(mast_forest.advice_map()).map_exec_err()?;
1019 let (loaded_package_debug_info, loaded_source_node_id) =
1020 Self::loaded_package_source_context(
1021 &loaded_mast_forest,
1022 root_id,
1023 source_aware_execution,
1024 )?;
1025
1026 Ok((root_id, mast_forest, loaded_package_debug_info, loaded_source_node_id))
1027 }
1028
1029 async fn load_mast_forest(
1030 &mut self,
1031 node_digest: Word,
1032 host: &mut impl Host,
1033 package_debug_info: Option<&PackageDebugInfo>,
1034 source_node_id: Option<DebugSourceNodeId>,
1035 source_aware_execution: bool,
1036 ) -> Result<
1037 (
1038 MastNodeId,
1039 Arc<MastForest>,
1040 Option<Arc<PackageDebugInfo>>,
1041 Option<DebugSourceNodeId>,
1042 ),
1043 ExecutionError,
1044 > {
1045 let loaded_mast_forest = if let Some(mast_forest) = host.get_mast_forest(&node_digest).await
1046 {
1047 mast_forest
1048 } else {
1049 return Err(match (package_debug_info, source_node_id) {
1050 (Some(debug_info), Some(source_node_id)) => {
1051 crate::errors::procedure_not_found_with_package_source_context(
1052 node_digest,
1053 PackageSourceDebugContext::new(debug_info, source_node_id),
1054 host,
1055 )
1056 },
1057 _ => crate::errors::procedure_not_found_with_context(node_digest),
1058 });
1059 };
1060 let mast_forest = loaded_mast_forest.mast_forest().clone();
1061
1062 let root_id = mast_forest.find_procedure_root(node_digest).ok_or_else(|| {
1063 let context = match (package_debug_info, source_node_id) {
1064 (Some(debug_info), Some(source_node_id)) => {
1065 Some(PackageSourceDebugContext::new(debug_info, source_node_id))
1066 },
1067 _ => None,
1068 };
1069 malformed_mast_forest_with_context(node_digest, context, host)
1070 })?;
1071
1072 self.advice.extend_map(mast_forest.advice_map()).map_exec_err()?;
1073 let (loaded_package_debug_info, loaded_source_node_id) =
1074 Self::loaded_package_source_context(
1075 &loaded_mast_forest,
1076 root_id,
1077 source_aware_execution,
1078 )?;
1079
1080 Ok((root_id, mast_forest, loaded_package_debug_info, loaded_source_node_id))
1081 }
1082
1083 fn loaded_package_source_context(
1084 loaded_mast_forest: &LoadedMastForest,
1085 root_id: MastNodeId,
1086 source_aware_execution: bool,
1087 ) -> Result<(Option<Arc<PackageDebugInfo>>, Option<DebugSourceNodeId>), ExecutionError> {
1088 if !source_aware_execution {
1089 return Ok((None, None));
1090 }
1091
1092 let Some(package_debug_info) = loaded_mast_forest
1093 .package_debug_info()
1094 .map_err(|_| ExecutionError::Internal("loaded package debug info is malformed"))?
1095 else {
1096 return Ok((None, None));
1097 };
1098
1099 let source_node_id = match package_debug_info.unique_source_root_for_exec_node(root_id) {
1100 Ok(source_node_id) => source_node_id,
1101 Err(DebugSourceGraphLookupError::AmbiguousRoot { .. }) => None,
1102 Err(_) => {
1103 return Err(ExecutionError::Internal(
1104 "loaded package debug source graph has malformed entrypoint roots",
1105 ));
1106 },
1107 };
1108
1109 Ok((Some(package_debug_info), source_node_id))
1110 }
1111
1112 pub fn execute_by_step_sync(
1114 mut self,
1115 program: &Program,
1116 host: &mut impl SyncHost,
1117 ) -> Result<StackOutputs, ExecutionError> {
1118 let mut current_resume_ctx = self.get_initial_resume_context(program)?;
1119
1120 loop {
1121 match self.step_sync(host, current_resume_ctx)? {
1122 Some(next_resume_ctx) => {
1123 current_resume_ctx = next_resume_ctx;
1124 },
1125 None => break Ok(self.current_stack_outputs()),
1126 }
1127 }
1128 }
1129
1130 #[cfg(any(test, feature = "testing"))]
1133 pub fn execute_by_step_with_package_debug_info_sync(
1134 mut self,
1135 program: &Program,
1136 package_debug_info: &PackageDebugInfo,
1137 host: &mut impl SyncHost,
1138 ) -> Result<StackOutputs, ExecutionError> {
1139 let mut current_resume_ctx =
1140 self.source_aware_resume_context(program, package_debug_info, None)?;
1141
1142 loop {
1143 match self.step_with_package_debug_info_sync(
1144 host,
1145 current_resume_ctx,
1146 package_debug_info,
1147 )? {
1148 Some(next_resume_ctx) => {
1149 current_resume_ctx = next_resume_ctx;
1150 },
1151 None => break Ok(self.current_stack_outputs()),
1152 }
1153 }
1154 }
1155
1156 #[cfg(any(test, feature = "testing"))]
1159 pub fn execute_by_step_with_package_debug_info_at_source_node_sync(
1160 mut self,
1161 program: &Program,
1162 package_debug_info: &PackageDebugInfo,
1163 entrypoint_source_node_id: DebugSourceNodeId,
1164 host: &mut impl SyncHost,
1165 ) -> Result<StackOutputs, ExecutionError> {
1166 let mut current_resume_ctx = self.source_aware_resume_context(
1167 program,
1168 package_debug_info,
1169 Some(entrypoint_source_node_id),
1170 )?;
1171
1172 loop {
1173 match self.step_with_package_debug_info_sync(
1174 host,
1175 current_resume_ctx,
1176 package_debug_info,
1177 )? {
1178 Some(next_resume_ctx) => {
1179 current_resume_ctx = next_resume_ctx;
1180 },
1181 None => break Ok(self.current_stack_outputs()),
1182 }
1183 }
1184 }
1185
1186 #[inline(always)]
1188 pub async fn execute_by_step(
1189 mut self,
1190 program: &Program,
1191 host: &mut impl Host,
1192 ) -> Result<StackOutputs, ExecutionError> {
1193 let mut current_resume_ctx = self.get_initial_resume_context(program)?;
1194 let mut processor = self;
1195
1196 loop {
1197 match processor.step(host, current_resume_ctx).await? {
1198 Some(next_resume_ctx) => {
1199 current_resume_ctx = next_resume_ctx;
1200 },
1201 None => break Ok(processor.current_stack_outputs()),
1202 }
1203 }
1204 }
1205
1206 #[cfg(any(test, feature = "testing"))]
1208 #[inline(always)]
1209 pub async fn execute_by_step_with_package_debug_info(
1210 mut self,
1211 program: &Program,
1212 package_debug_info: &PackageDebugInfo,
1213 host: &mut impl Host,
1214 ) -> Result<StackOutputs, ExecutionError> {
1215 let mut current_resume_ctx =
1216 self.source_aware_resume_context(program, package_debug_info, None)?;
1217 let mut processor = self;
1218
1219 loop {
1220 match processor
1221 .step_with_package_debug_info(host, current_resume_ctx, package_debug_info)
1222 .await?
1223 {
1224 Some(next_resume_ctx) => {
1225 current_resume_ctx = next_resume_ctx;
1226 },
1227 None => break Ok(processor.current_stack_outputs()),
1228 }
1229 }
1230 }
1231
1232 #[cfg(any(test, feature = "testing"))]
1235 #[inline(always)]
1236 pub async fn execute_by_step_with_package_debug_info_at_source_node(
1237 mut self,
1238 program: &Program,
1239 package_debug_info: &PackageDebugInfo,
1240 entrypoint_source_node_id: DebugSourceNodeId,
1241 host: &mut impl Host,
1242 ) -> Result<StackOutputs, ExecutionError> {
1243 let mut current_resume_ctx = self.source_aware_resume_context(
1244 program,
1245 package_debug_info,
1246 Some(entrypoint_source_node_id),
1247 )?;
1248 let mut processor = self;
1249
1250 loop {
1251 match processor
1252 .step_with_package_debug_info(host, current_resume_ctx, package_debug_info)
1253 .await?
1254 {
1255 Some(next_resume_ctx) => {
1256 current_resume_ctx = next_resume_ctx;
1257 },
1258 None => break Ok(processor.current_stack_outputs()),
1259 }
1260 }
1261 }
1262
1263 #[cfg(any(test, feature = "testing"))]
1267 pub fn execute_mut_sync(
1268 &mut self,
1269 program: &Program,
1270 host: &mut impl SyncHost,
1271 ) -> Result<StackOutputs, ExecutionError> {
1272 let mut continuation_stack = ContinuationStack::new(program);
1273 let mut current_forest = program.mast_forest().clone();
1274 let mut package_debug_info = None;
1275
1276 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
1277
1278 let flow = self.execute_impl(
1279 &mut continuation_stack,
1280 &mut current_forest,
1281 program.kernel(),
1282 host,
1283 &mut NoopTracer,
1284 &NeverStopper,
1285 &mut package_debug_info,
1286 );
1287 Self::stack_result_from_flow(flow)
1288 }
1289
1290 #[cfg(any(test, feature = "testing"))]
1292 #[inline(always)]
1293 pub async fn execute_mut(
1294 &mut self,
1295 program: &Program,
1296 host: &mut impl Host,
1297 ) -> Result<StackOutputs, ExecutionError> {
1298 let mut continuation_stack = ContinuationStack::new(program);
1299 let mut current_forest = program.mast_forest().clone();
1300 let mut package_debug_info = None;
1301
1302 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
1303
1304 let flow = self
1305 .execute_impl_async(
1306 &mut continuation_stack,
1307 &mut current_forest,
1308 program.kernel(),
1309 host,
1310 &mut NoopTracer,
1311 &NeverStopper,
1312 &mut package_debug_info,
1313 )
1314 .await;
1315 Self::stack_result_from_flow(flow)
1316 }
1317}