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§
- Execution
State - Frames, locals, operands, and private execution state for one invocation.