hypervisor: emulator: use static mapping to dispatch emulation

The mapping between code and its handler is static. We can drop the
HashMap in favour of a static match expression.

This has two benefits:
1. No more memory allocation and deallocation for the HashMap.
2. Shorter look-up time.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
Wei Liu
2020-12-01 15:07:00 +00:00
committed by Samuel Ortiz
parent ffaab46934
commit ab89b48143
+36 -23
View File
@@ -475,32 +475,47 @@ impl CpuStateManager for EmulatorCpuState {
pub struct Emulator<'a, T: CpuStateManager> { pub struct Emulator<'a, T: CpuStateManager> {
platform: &'a mut dyn PlatformEmulator<CpuState = T>, platform: &'a mut dyn PlatformEmulator<CpuState = T>,
insn_map: InstructionMap<T>, }
// Reduce repetition, see its invocation in get_handler().
macro_rules! gen_handler_match {
($value: ident, $( ($module:ident, $code:ident) ),* ) => {
match $value {
$(
Code::$code => Some(Box::new($module::$code {})),
)*
_ => None,
}
};
} }
impl<'a, T: CpuStateManager> Emulator<'a, T> { impl<'a, T: CpuStateManager> Emulator<'a, T> {
pub fn new(platform: &mut dyn PlatformEmulator<CpuState = T>) -> Emulator<T> { pub fn new(platform: &mut dyn PlatformEmulator<CpuState = T>) -> Emulator<T> {
let mut insn_map = InstructionMap::<T>::new(); Emulator { platform }
}
// MOV fn get_handler(code: Code) -> Option<Box<dyn InstructionHandler<T>>> {
insn_add!(insn_map, mov, Mov_r8_imm8); let handler: Option<Box<dyn InstructionHandler<T>>> = gen_handler_match!(
insn_add!(insn_map, mov, Mov_r8_rm8); code,
insn_add!(insn_map, mov, Mov_r16_imm16); (mov, Mov_r8_rm8),
insn_add!(insn_map, mov, Mov_r16_rm16); (mov, Mov_r8_imm8),
insn_add!(insn_map, mov, Mov_r32_imm32); (mov, Mov_r16_imm16),
insn_add!(insn_map, mov, Mov_r32_rm32); (mov, Mov_r16_rm16),
insn_add!(insn_map, mov, Mov_r64_imm64); (mov, Mov_r32_imm32),
insn_add!(insn_map, mov, Mov_r64_rm64); (mov, Mov_r32_rm32),
insn_add!(insn_map, mov, Mov_rm8_imm8); (mov, Mov_r64_imm64),
insn_add!(insn_map, mov, Mov_rm8_r8); (mov, Mov_r64_rm64),
insn_add!(insn_map, mov, Mov_rm16_imm16); (mov, Mov_rm8_imm8),
insn_add!(insn_map, mov, Mov_rm16_r16); (mov, Mov_rm8_r8),
insn_add!(insn_map, mov, Mov_rm32_imm32); (mov, Mov_rm16_imm16),
insn_add!(insn_map, mov, Mov_rm32_r32); (mov, Mov_rm16_r16),
insn_add!(insn_map, mov, Mov_rm64_imm32); (mov, Mov_rm32_imm32),
insn_add!(insn_map, mov, Mov_rm64_r64); (mov, Mov_rm32_r32),
(mov, Mov_rm64_imm32),
(mov, Mov_rm64_r64)
);
Emulator { platform, insn_map } handler
} }
fn emulate_insn_stream( fn emulate_insn_stream(
@@ -561,9 +576,7 @@ impl<'a, T: CpuStateManager> Emulator<'a, T> {
} }
// Emulate the decoded instruction // Emulate the decoded instruction
self.insn_map Emulator::get_handler(insn.code())
.instructions
.get(&insn.code())
.ok_or_else(|| { .ok_or_else(|| {
EmulationError::UnsupportedInstruction(anyhow!( EmulationError::UnsupportedInstruction(anyhow!(
"{:#x?} {:?} {:?}", "{:#x?} {:?} {:?}",