Skip to main content

Module execution_state

Module execution_state 

Source
Expand description

Checked invocation state and execution of an independently owned module.

The host owns program data. ExecutionState owns frames, locals, operands, the private PC, and execution flags. A runner borrows both the module and the machine; instructions borrow the module while authored Steps mutate devices. Component authors choose messages/effects, without implementing stack logic.

use vihaco_abi::{Type, Value};
use vihaco_module::module::{LocalModule, FunctionInfo, Signature};
use vihaco_runtime::{composite, field, Apply, BuildMessage, Execute, HasInstructionSet, Step};
use vihaco_stdlib::{ExecutionState, Image, execution_state::execute, program::program};
use vihaco_cpu::{CPU, cpu};

#[composite]
struct Machine {
    #[device(0)] #[program] execution: vihaco_stdlib::ExecutionState,
    #[device(1)] cpu: vihaco_cpu::CPU,
}
type Instruction = <Machine as HasInstructionSet>::Runtime;
type Program = LocalModule<Instruction, Value, Type>;

impl<I> Step<field!(Machine::execution), I, Program> for Machine
where
    ExecutionState: Execute<I, Effect = (), Error = eyre::Report>,
    Self: BuildMessage<field!(Machine::execution), I, Program>,
{
    fn step(&mut self, instruction: &I, module: &Program) -> eyre::Result<()> {
        let message = <Self as BuildMessage<field!(Machine::execution), I, Program>>
            ::build_message(self, instruction, module)?;
        self.execution.execute(instruction, message)
    }
}
impl<I> Step<field!(Machine::cpu), I, Program> for Machine
where
    CPU: Execute<I, Error = eyre::Report>,
    Self: BuildMessage<field!(Machine::cpu), I, Program>,
    ExecutionState: Apply<<CPU as Execute<I>>::Effect>,
{
    fn step(&mut self, instruction: &I, module: &Program) -> eyre::Result<()> {
        let message = <Self as BuildMessage<field!(Machine::cpu), I, Program>>
            ::build_message(self, instruction, module)?;
        let effect = self.cpu.execute(instruction, message)?;
        self.execution.apply(effect);
        Ok(())
    }
}

let module: Program = LocalModule {
    code: vec![
        Instruction::V_execution__program__ConstU64(program::ConstU64(20)),
        Instruction::V_execution__program__ConstU64(program::ConstU64(22)),
        Instruction::V_cpu__cpu__AddU64(cpu::AddU64),
        Instruction::V_execution__program__Return(program::Return(1)),
    ],
    main_function: Some(0),
    functions: vec![FunctionInfo {
        name: 0, signature: Signature { params: vec![], ret: vec![Type::U64] },
        local_count: 0, start_address: 0, end_address: 4, file: 0,
    }],
    ..Default::default()
};
// An ordinary outer owner keeps immutable program data beside its machine.
struct Loaded {
    image: Image<Instruction>,
    machine: Machine,
}
impl Loaded {
    fn run(&mut self) -> eyre::Result<()> {
        execute(&self.image.module, &mut self.machine, &[])
    }
}
let mut loaded = Loaded {
    image: Image::new(module),
    machine: Machine { execution: ExecutionState::new(), cpu: CPU::default() },
};
loaded.run()?;
assert_eq!(loaded.machine.execution.stack(), &[42]);

Structs§

ExecutionState
Frames, locals, operands, and private execution state for one invocation.

Functions§

execute
Enter main and execute through the composite’s authored Steps.
resume
Continue an invocation until Halt/root return or an error.