1use alloc::{sync::Arc, vec::Vec};
2use core::ops::ControlFlow;
3
4use miden_core::{
5 Word,
6 mast::{MastForest, MastNodeId},
7 program::{KernelDescriptor, 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 #[cfg(feature = "std")]
147 #[instrument(name = "execute_and_build_trace_sync", skip_all)]
148 pub fn execute_and_build_trace_sync(
149 self,
150 program: &Program,
151 host: &mut impl SyncHost,
152 ) -> Result<crate::trace::ExecutionTrace, ExecutionError> {
153 use crate::trace::{MAX_TRACE_LEN, build_hasher_chiplet, build_trace_with_prebuilt_hasher};
154
155 let (sender, receiver) = std::sync::mpsc::channel();
156 let mut tracer = ExecutionTracer::new_with_streamed_hasher(
157 self.options.core_trace_fragment_size(),
158 self.options.max_stack_depth(),
159 sender,
160 );
161
162 std::thread::scope(|scope| {
163 let span = tracing::Span::current();
167 let hasher = scope.spawn(move || {
168 let _span = span.entered();
169 build_hasher_chiplet(receiver.into_iter().map(Ok), MAX_TRACE_LEN)
170 });
171
172 let execution_output = self.execute_with_tracer_sync(program, host, &mut tracer);
176
177 let mut inputs = match execution_output {
178 Ok(output) => Self::trace_build_inputs_from_parts(program, output, tracer),
179 Err(err) => {
180 drop(tracer);
185 match hasher.join() {
186 Ok(Err(builder_err)) => {
187 tracing::debug!(%builder_err, "hasher builder also failed");
188 },
189 Ok(Ok(_)) => (),
190 Err(panic) => std::panic::resume_unwind(panic),
191 }
192 return Err(err);
193 },
194 };
195 drop(inputs.take_hasher_replay());
197 let hasher = match hasher.join() {
198 Ok(result) => result?,
199 Err(panic) => std::panic::resume_unwind(panic),
200 };
201
202 build_trace_with_prebuilt_hasher(inputs, hasher)
203 })
204 }
205
206 #[instrument(name = "execute_trace_inputs_sync", skip_all)]
228 pub fn execute_trace_inputs_sync(
229 self,
230 program: &Program,
231 host: &mut impl SyncHost,
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_sync(program, host, &mut tracer)?;
238 Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer))
239 }
240
241 #[instrument(name = "execute_trace_inputs_with_package_debug_info_sync", skip_all)]
244 pub fn execute_trace_inputs_with_package_debug_info_sync(
245 self,
246 program: &Program,
247 package_debug_info: &PackageDebugInfo,
248 host: &mut impl SyncHost,
249 ) -> Result<TraceBuildInputs, ExecutionError> {
250 let mut tracer = ExecutionTracer::new(
251 self.options.core_trace_fragment_size(),
252 self.options.max_stack_depth(),
253 );
254 let execution_output = self.execute_with_package_debug_info_and_tracer_sync(
255 program,
256 package_debug_info,
257 None,
258 host,
259 &mut tracer,
260 )?;
261 Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer))
262 }
263
264 #[instrument(
268 name = "execute_trace_inputs_with_package_debug_info_at_source_node_sync",
269 skip_all
270 )]
271 pub fn execute_trace_inputs_with_package_debug_info_at_source_node_sync(
272 self,
273 program: &Program,
274 package_debug_info: &PackageDebugInfo,
275 entrypoint_source_node_id: DebugSourceNodeId,
276 host: &mut impl SyncHost,
277 ) -> Result<TraceBuildInputs, ExecutionError> {
278 let mut tracer = ExecutionTracer::new(
279 self.options.core_trace_fragment_size(),
280 self.options.max_stack_depth(),
281 );
282 let execution_output = self.execute_with_package_debug_info_and_tracer_sync(
283 program,
284 package_debug_info,
285 Some(entrypoint_source_node_id),
286 host,
287 &mut tracer,
288 )?;
289 Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer))
290 }
291
292 #[inline(always)]
294 #[instrument(name = "execute_trace_inputs", skip_all)]
295 pub async fn execute_trace_inputs(
296 self,
297 program: &Program,
298 host: &mut impl Host,
299 ) -> Result<TraceBuildInputs, ExecutionError> {
300 let mut tracer = ExecutionTracer::new(
301 self.options.core_trace_fragment_size(),
302 self.options.max_stack_depth(),
303 );
304 let execution_output = self.execute_with_tracer(program, host, &mut tracer).await?;
305 Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer))
306 }
307
308 #[cfg(any(test, feature = "testing"))]
310 #[inline(always)]
311 #[instrument(name = "execute_trace_inputs_with_package_debug_info", skip_all)]
312 pub async fn execute_trace_inputs_with_package_debug_info(
313 self,
314 program: &Program,
315 package_debug_info: &PackageDebugInfo,
316 host: &mut impl Host,
317 ) -> Result<TraceBuildInputs, ExecutionError> {
318 let mut tracer = ExecutionTracer::new(
319 self.options.core_trace_fragment_size(),
320 self.options.max_stack_depth(),
321 );
322 let execution_output = self
323 .execute_with_package_debug_info_and_tracer(
324 program,
325 package_debug_info,
326 None,
327 host,
328 &mut tracer,
329 )
330 .await?;
331 Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer))
332 }
333
334 #[cfg(any(test, feature = "testing"))]
337 #[inline(always)]
338 #[instrument(name = "execute_trace_inputs_with_package_debug_info_at_source_node", skip_all)]
339 pub async fn execute_trace_inputs_with_package_debug_info_at_source_node(
340 self,
341 program: &Program,
342 package_debug_info: &PackageDebugInfo,
343 entrypoint_source_node_id: DebugSourceNodeId,
344 host: &mut impl Host,
345 ) -> Result<TraceBuildInputs, ExecutionError> {
346 let mut tracer = ExecutionTracer::new(
347 self.options.core_trace_fragment_size(),
348 self.options.max_stack_depth(),
349 );
350 let execution_output = self
351 .execute_with_package_debug_info_and_tracer(
352 program,
353 package_debug_info,
354 Some(entrypoint_source_node_id),
355 host,
356 &mut tracer,
357 )
358 .await?;
359 Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer))
360 }
361
362 pub async fn execute_with_tracer<T>(
364 mut self,
365 program: &Program,
366 host: &mut impl Host,
367 tracer: &mut T,
368 ) -> Result<ExecutionOutput, ExecutionError>
369 where
370 T: Tracer<Processor = Self, Forest = Arc<MastForest>>,
371 {
372 let mut continuation_stack = ContinuationStack::new(program);
373 let mut current_forest = program.mast_forest().clone();
374 let mut package_debug_info = None;
375
376 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
377 let flow = self
378 .execute_impl_async(
379 &mut continuation_stack,
380 &mut current_forest,
381 program.kernel(),
382 host,
383 tracer,
384 &NeverStopper,
385 &mut package_debug_info,
386 )
387 .await;
388 Self::execution_result_from_flow(flow, self)
389 }
390
391 async fn execute_with_package_debug_info_and_tracer<T>(
394 mut self,
395 program: &Program,
396 package_debug_info: &PackageDebugInfo,
397 entrypoint_source_node_id: Option<DebugSourceNodeId>,
398 host: &mut impl Host,
399 tracer: &mut T,
400 ) -> Result<ExecutionOutput, ExecutionError>
401 where
402 T: Tracer<Processor = Self, Forest = Arc<MastForest>>,
403 {
404 let mut continuation_stack = Self::source_aware_continuation_stack(
405 program,
406 package_debug_info,
407 entrypoint_source_node_id,
408 )?;
409 let mut current_forest = program.mast_forest().clone();
410 let mut package_debug_info = Some(Arc::new(package_debug_info.clone()));
411
412 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
413 let flow = self
414 .execute_impl_async(
415 &mut continuation_stack,
416 &mut current_forest,
417 program.kernel(),
418 host,
419 tracer,
420 &NeverStopper,
421 &mut package_debug_info,
422 )
423 .await;
424 Self::execution_result_from_flow(flow, self)
425 }
426
427 pub fn execute_with_tracer_sync<T>(
429 mut self,
430 program: &Program,
431 host: &mut impl SyncHost,
432 tracer: &mut T,
433 ) -> Result<ExecutionOutput, ExecutionError>
434 where
435 T: Tracer<Processor = Self, Forest = Arc<MastForest>>,
436 {
437 let mut continuation_stack = ContinuationStack::new(program);
438 let mut current_forest = program.mast_forest().clone();
439 let mut package_debug_info = None;
440
441 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
442 let flow = self.execute_impl(
443 &mut continuation_stack,
444 &mut current_forest,
445 program.kernel(),
446 host,
447 tracer,
448 &NeverStopper,
449 &mut package_debug_info,
450 );
451 Self::execution_result_from_flow(flow, self)
452 }
453
454 fn execute_with_package_debug_info_and_tracer_sync<T>(
457 mut self,
458 program: &Program,
459 package_debug_info: &PackageDebugInfo,
460 entrypoint_source_node_id: Option<DebugSourceNodeId>,
461 host: &mut impl SyncHost,
462 tracer: &mut T,
463 ) -> Result<ExecutionOutput, ExecutionError>
464 where
465 T: Tracer<Processor = Self, Forest = Arc<MastForest>>,
466 {
467 let mut continuation_stack = Self::source_aware_continuation_stack(
468 program,
469 package_debug_info,
470 entrypoint_source_node_id,
471 )?;
472 let mut current_forest = program.mast_forest().clone();
473 let mut package_debug_info = Some(Arc::new(package_debug_info.clone()));
474
475 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
476 let flow = self.execute_impl(
477 &mut continuation_stack,
478 &mut current_forest,
479 program.kernel(),
480 host,
481 tracer,
482 &NeverStopper,
483 &mut package_debug_info,
484 );
485 Self::execution_result_from_flow(flow, self)
486 }
487
488 pub fn step_sync(
490 &mut self,
491 host: &mut impl SyncHost,
492 resume_ctx: ResumeContext,
493 ) -> Result<Option<ResumeContext>, ExecutionError> {
494 let ResumeContext {
495 mut current_forest,
496 mut continuation_stack,
497 kernel,
498 mut package_debug_info,
499 } = resume_ctx;
500
501 let flow = self.execute_impl(
502 &mut continuation_stack,
503 &mut current_forest,
504 &kernel,
505 host,
506 &mut NoopTracer,
507 &StepStopper,
508 &mut package_debug_info,
509 );
510 Self::resume_context_from_flow(
511 flow,
512 continuation_stack,
513 current_forest,
514 kernel,
515 package_debug_info,
516 )
517 }
518
519 pub fn step_with_package_debug_info_sync(
521 &mut self,
522 host: &mut impl SyncHost,
523 resume_ctx: ResumeContext,
524 package_debug_info: &PackageDebugInfo,
525 ) -> Result<Option<ResumeContext>, ExecutionError> {
526 let ResumeContext {
527 mut current_forest,
528 mut continuation_stack,
529 kernel,
530 package_debug_info: mut active_package_debug_info,
531 } = resume_ctx;
532 Self::ensure_source_aware_step_context(
533 &mut continuation_stack,
534 &mut active_package_debug_info,
535 package_debug_info,
536 )?;
537
538 let flow = self.execute_impl(
539 &mut continuation_stack,
540 &mut current_forest,
541 &kernel,
542 host,
543 &mut NoopTracer,
544 &StepStopper,
545 &mut active_package_debug_info,
546 );
547 Self::resume_context_from_flow(
548 flow,
549 continuation_stack,
550 current_forest,
551 kernel,
552 active_package_debug_info,
553 )
554 }
555
556 #[inline(always)]
558 pub async fn step(
559 &mut self,
560 host: &mut impl Host,
561 resume_ctx: ResumeContext,
562 ) -> Result<Option<ResumeContext>, ExecutionError> {
563 let ResumeContext {
564 mut current_forest,
565 mut continuation_stack,
566 kernel,
567 mut package_debug_info,
568 } = resume_ctx;
569
570 let flow = self
571 .execute_impl_async(
572 &mut continuation_stack,
573 &mut current_forest,
574 &kernel,
575 host,
576 &mut NoopTracer,
577 &StepStopper,
578 &mut package_debug_info,
579 )
580 .await;
581 Self::resume_context_from_flow(
582 flow,
583 continuation_stack,
584 current_forest,
585 kernel,
586 package_debug_info,
587 )
588 }
589
590 #[inline(always)]
592 pub async fn step_with_package_debug_info(
593 &mut self,
594 host: &mut impl Host,
595 resume_ctx: ResumeContext,
596 package_debug_info: &PackageDebugInfo,
597 ) -> Result<Option<ResumeContext>, ExecutionError> {
598 let ResumeContext {
599 mut current_forest,
600 mut continuation_stack,
601 kernel,
602 package_debug_info: mut active_package_debug_info,
603 } = resume_ctx;
604 Self::ensure_source_aware_step_context(
605 &mut continuation_stack,
606 &mut active_package_debug_info,
607 package_debug_info,
608 )?;
609
610 let flow = self
611 .execute_impl_async(
612 &mut continuation_stack,
613 &mut current_forest,
614 &kernel,
615 host,
616 &mut NoopTracer,
617 &StepStopper,
618 &mut active_package_debug_info,
619 )
620 .await;
621 Self::resume_context_from_flow(
622 flow,
623 continuation_stack,
624 current_forest,
625 kernel,
626 active_package_debug_info,
627 )
628 }
629
630 #[inline(always)]
632 fn trace_build_inputs_from_parts(
633 program: &Program,
634 execution_output: ExecutionOutput,
635 tracer: ExecutionTracer,
636 ) -> TraceBuildInputs {
637 TraceBuildInputs::from_execution(
638 program,
639 execution_output,
640 tracer.into_trace_generation_context(),
641 )
642 }
643
644 pub(super) fn source_aware_continuation_stack(
645 program: &Program,
646 package_debug_info: &PackageDebugInfo,
647 entrypoint_source_node_id: Option<DebugSourceNodeId>,
648 ) -> Result<ContinuationStack<Arc<MastForest>>, ExecutionError> {
649 if let Some(source_node_id) = entrypoint_source_node_id {
650 let Some(source_node) = package_debug_info.source_node(source_node_id) else {
651 return Err(ExecutionError::Internal(
652 "package debug source graph is missing the entrypoint source node",
653 ));
654 };
655 if source_node.exec_node != program.entrypoint() {
656 return Err(ExecutionError::Internal(
657 "package debug entrypoint source node does not match the program entrypoint",
658 ));
659 }
660
661 return Ok(ContinuationStack::new_with_source_node_id(program, source_node_id));
662 }
663
664 let Some(source_node_id) = package_debug_info
665 .unique_source_root_for_exec_node(program.entrypoint())
666 .map_err(|_| {
667 ExecutionError::Internal(
668 "package debug source graph has ambiguous or malformed entrypoint roots",
669 )
670 })?
671 else {
672 return Ok(ContinuationStack::new_with_optional_source_node_id(program, None));
673 };
674
675 Ok(ContinuationStack::new_with_source_node_id(program, source_node_id))
676 }
677
678 #[cfg(any(test, feature = "testing"))]
679 fn source_aware_resume_context(
680 &mut self,
681 program: &Program,
682 package_debug_info: &PackageDebugInfo,
683 entrypoint_source_node_id: Option<DebugSourceNodeId>,
684 ) -> Result<ResumeContext, ExecutionError> {
685 self.advice
686 .extend_map(program.mast_forest().advice_map())
687 .map_exec_err_no_ctx()?;
688
689 Ok(ResumeContext {
690 current_forest: program.mast_forest().clone(),
691 continuation_stack: Self::source_aware_continuation_stack(
692 program,
693 package_debug_info,
694 entrypoint_source_node_id,
695 )?,
696 kernel: program.kernel().clone(),
697 package_debug_info: Some(Arc::new(package_debug_info.clone())),
698 })
699 }
700
701 fn ensure_source_aware_step_context(
702 continuation_stack: &mut ContinuationStack<Arc<MastForest>>,
703 package_debug_info: &mut Option<Arc<PackageDebugInfo>>,
704 supplied_package_debug_info: &PackageDebugInfo,
705 ) -> Result<(), ExecutionError> {
706 if package_debug_info.is_none() {
707 *package_debug_info = Some(Arc::new(supplied_package_debug_info.clone()));
708 }
709
710 if !continuation_stack.tracks_source_nodes() {
711 let source_node_id = Self::source_root_for_next_continuation(
712 continuation_stack,
713 package_debug_info.as_deref().expect("package debug info was just initialized"),
714 )?;
715 continuation_stack.start_tracking_source_nodes(source_node_id);
716 }
717
718 Ok(())
719 }
720
721 fn source_root_for_next_continuation(
722 continuation_stack: &ContinuationStack<Arc<MastForest>>,
723 package_debug_info: &PackageDebugInfo,
724 ) -> Result<Option<DebugSourceNodeId>, ExecutionError> {
725 let Some((continuation, _)) = continuation_stack.peek_continuation_with_source_node_id()
726 else {
727 return Ok(None);
728 };
729
730 let Some(exec_node) = continuation.exec_node() else {
731 return Ok(None);
732 };
733
734 package_debug_info.unique_source_root_for_exec_node(exec_node).map_err(|_| {
735 ExecutionError::Internal(
736 "package debug source graph has ambiguous or malformed continuation roots",
737 )
738 })
739 }
740
741 #[inline(always)]
743 fn resume_context_from_flow(
744 flow: ControlFlow<BreakReason<Arc<MastForest>>, StackOutputs>,
745 mut continuation_stack: ContinuationStack<Arc<MastForest>>,
746 current_forest: Arc<MastForest>,
747 kernel: KernelDescriptor,
748 package_debug_info: Option<Arc<PackageDebugInfo>>,
749 ) -> Result<Option<ResumeContext>, ExecutionError> {
750 match flow {
751 ControlFlow::Continue(_) => Ok(None),
752 ControlFlow::Break(break_reason) => match break_reason {
753 BreakReason::Err(err) => Err(err),
754 BreakReason::Stopped(maybe_continuation) => {
755 if let Some((continuation, source_node_id)) = maybe_continuation {
756 continuation_stack.push_with_source_node_id(continuation, source_node_id);
757 }
758
759 Ok(Some(ResumeContext {
760 current_forest,
761 continuation_stack,
762 kernel,
763 package_debug_info,
764 }))
765 },
766 },
767 }
768 }
769
770 #[inline(always)]
772 fn current_stack_outputs(&self) -> StackOutputs {
773 StackOutputs::new(
774 &self.stack[self.stack_bot_idx..self.stack_top_idx]
775 .iter()
776 .rev()
777 .copied()
778 .collect::<Vec<_>>(),
779 )
780 .unwrap()
781 }
782
783 fn execute_impl<S, T>(
789 &mut self,
790 continuation_stack: &mut ContinuationStack<Arc<MastForest>>,
791 current_forest: &mut Arc<MastForest>,
792 kernel: &KernelDescriptor,
793 host: &mut impl SyncHost,
794 tracer: &mut T,
795 stopper: &S,
796 package_debug_info: &mut Option<Arc<PackageDebugInfo>>,
797 ) -> ControlFlow<BreakReason<Arc<MastForest>>, StackOutputs>
798 where
799 S: Stopper<Processor = Self, Forest = Arc<MastForest>>,
800 T: Tracer<Processor = Self, Forest = Arc<MastForest>>,
801 {
802 while let ControlFlow::Break(internal_break_reason) = execute_impl(
803 self,
804 continuation_stack,
805 current_forest,
806 kernel,
807 host,
808 tracer,
809 stopper,
810 package_debug_info,
811 ) {
812 let current_package_debug_info = package_debug_info.as_deref();
813 let source_aware_execution =
814 current_package_debug_info.is_some() || continuation_stack.tracks_source_nodes();
815 match internal_break_reason {
816 InternalBreakReason::User(break_reason) => return ControlFlow::Break(break_reason),
817 InternalBreakReason::Emit { op_idx, continuation, source_node_id } => {
818 self.op_emit_sync(host, op_idx, current_package_debug_info, source_node_id)?;
819
820 finish_emit_op_execution(
821 continuation,
822 source_node_id,
823 self,
824 continuation_stack,
825 current_forest,
826 tracer,
827 stopper,
828 )?;
829 },
830 InternalBreakReason::LoadMastForestFromDyn { callee_hash, source_node_id } => {
831 let (root_id, new_forest, new_package_debug_info, new_source_node_id) =
832 match self.load_mast_forest_sync(
833 callee_hash,
834 host,
835 current_package_debug_info,
836 source_node_id,
837 source_aware_execution,
838 ) {
839 Ok(result) => result,
840 Err(err) => return ControlFlow::Break(BreakReason::Err(err)),
841 };
842
843 finish_load_mast_forest_from_dyn_start(
844 root_id,
845 new_forest,
846 new_package_debug_info,
847 new_source_node_id,
848 self,
849 current_forest,
850 package_debug_info,
851 continuation_stack,
852 tracer,
853 stopper,
854 )?;
855 },
856 InternalBreakReason::LoadMastForestFromExternal {
857 external_node_id,
858 procedure_hash,
859 source_node_id,
860 } => {
861 let (root_id, new_forest, new_package_debug_info, new_source_node_id) =
862 match self.load_mast_forest_sync(
863 procedure_hash,
864 host,
865 current_package_debug_info,
866 source_node_id,
867 source_aware_execution,
868 ) {
869 Ok(result) => result,
870 Err(err) => {
871 let maybe_enriched_err = maybe_use_caller_error_context(
872 err,
873 continuation_stack,
874 current_package_debug_info,
875 host,
876 );
877 return ControlFlow::Break(BreakReason::Err(maybe_enriched_err));
878 },
879 };
880
881 finish_load_mast_forest_from_external(
882 root_id,
883 new_forest,
884 new_package_debug_info,
885 new_source_node_id,
886 external_node_id,
887 current_forest,
888 package_debug_info,
889 continuation_stack,
890 tracer,
891 )?;
892 },
893 }
894 }
895
896 match StackOutputs::new(
897 &self.stack[self.stack_bot_idx..self.stack_top_idx]
898 .iter()
899 .rev()
900 .copied()
901 .collect::<Vec<_>>(),
902 ) {
903 Ok(stack_outputs) => ControlFlow::Continue(stack_outputs),
904 Err(_) => ControlFlow::Break(BreakReason::Err(ExecutionError::OutputStackOverflow(
905 self.stack_top_idx - self.stack_bot_idx - MIN_STACK_DEPTH,
906 ))),
907 }
908 }
909
910 async fn execute_impl_async<S, T>(
911 &mut self,
912 continuation_stack: &mut ContinuationStack<Arc<MastForest>>,
913 current_forest: &mut Arc<MastForest>,
914 kernel: &KernelDescriptor,
915 host: &mut impl Host,
916 tracer: &mut T,
917 stopper: &S,
918 package_debug_info: &mut Option<Arc<PackageDebugInfo>>,
919 ) -> ControlFlow<BreakReason<Arc<MastForest>>, StackOutputs>
920 where
921 S: Stopper<Processor = Self, Forest = Arc<MastForest>>,
922 T: Tracer<Processor = Self, Forest = Arc<MastForest>>,
923 {
924 while let ControlFlow::Break(internal_break_reason) = execute_impl(
925 self,
926 continuation_stack,
927 current_forest,
928 kernel,
929 host,
930 tracer,
931 stopper,
932 package_debug_info,
933 ) {
934 let current_package_debug_info = package_debug_info.as_deref();
935 let source_aware_execution =
936 current_package_debug_info.is_some() || continuation_stack.tracks_source_nodes();
937 match internal_break_reason {
938 InternalBreakReason::User(break_reason) => return ControlFlow::Break(break_reason),
939 InternalBreakReason::Emit { op_idx, continuation, source_node_id } => {
940 self.op_emit(host, op_idx, current_package_debug_info, source_node_id).await?;
941
942 finish_emit_op_execution(
943 continuation,
944 source_node_id,
945 self,
946 continuation_stack,
947 current_forest,
948 tracer,
949 stopper,
950 )?;
951 },
952 InternalBreakReason::LoadMastForestFromDyn { callee_hash, source_node_id } => {
953 let (root_id, new_forest, new_package_debug_info, new_source_node_id) =
954 match self
955 .load_mast_forest(
956 callee_hash,
957 host,
958 current_package_debug_info,
959 source_node_id,
960 source_aware_execution,
961 )
962 .await
963 {
964 Ok(result) => result,
965 Err(err) => return ControlFlow::Break(BreakReason::Err(err)),
966 };
967
968 finish_load_mast_forest_from_dyn_start(
969 root_id,
970 new_forest,
971 new_package_debug_info,
972 new_source_node_id,
973 self,
974 current_forest,
975 package_debug_info,
976 continuation_stack,
977 tracer,
978 stopper,
979 )?;
980 },
981 InternalBreakReason::LoadMastForestFromExternal {
982 external_node_id,
983 procedure_hash,
984 source_node_id,
985 } => {
986 let (root_id, new_forest, new_package_debug_info, new_source_node_id) =
987 match self
988 .load_mast_forest(
989 procedure_hash,
990 host,
991 current_package_debug_info,
992 source_node_id,
993 source_aware_execution,
994 )
995 .await
996 {
997 Ok(result) => result,
998 Err(err) => {
999 let maybe_enriched_err = maybe_use_caller_error_context(
1000 err,
1001 continuation_stack,
1002 current_package_debug_info,
1003 host,
1004 );
1005 return ControlFlow::Break(BreakReason::Err(maybe_enriched_err));
1006 },
1007 };
1008
1009 finish_load_mast_forest_from_external(
1010 root_id,
1011 new_forest,
1012 new_package_debug_info,
1013 new_source_node_id,
1014 external_node_id,
1015 current_forest,
1016 package_debug_info,
1017 continuation_stack,
1018 tracer,
1019 )?;
1020 },
1021 }
1022 }
1023
1024 match StackOutputs::new(
1025 &self.stack[self.stack_bot_idx..self.stack_top_idx]
1026 .iter()
1027 .rev()
1028 .copied()
1029 .collect::<Vec<_>>(),
1030 ) {
1031 Ok(stack_outputs) => ControlFlow::Continue(stack_outputs),
1032 Err(_) => ControlFlow::Break(BreakReason::Err(ExecutionError::OutputStackOverflow(
1033 self.stack_top_idx - self.stack_bot_idx - MIN_STACK_DEPTH,
1034 ))),
1035 }
1036 }
1037
1038 fn load_mast_forest_sync(
1042 &mut self,
1043 node_digest: Word,
1044 host: &mut impl SyncHost,
1045 package_debug_info: Option<&PackageDebugInfo>,
1046 source_node_id: Option<DebugSourceNodeId>,
1047 source_aware_execution: bool,
1048 ) -> Result<
1049 (
1050 MastNodeId,
1051 Arc<MastForest>,
1052 Option<Arc<PackageDebugInfo>>,
1053 Option<DebugSourceNodeId>,
1054 ),
1055 ExecutionError,
1056 > {
1057 let loaded_mast_forest = host.get_mast_forest(&node_digest).ok_or_else(|| {
1058 match (package_debug_info, source_node_id) {
1059 (Some(debug_info), Some(source_node_id)) => {
1060 crate::errors::procedure_not_found_with_package_source_context(
1061 node_digest,
1062 PackageSourceDebugContext::new(debug_info, source_node_id),
1063 host,
1064 )
1065 },
1066 _ => crate::errors::procedure_not_found_with_context(node_digest),
1067 }
1068 })?;
1069 let mast_forest = loaded_mast_forest.mast_forest().clone();
1070
1071 let root_id = mast_forest.find_procedure_root(node_digest).ok_or_else(|| {
1072 let context = match (package_debug_info, source_node_id) {
1073 (Some(debug_info), Some(source_node_id)) => {
1074 Some(PackageSourceDebugContext::new(debug_info, source_node_id))
1075 },
1076 _ => None,
1077 };
1078 malformed_mast_forest_with_context(node_digest, context, host)
1079 })?;
1080
1081 self.advice.extend_map(mast_forest.advice_map()).map_exec_err()?;
1082 let (loaded_package_debug_info, loaded_source_node_id) =
1083 Self::loaded_package_source_context(
1084 &loaded_mast_forest,
1085 root_id,
1086 source_aware_execution,
1087 )?;
1088
1089 Ok((root_id, mast_forest, loaded_package_debug_info, loaded_source_node_id))
1090 }
1091
1092 async fn load_mast_forest(
1093 &mut self,
1094 node_digest: Word,
1095 host: &mut impl Host,
1096 package_debug_info: Option<&PackageDebugInfo>,
1097 source_node_id: Option<DebugSourceNodeId>,
1098 source_aware_execution: bool,
1099 ) -> Result<
1100 (
1101 MastNodeId,
1102 Arc<MastForest>,
1103 Option<Arc<PackageDebugInfo>>,
1104 Option<DebugSourceNodeId>,
1105 ),
1106 ExecutionError,
1107 > {
1108 let loaded_mast_forest = if let Some(mast_forest) = host.get_mast_forest(&node_digest).await
1109 {
1110 mast_forest
1111 } else {
1112 return Err(match (package_debug_info, source_node_id) {
1113 (Some(debug_info), Some(source_node_id)) => {
1114 crate::errors::procedure_not_found_with_package_source_context(
1115 node_digest,
1116 PackageSourceDebugContext::new(debug_info, source_node_id),
1117 host,
1118 )
1119 },
1120 _ => crate::errors::procedure_not_found_with_context(node_digest),
1121 });
1122 };
1123 let mast_forest = loaded_mast_forest.mast_forest().clone();
1124
1125 let root_id = mast_forest.find_procedure_root(node_digest).ok_or_else(|| {
1126 let context = match (package_debug_info, source_node_id) {
1127 (Some(debug_info), Some(source_node_id)) => {
1128 Some(PackageSourceDebugContext::new(debug_info, source_node_id))
1129 },
1130 _ => None,
1131 };
1132 malformed_mast_forest_with_context(node_digest, context, host)
1133 })?;
1134
1135 self.advice.extend_map(mast_forest.advice_map()).map_exec_err()?;
1136 let (loaded_package_debug_info, loaded_source_node_id) =
1137 Self::loaded_package_source_context(
1138 &loaded_mast_forest,
1139 root_id,
1140 source_aware_execution,
1141 )?;
1142
1143 Ok((root_id, mast_forest, loaded_package_debug_info, loaded_source_node_id))
1144 }
1145
1146 fn loaded_package_source_context(
1147 loaded_mast_forest: &LoadedMastForest,
1148 root_id: MastNodeId,
1149 source_aware_execution: bool,
1150 ) -> Result<(Option<Arc<PackageDebugInfo>>, Option<DebugSourceNodeId>), ExecutionError> {
1151 if !source_aware_execution {
1152 return Ok((None, None));
1153 }
1154
1155 let Some(package_debug_info) = loaded_mast_forest
1156 .package_debug_info()
1157 .map_err(|_| ExecutionError::Internal("loaded package debug info is malformed"))?
1158 else {
1159 return Ok((None, None));
1160 };
1161
1162 let source_node_id = match package_debug_info.unique_source_root_for_exec_node(root_id) {
1163 Ok(source_node_id) => source_node_id,
1164 Err(DebugSourceGraphLookupError::AmbiguousRoot { .. }) => None,
1165 Err(_) => {
1166 return Err(ExecutionError::Internal(
1167 "loaded package debug source graph has malformed entrypoint roots",
1168 ));
1169 },
1170 };
1171
1172 Ok((Some(package_debug_info), source_node_id))
1173 }
1174
1175 pub fn execute_by_step_sync(
1177 mut self,
1178 program: &Program,
1179 host: &mut impl SyncHost,
1180 ) -> Result<StackOutputs, ExecutionError> {
1181 let mut current_resume_ctx = self.get_initial_resume_context(program)?;
1182
1183 loop {
1184 match self.step_sync(host, current_resume_ctx)? {
1185 Some(next_resume_ctx) => {
1186 current_resume_ctx = next_resume_ctx;
1187 },
1188 None => break Ok(self.current_stack_outputs()),
1189 }
1190 }
1191 }
1192
1193 #[cfg(any(test, feature = "testing"))]
1196 pub fn execute_by_step_with_package_debug_info_sync(
1197 mut self,
1198 program: &Program,
1199 package_debug_info: &PackageDebugInfo,
1200 host: &mut impl SyncHost,
1201 ) -> Result<StackOutputs, ExecutionError> {
1202 let mut current_resume_ctx =
1203 self.source_aware_resume_context(program, package_debug_info, None)?;
1204
1205 loop {
1206 match self.step_with_package_debug_info_sync(
1207 host,
1208 current_resume_ctx,
1209 package_debug_info,
1210 )? {
1211 Some(next_resume_ctx) => {
1212 current_resume_ctx = next_resume_ctx;
1213 },
1214 None => break Ok(self.current_stack_outputs()),
1215 }
1216 }
1217 }
1218
1219 #[cfg(any(test, feature = "testing"))]
1222 pub fn execute_by_step_with_package_debug_info_at_source_node_sync(
1223 mut self,
1224 program: &Program,
1225 package_debug_info: &PackageDebugInfo,
1226 entrypoint_source_node_id: DebugSourceNodeId,
1227 host: &mut impl SyncHost,
1228 ) -> Result<StackOutputs, ExecutionError> {
1229 let mut current_resume_ctx = self.source_aware_resume_context(
1230 program,
1231 package_debug_info,
1232 Some(entrypoint_source_node_id),
1233 )?;
1234
1235 loop {
1236 match self.step_with_package_debug_info_sync(
1237 host,
1238 current_resume_ctx,
1239 package_debug_info,
1240 )? {
1241 Some(next_resume_ctx) => {
1242 current_resume_ctx = next_resume_ctx;
1243 },
1244 None => break Ok(self.current_stack_outputs()),
1245 }
1246 }
1247 }
1248
1249 #[inline(always)]
1251 pub async fn execute_by_step(
1252 mut self,
1253 program: &Program,
1254 host: &mut impl Host,
1255 ) -> Result<StackOutputs, ExecutionError> {
1256 let mut current_resume_ctx = self.get_initial_resume_context(program)?;
1257 let mut processor = self;
1258
1259 loop {
1260 match processor.step(host, current_resume_ctx).await? {
1261 Some(next_resume_ctx) => {
1262 current_resume_ctx = next_resume_ctx;
1263 },
1264 None => break Ok(processor.current_stack_outputs()),
1265 }
1266 }
1267 }
1268
1269 #[cfg(any(test, feature = "testing"))]
1271 #[inline(always)]
1272 pub async fn execute_by_step_with_package_debug_info(
1273 mut self,
1274 program: &Program,
1275 package_debug_info: &PackageDebugInfo,
1276 host: &mut impl Host,
1277 ) -> Result<StackOutputs, ExecutionError> {
1278 let mut current_resume_ctx =
1279 self.source_aware_resume_context(program, package_debug_info, None)?;
1280 let mut processor = self;
1281
1282 loop {
1283 match processor
1284 .step_with_package_debug_info(host, current_resume_ctx, package_debug_info)
1285 .await?
1286 {
1287 Some(next_resume_ctx) => {
1288 current_resume_ctx = next_resume_ctx;
1289 },
1290 None => break Ok(processor.current_stack_outputs()),
1291 }
1292 }
1293 }
1294
1295 #[cfg(any(test, feature = "testing"))]
1298 #[inline(always)]
1299 pub async fn execute_by_step_with_package_debug_info_at_source_node(
1300 mut self,
1301 program: &Program,
1302 package_debug_info: &PackageDebugInfo,
1303 entrypoint_source_node_id: DebugSourceNodeId,
1304 host: &mut impl Host,
1305 ) -> Result<StackOutputs, ExecutionError> {
1306 let mut current_resume_ctx = self.source_aware_resume_context(
1307 program,
1308 package_debug_info,
1309 Some(entrypoint_source_node_id),
1310 )?;
1311 let mut processor = self;
1312
1313 loop {
1314 match processor
1315 .step_with_package_debug_info(host, current_resume_ctx, package_debug_info)
1316 .await?
1317 {
1318 Some(next_resume_ctx) => {
1319 current_resume_ctx = next_resume_ctx;
1320 },
1321 None => break Ok(processor.current_stack_outputs()),
1322 }
1323 }
1324 }
1325
1326 #[cfg(any(test, feature = "testing"))]
1330 pub fn execute_mut_sync(
1331 &mut self,
1332 program: &Program,
1333 host: &mut impl SyncHost,
1334 ) -> Result<StackOutputs, ExecutionError> {
1335 let mut continuation_stack = ContinuationStack::new(program);
1336 let mut current_forest = program.mast_forest().clone();
1337 let mut package_debug_info = None;
1338
1339 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
1340
1341 let flow = self.execute_impl(
1342 &mut continuation_stack,
1343 &mut current_forest,
1344 program.kernel(),
1345 host,
1346 &mut NoopTracer,
1347 &NeverStopper,
1348 &mut package_debug_info,
1349 );
1350 Self::stack_result_from_flow(flow)
1351 }
1352
1353 #[cfg(any(test, feature = "testing"))]
1355 #[inline(always)]
1356 pub async fn execute_mut(
1357 &mut self,
1358 program: &Program,
1359 host: &mut impl Host,
1360 ) -> Result<StackOutputs, ExecutionError> {
1361 let mut continuation_stack = ContinuationStack::new(program);
1362 let mut current_forest = program.mast_forest().clone();
1363 let mut package_debug_info = None;
1364
1365 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
1366
1367 let flow = self
1368 .execute_impl_async(
1369 &mut continuation_stack,
1370 &mut current_forest,
1371 program.kernel(),
1372 host,
1373 &mut NoopTracer,
1374 &NeverStopper,
1375 &mut package_debug_info,
1376 )
1377 .await;
1378 Self::stack_result_from_flow(flow)
1379 }
1380}