use super::*;
use crate::ExtendedOpcode;
use crate::decode::ExtendedOpVisitor;
use crate::opcode::Opcode;
use crate::profile::ExecutingPcRef;
type Handler = fn(&mut MachineState, UnsafeBytecodeStream, ExecutingPcRef<'_>) -> Done;
#[cfg(pulley_tail_calls)]
macro_rules! tail_call {
($e:expr) => {
become $e
};
}
#[cfg(pulley_assume_llvm_makes_tail_calls)]
macro_rules! tail_call {
($e:expr) => {
return $e
};
}
impl Interpreter<'_> {
pub fn run(self) -> Done {
dispatch(self.state, self.pc, self.executing_pc)
}
}
fn debug<'a>(
state: &'a mut MachineState,
pc: UnsafeBytecodeStream,
executing_pc: ExecutingPcRef<'a>,
) -> debug::Debug<'a> {
debug::Debug(Interpreter {
state,
pc,
executing_pc,
})
}
fn dispatch(
state: &mut MachineState,
pc: UnsafeBytecodeStream,
executing_pc: ExecutingPcRef<'_>,
) -> Done {
let mut debug = debug(state, pc, executing_pc);
debug.before_visit();
let Ok(opcode) = Opcode::decode(debug.bytecode());
let handler = OPCODE_HANDLER_TABLE[opcode as usize];
tail_call!(handler(debug.0.state, debug.0.pc, debug.0.executing_pc));
}
fn run_extended(
state: &mut MachineState,
pc: UnsafeBytecodeStream,
pc_ref: ExecutingPcRef<'_>,
) -> Done {
let mut i = debug(state, pc, pc_ref);
let Ok(opcode) = ExtendedOpcode::decode(i.bytecode());
let handler = EXTENDED_OPCODE_HANDLER_TABLE[opcode as usize];
tail_call!(handler(i.0.state, i.0.pc, i.0.executing_pc));
}
static OPCODE_HANDLER_TABLE: [Handler; Opcode::MAX as usize + 1] = {
macro_rules! define_opcode_handler_table {
($(
$( #[$attr:meta] )*
$snake_name:ident = $name:ident $( {
$(
$( #[$field_attr:meta] )*
$field:ident : $field_ty:ty
),*
} )?;
)*) => {
[
$($snake_name,)* run_extended,
]
};
}
for_each_op!(define_opcode_handler_table)
};
static EXTENDED_OPCODE_HANDLER_TABLE: [Handler; ExtendedOpcode::MAX as usize + 1] = {
macro_rules! define_extended_opcode_handler_table {
($(
$( #[$attr:meta] )*
$snake_name:ident = $name:ident $( {
$(
$( #[$field_attr:meta] )*
$field:ident : $field_ty:ty
),*
} )?;
)*) => {
[
$($snake_name,)* ]
};
}
for_each_extended_op!(define_extended_opcode_handler_table)
};
macro_rules! define_opcode_handler {
($(
$( #[$attr:meta] )*
$snake_name:ident = $name:ident $( {
$(
$( #[$field_attr:meta] )*
$field:ident : $field_ty:ty
),*
} )?;
)*) => {$(
fn $snake_name(
state: &mut MachineState,
pc: UnsafeBytecodeStream,
executing_pc: ExecutingPcRef<'_>,
) -> Done {
let mut debug = debug(state, pc, executing_pc);
$(
let Ok(($($field,)*)) = crate::decode::operands::$snake_name(debug.0.bytecode());
)?
let result = debug.$snake_name($($($field),*)?);
debug.after_visit();
match result {
ControlFlow::Continue(()) => {
tail_call!(dispatch(debug.0.state, debug.0.pc, debug.0.executing_pc))
}
ControlFlow::Break(done) => done,
}
}
)*};
}
for_each_op!(define_opcode_handler);
for_each_extended_op!(define_opcode_handler);