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