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 tracing::instrument;
10
11use super::{
12 FastProcessor, NoopTracer,
13 external::maybe_use_caller_error_context,
14 step::{BreakReason, NeverStopper, ResumeContext, StepStopper},
15};
16use crate::{
17 ExecutionError, ExecutionOutput, Host, Stopper, SyncHost, TraceBuildInputs,
18 continuation_stack::ContinuationStack,
19 errors::{MapExecErr, MapExecErrNoCtx, OperationError},
20 execution::{
21 InternalBreakReason, execute_impl, finish_emit_op_execution,
22 finish_load_mast_forest_from_dyn_start, finish_load_mast_forest_from_external,
23 },
24 trace::execution_tracer::ExecutionTracer,
25 tracer::Tracer,
26};
27
28impl FastProcessor {
29 pub fn execute_sync(
34 self,
35 program: &Program,
36 host: &mut impl SyncHost,
37 ) -> Result<ExecutionOutput, ExecutionError> {
38 self.execute_with_tracer_sync(program, host, &mut NoopTracer)
39 }
40
41 #[inline(always)]
43 pub async fn execute(
44 self,
45 program: &Program,
46 host: &mut impl Host,
47 ) -> Result<ExecutionOutput, ExecutionError> {
48 self.execute_with_tracer(program, host, &mut NoopTracer).await
49 }
50
51 #[instrument(name = "execute_trace_inputs_sync", skip_all)]
70 pub fn execute_trace_inputs_sync(
71 self,
72 program: &Program,
73 host: &mut impl SyncHost,
74 ) -> Result<TraceBuildInputs, ExecutionError> {
75 let mut tracer = ExecutionTracer::new(
76 self.options.core_trace_fragment_size(),
77 self.options.max_stack_depth(),
78 );
79 let execution_output = self.execute_with_tracer_sync(program, host, &mut tracer)?;
80 Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer))
81 }
82
83 #[inline(always)]
85 #[instrument(name = "execute_trace_inputs", skip_all)]
86 pub async fn execute_trace_inputs(
87 self,
88 program: &Program,
89 host: &mut impl Host,
90 ) -> Result<TraceBuildInputs, ExecutionError> {
91 let mut tracer = ExecutionTracer::new(
92 self.options.core_trace_fragment_size(),
93 self.options.max_stack_depth(),
94 );
95 let execution_output = self.execute_with_tracer(program, host, &mut tracer).await?;
96 Ok(Self::trace_build_inputs_from_parts(program, execution_output, tracer))
97 }
98
99 pub async fn execute_with_tracer<T>(
101 mut self,
102 program: &Program,
103 host: &mut impl Host,
104 tracer: &mut T,
105 ) -> Result<ExecutionOutput, ExecutionError>
106 where
107 T: Tracer<Processor = Self>,
108 {
109 let mut continuation_stack = ContinuationStack::new(program);
110 let mut current_forest = program.mast_forest().clone();
111
112 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
113 let flow = self
114 .execute_impl_async(
115 &mut continuation_stack,
116 &mut current_forest,
117 program.kernel(),
118 host,
119 tracer,
120 &NeverStopper,
121 )
122 .await;
123 Self::execution_result_from_flow(flow, self)
124 }
125
126 pub fn execute_with_tracer_sync<T>(
128 mut self,
129 program: &Program,
130 host: &mut impl SyncHost,
131 tracer: &mut T,
132 ) -> Result<ExecutionOutput, ExecutionError>
133 where
134 T: Tracer<Processor = Self>,
135 {
136 let mut continuation_stack = ContinuationStack::new(program);
137 let mut current_forest = program.mast_forest().clone();
138
139 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
140 let flow = self.execute_impl(
141 &mut continuation_stack,
142 &mut current_forest,
143 program.kernel(),
144 host,
145 tracer,
146 &NeverStopper,
147 );
148 Self::execution_result_from_flow(flow, self)
149 }
150
151 pub fn step_sync(
153 &mut self,
154 host: &mut impl SyncHost,
155 resume_ctx: ResumeContext,
156 ) -> Result<Option<ResumeContext>, ExecutionError> {
157 let ResumeContext {
158 mut current_forest,
159 mut continuation_stack,
160 kernel,
161 } = resume_ctx;
162
163 let flow = self.execute_impl(
164 &mut continuation_stack,
165 &mut current_forest,
166 &kernel,
167 host,
168 &mut NoopTracer,
169 &StepStopper,
170 );
171 Self::resume_context_from_flow(flow, continuation_stack, current_forest, kernel)
172 }
173
174 #[inline(always)]
176 pub async fn step(
177 &mut self,
178 host: &mut impl Host,
179 resume_ctx: ResumeContext,
180 ) -> Result<Option<ResumeContext>, ExecutionError> {
181 let ResumeContext {
182 mut current_forest,
183 mut continuation_stack,
184 kernel,
185 } = resume_ctx;
186
187 let flow = self
188 .execute_impl_async(
189 &mut continuation_stack,
190 &mut current_forest,
191 &kernel,
192 host,
193 &mut NoopTracer,
194 &StepStopper,
195 )
196 .await;
197 Self::resume_context_from_flow(flow, continuation_stack, current_forest, kernel)
198 }
199
200 #[inline(always)]
202 fn trace_build_inputs_from_parts(
203 program: &Program,
204 execution_output: ExecutionOutput,
205 tracer: ExecutionTracer,
206 ) -> TraceBuildInputs {
207 TraceBuildInputs::from_execution(
208 program,
209 execution_output,
210 tracer.into_trace_generation_context(),
211 )
212 }
213
214 #[inline(always)]
216 fn resume_context_from_flow(
217 flow: ControlFlow<BreakReason, StackOutputs>,
218 mut continuation_stack: ContinuationStack,
219 current_forest: Arc<MastForest>,
220 kernel: Kernel,
221 ) -> Result<Option<ResumeContext>, ExecutionError> {
222 match flow {
223 ControlFlow::Continue(_) => Ok(None),
224 ControlFlow::Break(break_reason) => match break_reason {
225 BreakReason::Err(err) => Err(err),
226 BreakReason::Stopped(maybe_continuation) => {
227 if let Some(continuation) = maybe_continuation {
228 continuation_stack.push_continuation(continuation);
229 }
230
231 Ok(Some(ResumeContext {
232 current_forest,
233 continuation_stack,
234 kernel,
235 }))
236 },
237 },
238 }
239 }
240
241 #[inline(always)]
243 fn current_stack_outputs(&self) -> StackOutputs {
244 StackOutputs::new(
245 &self.stack[self.stack_bot_idx..self.stack_top_idx]
246 .iter()
247 .rev()
248 .copied()
249 .collect::<Vec<_>>(),
250 )
251 .unwrap()
252 }
253
254 fn execute_impl<S, T>(
260 &mut self,
261 continuation_stack: &mut ContinuationStack,
262 current_forest: &mut Arc<MastForest>,
263 kernel: &Kernel,
264 host: &mut impl SyncHost,
265 tracer: &mut T,
266 stopper: &S,
267 ) -> ControlFlow<BreakReason, StackOutputs>
268 where
269 S: Stopper<Processor = Self>,
270 T: Tracer<Processor = Self>,
271 {
272 while let ControlFlow::Break(internal_break_reason) =
273 execute_impl(self, continuation_stack, current_forest, kernel, host, tracer, stopper)
274 {
275 match internal_break_reason {
276 InternalBreakReason::User(break_reason) => return ControlFlow::Break(break_reason),
277 InternalBreakReason::Emit {
278 basic_block_node_id,
279 op_idx,
280 continuation,
281 } => {
282 self.op_emit_sync(host, current_forest, basic_block_node_id, op_idx)?;
283
284 finish_emit_op_execution(
285 continuation,
286 self,
287 continuation_stack,
288 current_forest,
289 tracer,
290 stopper,
291 )?;
292 },
293 InternalBreakReason::LoadMastForestFromDyn { dyn_node_id, callee_hash } => {
294 let (root_id, new_forest) = match self.load_mast_forest_sync(
295 callee_hash,
296 host,
297 current_forest,
298 dyn_node_id,
299 ) {
300 Ok(result) => result,
301 Err(err) => return ControlFlow::Break(BreakReason::Err(err)),
302 };
303
304 finish_load_mast_forest_from_dyn_start(
305 root_id,
306 new_forest,
307 self,
308 current_forest,
309 continuation_stack,
310 tracer,
311 stopper,
312 )?;
313 },
314 InternalBreakReason::LoadMastForestFromExternal {
315 external_node_id,
316 procedure_hash,
317 } => {
318 let (root_id, new_forest) = match self.load_mast_forest_sync(
319 procedure_hash,
320 host,
321 current_forest,
322 external_node_id,
323 ) {
324 Ok(result) => result,
325 Err(err) => {
326 let maybe_enriched_err = maybe_use_caller_error_context(
327 err,
328 current_forest,
329 continuation_stack,
330 host,
331 );
332
333 return ControlFlow::Break(BreakReason::Err(maybe_enriched_err));
334 },
335 };
336
337 finish_load_mast_forest_from_external(
338 root_id,
339 new_forest,
340 external_node_id,
341 current_forest,
342 continuation_stack,
343 host,
344 tracer,
345 )?;
346 },
347 }
348 }
349
350 match StackOutputs::new(
351 &self.stack[self.stack_bot_idx..self.stack_top_idx]
352 .iter()
353 .rev()
354 .copied()
355 .collect::<Vec<_>>(),
356 ) {
357 Ok(stack_outputs) => ControlFlow::Continue(stack_outputs),
358 Err(_) => ControlFlow::Break(BreakReason::Err(ExecutionError::OutputStackOverflow(
359 self.stack_top_idx - self.stack_bot_idx - MIN_STACK_DEPTH,
360 ))),
361 }
362 }
363
364 async fn execute_impl_async<S, T>(
365 &mut self,
366 continuation_stack: &mut ContinuationStack,
367 current_forest: &mut Arc<MastForest>,
368 kernel: &Kernel,
369 host: &mut impl Host,
370 tracer: &mut T,
371 stopper: &S,
372 ) -> ControlFlow<BreakReason, StackOutputs>
373 where
374 S: Stopper<Processor = Self>,
375 T: Tracer<Processor = Self>,
376 {
377 while let ControlFlow::Break(internal_break_reason) =
378 execute_impl(self, continuation_stack, current_forest, kernel, host, tracer, stopper)
379 {
380 match internal_break_reason {
381 InternalBreakReason::User(break_reason) => return ControlFlow::Break(break_reason),
382 InternalBreakReason::Emit {
383 basic_block_node_id,
384 op_idx,
385 continuation,
386 } => {
387 self.op_emit(host, current_forest, basic_block_node_id, op_idx).await?;
388
389 finish_emit_op_execution(
390 continuation,
391 self,
392 continuation_stack,
393 current_forest,
394 tracer,
395 stopper,
396 )?;
397 },
398 InternalBreakReason::LoadMastForestFromDyn { dyn_node_id, callee_hash } => {
399 let (root_id, new_forest) = match self
400 .load_mast_forest(callee_hash, host, current_forest, dyn_node_id)
401 .await
402 {
403 Ok(result) => result,
404 Err(err) => return ControlFlow::Break(BreakReason::Err(err)),
405 };
406
407 finish_load_mast_forest_from_dyn_start(
408 root_id,
409 new_forest,
410 self,
411 current_forest,
412 continuation_stack,
413 tracer,
414 stopper,
415 )?;
416 },
417 InternalBreakReason::LoadMastForestFromExternal {
418 external_node_id,
419 procedure_hash,
420 } => {
421 let (root_id, new_forest) = match self
422 .load_mast_forest(procedure_hash, host, current_forest, external_node_id)
423 .await
424 {
425 Ok(result) => result,
426 Err(err) => {
427 let maybe_enriched_err = maybe_use_caller_error_context(
428 err,
429 current_forest,
430 continuation_stack,
431 host,
432 );
433
434 return ControlFlow::Break(BreakReason::Err(maybe_enriched_err));
435 },
436 };
437
438 finish_load_mast_forest_from_external(
439 root_id,
440 new_forest,
441 external_node_id,
442 current_forest,
443 continuation_stack,
444 host,
445 tracer,
446 )?;
447 },
448 }
449 }
450
451 match StackOutputs::new(
452 &self.stack[self.stack_bot_idx..self.stack_top_idx]
453 .iter()
454 .rev()
455 .copied()
456 .collect::<Vec<_>>(),
457 ) {
458 Ok(stack_outputs) => ControlFlow::Continue(stack_outputs),
459 Err(_) => ControlFlow::Break(BreakReason::Err(ExecutionError::OutputStackOverflow(
460 self.stack_top_idx - self.stack_bot_idx - MIN_STACK_DEPTH,
461 ))),
462 }
463 }
464
465 fn load_mast_forest_sync(
469 &mut self,
470 node_digest: Word,
471 host: &mut impl SyncHost,
472 current_forest: &MastForest,
473 node_id: MastNodeId,
474 ) -> Result<(MastNodeId, Arc<MastForest>), ExecutionError> {
475 let mast_forest = host.get_mast_forest(&node_digest).ok_or_else(|| {
476 crate::errors::procedure_not_found_with_context(
477 node_digest,
478 current_forest,
479 node_id,
480 host,
481 )
482 })?;
483
484 let root_id = mast_forest.find_procedure_root(node_digest).ok_or_else(|| {
485 Err::<(), _>(OperationError::MalformedMastForestInHost { root_digest: node_digest })
486 .map_exec_err(current_forest, node_id, host)
487 .unwrap_err()
488 })?;
489
490 self.advice.extend_map(mast_forest.advice_map()).map_exec_err(
491 current_forest,
492 node_id,
493 host,
494 )?;
495
496 Ok((root_id, mast_forest))
497 }
498
499 async fn load_mast_forest(
500 &mut self,
501 node_digest: Word,
502 host: &mut impl Host,
503 current_forest: &MastForest,
504 node_id: MastNodeId,
505 ) -> Result<(MastNodeId, Arc<MastForest>), ExecutionError> {
506 let mast_forest = if let Some(mast_forest) = host.get_mast_forest(&node_digest).await {
507 mast_forest
508 } else {
509 return Err(crate::errors::procedure_not_found_with_context(
510 node_digest,
511 current_forest,
512 node_id,
513 host,
514 ));
515 };
516
517 let root_id = mast_forest.find_procedure_root(node_digest).ok_or_else(|| {
518 Err::<(), _>(OperationError::MalformedMastForestInHost { root_digest: node_digest })
519 .map_exec_err(current_forest, node_id, host)
520 .unwrap_err()
521 })?;
522
523 self.advice.extend_map(mast_forest.advice_map()).map_exec_err(
524 current_forest,
525 node_id,
526 host,
527 )?;
528
529 Ok((root_id, mast_forest))
530 }
531
532 pub fn execute_by_step_sync(
534 mut self,
535 program: &Program,
536 host: &mut impl SyncHost,
537 ) -> Result<StackOutputs, ExecutionError> {
538 let mut current_resume_ctx = self.get_initial_resume_context(program)?;
539
540 loop {
541 match self.step_sync(host, current_resume_ctx)? {
542 Some(next_resume_ctx) => {
543 current_resume_ctx = next_resume_ctx;
544 },
545 None => break Ok(self.current_stack_outputs()),
546 }
547 }
548 }
549
550 #[inline(always)]
552 pub async fn execute_by_step(
553 mut self,
554 program: &Program,
555 host: &mut impl Host,
556 ) -> Result<StackOutputs, ExecutionError> {
557 let mut current_resume_ctx = self.get_initial_resume_context(program)?;
558 let mut processor = self;
559
560 loop {
561 match processor.step(host, current_resume_ctx).await? {
562 Some(next_resume_ctx) => {
563 current_resume_ctx = next_resume_ctx;
564 },
565 None => break Ok(processor.current_stack_outputs()),
566 }
567 }
568 }
569
570 #[cfg(any(test, feature = "testing"))]
574 pub fn execute_mut_sync(
575 &mut self,
576 program: &Program,
577 host: &mut impl SyncHost,
578 ) -> Result<StackOutputs, ExecutionError> {
579 let mut continuation_stack = ContinuationStack::new(program);
580 let mut current_forest = program.mast_forest().clone();
581
582 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
583
584 let flow = self.execute_impl(
585 &mut continuation_stack,
586 &mut current_forest,
587 program.kernel(),
588 host,
589 &mut NoopTracer,
590 &NeverStopper,
591 );
592 Self::stack_result_from_flow(flow)
593 }
594
595 #[cfg(any(test, feature = "testing"))]
597 #[inline(always)]
598 pub async fn execute_mut(
599 &mut self,
600 program: &Program,
601 host: &mut impl Host,
602 ) -> Result<StackOutputs, ExecutionError> {
603 let mut continuation_stack = ContinuationStack::new(program);
604 let mut current_forest = program.mast_forest().clone();
605
606 self.advice.extend_map(current_forest.advice_map()).map_exec_err_no_ctx()?;
607
608 let flow = self
609 .execute_impl_async(
610 &mut continuation_stack,
611 &mut current_forest,
612 program.kernel(),
613 host,
614 &mut NoopTracer,
615 &NeverStopper,
616 )
617 .await;
618 Self::stack_result_from_flow(flow)
619 }
620}