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

View File

@ -475,32 +475,47 @@ impl CpuStateManager for EmulatorCpuState {
pub struct Emulator<'a, T: CpuStateManager> {
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> {
pub fn new(platform: &mut dyn PlatformEmulator<CpuState = T>) -> Emulator<T> {
let mut insn_map = InstructionMap::<T>::new();
Emulator { platform }
}
// MOV
insn_add!(insn_map, mov, Mov_r8_imm8);
insn_add!(insn_map, mov, Mov_r8_rm8);
insn_add!(insn_map, mov, Mov_r16_imm16);
insn_add!(insn_map, mov, Mov_r16_rm16);
insn_add!(insn_map, mov, Mov_r32_imm32);
insn_add!(insn_map, mov, Mov_r32_rm32);
insn_add!(insn_map, mov, Mov_r64_imm64);
insn_add!(insn_map, mov, Mov_r64_rm64);
insn_add!(insn_map, mov, Mov_rm8_imm8);
insn_add!(insn_map, mov, Mov_rm8_r8);
insn_add!(insn_map, mov, Mov_rm16_imm16);
insn_add!(insn_map, mov, Mov_rm16_r16);
insn_add!(insn_map, mov, Mov_rm32_imm32);
insn_add!(insn_map, mov, Mov_rm32_r32);
insn_add!(insn_map, mov, Mov_rm64_imm32);
insn_add!(insn_map, mov, Mov_rm64_r64);
fn get_handler(code: Code) -> Option<Box<dyn InstructionHandler<T>>> {
let handler: Option<Box<dyn InstructionHandler<T>>> = gen_handler_match!(
code,
(mov, Mov_r8_rm8),
(mov, Mov_r8_imm8),
(mov, Mov_r16_imm16),
(mov, Mov_r16_rm16),
(mov, Mov_r32_imm32),
(mov, Mov_r32_rm32),
(mov, Mov_r64_imm64),
(mov, Mov_r64_rm64),
(mov, Mov_rm8_imm8),
(mov, Mov_rm8_r8),
(mov, Mov_rm16_imm16),
(mov, Mov_rm16_r16),
(mov, Mov_rm32_imm32),
(mov, Mov_rm32_r32),
(mov, Mov_rm64_imm32),
(mov, Mov_rm64_r64)
);
Emulator { platform, insn_map }
handler
}
fn emulate_insn_stream(
@ -561,9 +576,7 @@ impl<'a, T: CpuStateManager> Emulator<'a, T> {
}
// Emulate the decoded instruction
self.insn_map
.instructions
.get(&insn.code())
Emulator::get_handler(insn.code())
.ok_or_else(|| {
EmulationError::UnsupportedInstruction(anyhow!(
"{:#x?} {:?} {:?}",