pub mod asm;
pub mod output;
pub mod rust;
pub use asm::*;
pub use output::*;
pub use rust::*;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use crate::error::{ExecutorError, ExecutorResult};
use proofman_fields::PrimeField64;
use zisk_common::{io::ZiskStdin, AsmExecutionInfo, ExecutorStatsHandle, StatsScope};
use zisk_core::ZiskRom;
pub type ChunkHook<'a> =
&'a dyn Fn(usize, &[Arc<zisk_common::EmuTrace>], bool) -> ExecutorResult<()>;
pub struct ExecutionPhase {
emulator_rust: EmulatorRust,
emulator_asm: Option<EmulatorAsm>,
is_asm_execution: AtomicBool,
}
impl ExecutionPhase {
pub fn new(chunk_size: u64, with_asm_emulator: bool) -> Self {
Self {
emulator_asm: with_asm_emulator.then(|| EmulatorAsm::new(chunk_size)),
emulator_rust: EmulatorRust::new(chunk_size),
is_asm_execution: AtomicBool::new(false),
}
}
#[inline]
pub fn is_asm_execution(&self) -> bool {
self.is_asm_execution.load(Ordering::Relaxed)
}
pub fn asm_emulator(&self) -> Option<&EmulatorAsm> {
if self.is_asm_execution() {
self.emulator_asm.as_ref()
} else {
None
}
}
pub fn set_asm_resources(&self, asm_resources: Arc<AsmResources>) -> ExecutorResult<()> {
let asm = self.emulator_asm.as_ref().ok_or(ExecutorError::AsmNotAvailable)?;
asm.set_asm_resources(asm_resources)?;
self.is_asm_execution.store(true, Ordering::Relaxed);
Ok(())
}
pub fn clear_asm_resources(&self) {
self.is_asm_execution.store(false, Ordering::Relaxed);
}
pub fn reset(&self) -> ExecutorResult<()> {
if let Some(asm) = self.asm_emulator() {
asm.reset()?;
}
Ok(())
}
pub fn get_asm_execution_info(&self) -> ExecutorResult<Option<AsmExecutionInfo>> {
match self.asm_emulator() {
Some(asm) => asm.get_asm_execution_info(),
None => Ok(None),
}
}
#[allow(clippy::too_many_arguments)]
pub fn run<F: PrimeField64>(
&self,
zisk_rom: &ZiskRom,
stdin: &ZiskStdin,
is_first_process: bool,
use_hints: bool,
stats: &ExecutorStatsHandle,
caller_stats_scope: &StatsScope,
chunk_hook: ChunkHook<'_>,
) -> ExecutorResult<ExecutionOutput> {
match self.asm_emulator() {
Some(asm) => asm.execute::<F>(
zisk_rom,
stdin,
is_first_process,
use_hints,
stats,
caller_stats_scope,
chunk_hook,
),
None => self.emulator_rust.execute::<F>(zisk_rom, stdin),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn emu_only_starts_in_rust_mode() {
let phase = ExecutionPhase::new(1024, false);
assert!(!phase.is_asm_execution());
assert!(phase.asm_emulator().is_none());
}
#[test]
fn asm_capable_starts_in_rust_mode() {
let phase = ExecutionPhase::new(1024, true);
assert!(!phase.is_asm_execution(), "runtime flag defaults to false");
assert!(phase.asm_emulator().is_none(), "no asm dispatch until set_asm_resources");
}
#[test]
fn rust_reset_is_noop() {
let phase = ExecutionPhase::new(1024, false);
assert!(phase.reset().is_ok());
}
#[test]
fn rust_asm_execution_info_is_none() {
let phase = ExecutionPhase::new(1024, false);
let info = phase.get_asm_execution_info().expect("ok");
assert!(info.is_none());
}
#[test]
fn clear_without_set_is_safe() {
let phase = ExecutionPhase::new(1024, true);
phase.clear_asm_resources();
assert!(!phase.is_asm_execution());
}
}