pub trait ProgramCounter<Address, Memory>where
Address: Copy,{
// Required methods
fn get_pc(&self) -> Address;
unsafe fn try_set_pc_relative(
&mut self,
instruction_size: u8,
offset: i32,
) -> bool;
unsafe fn failed_branch(
&mut self,
memory: &Memory,
) -> Result<ControlFlow<()>, ExecutionError<Address>>;
fn set_pc(
&mut self,
memory: &Memory,
pc: Address,
) -> Result<ControlFlow<()>, ExecutionError<Address>>;
// Provided methods
fn old_pc(&self, instruction_size: u8) -> Address
where Address: From<u8> + Sub<Output = Address> { ... }
fn set_pc_relative(
&mut self,
memory: &Memory,
instruction_size: u8,
offset: i32,
) -> Result<ControlFlow<()>, ExecutionError<Address>>
where Self: ProgramCounter<Address, Memory> { ... }
}Expand description
Generic program counter
Required Methods§
Sourceunsafe fn try_set_pc_relative(
&mut self,
instruction_size: u8,
offset: i32,
) -> bool
unsafe fn try_set_pc_relative( &mut self, instruction_size: u8, offset: i32, ) -> bool
Move offset bytes from the instruction being executed for targets this can resolve.
A simple implementation can resolve the offset against the program counter and validate it
the way Self::set_pc() does. Implementation that keeps the program counter as a position
in an already decoded instruction stream can move within that stream directly, which avoids
converting an address back into a position.
Returns true when the program counter now points at the target, and false when the
target is not somewhere it may point at.
Separate from Self::failed_branch() for the sake of threaded dispatch, where working out
what exactly is wrong with a target is code that no branch or jump ever runs, and inlining
it into the handler of every one of them puts it between the parts of the interpreter that
do run frequently. Split this way, a handler can hand a refused target to a cold
continuation with a tail call, which is the one call that costs it nothing, since nothing it
holds has to survive one.
§Safety
When this returns false, the program counter is left holding the refused target, which is
not a position to fetch from - it is what Self::failed_branch() reads to say what was
wrong with it. That call must come next before anything else observes the program counter.
Sourceunsafe fn failed_branch(
&mut self,
memory: &Memory,
) -> Result<ControlFlow<()>, ExecutionError<Address>>
unsafe fn failed_branch( &mut self, memory: &Memory, ) -> Result<ControlFlow<()>, ExecutionError<Address>>
Say what is wrong with the target Self::try_set_pc_relative() refused.
Implementations are expected to be #[cold] and #[inline(never)]: this is the half of
Self::set_pc_relative() that a program only reaches on its way out.
§Safety
Must be called right after Self::try_set_pc_relative() returned false, with nothing in
between having observed the program counter.
Sourcefn set_pc(
&mut self,
memory: &Memory,
pc: Address,
) -> Result<ControlFlow<()>, ExecutionError<Address>>
fn set_pc( &mut self, memory: &Memory, pc: Address, ) -> Result<ControlFlow<()>, ExecutionError<Address>>
Set the current value of the program counter
Provided Methods§
Sourcefn old_pc(&self, instruction_size: u8) -> Address
fn old_pc(&self, instruction_size: u8) -> Address
Get the previous value of the program counter before executing an instruction.
This is usually called from under instruction execution when the program counter is already
advanced during instruction fetching. As such, pc - instruction_size is expected to never
underflow.
Sourcefn set_pc_relative(
&mut self,
memory: &Memory,
instruction_size: u8,
offset: i32,
) -> Result<ControlFlow<()>, ExecutionError<Address>>where
Self: ProgramCounter<Address, Memory>,
fn set_pc_relative(
&mut self,
memory: &Memory,
instruction_size: u8,
offset: i32,
) -> Result<ControlFlow<()>, ExecutionError<Address>>where
Self: ProgramCounter<Address, Memory>,
Apply ExecutionResult::Branch, continuing offset bytes from the instruction being
executed.
This is Self::try_set_pc_relative() followed, if it refused the target, by
Self::failed_branch(), and exists for callers that have nothing better to do with a
refused target than ask what was wrong with it right there.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".