mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-23 18:02:05 -05:00
UserspaceEmulator: Add a very simple instruction fetch cache
To avoid MMU region lookup on every single instruction fetch, we now cache a raw pointer to the current instruction. This gets automatically invalidated when we jump somewhere, but as long as we're executing sequentially, instruction fetches will hit the cache and bypass all the region lookup stuff. This is about a ~2x speedup. :^)
This commit is contained in:
parent
c8d3f8cdeb
commit
8656835935
5 changed files with 44 additions and 4 deletions
|
@ -75,4 +75,9 @@ void SimpleRegion::write32(u32 offset, u32 value)
|
|||
*reinterpret_cast<u32*>(m_data + offset) = value;
|
||||
}
|
||||
|
||||
u8* SimpleRegion::cacheable_ptr(u32 offset)
|
||||
{
|
||||
return m_data + offset;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,6 +45,8 @@ public:
|
|||
|
||||
u8* data() { return m_data; }
|
||||
|
||||
virtual u8* cacheable_ptr(u32 offset) override;
|
||||
|
||||
private:
|
||||
u8* m_data { nullptr };
|
||||
};
|
||||
|
|
|
@ -61,23 +61,44 @@ void SoftCPU::dump() const
|
|||
printf("o=%u s=%u z=%u a=%u p=%u c=%u\n", of(), sf(), zf(), af(), pf(), cf());
|
||||
}
|
||||
|
||||
void SoftCPU::update_code_cache()
|
||||
{
|
||||
auto* region = m_emulator.mmu().find_region({ cs(), eip() });
|
||||
ASSERT(region);
|
||||
|
||||
m_cached_code_ptr = region->cacheable_ptr(eip() - region->base());
|
||||
m_cached_code_end = region->cacheable_ptr(region->size());
|
||||
}
|
||||
|
||||
u8 SoftCPU::read8()
|
||||
{
|
||||
auto value = read_memory8({ cs(), eip() });
|
||||
if (!m_cached_code_ptr || m_cached_code_ptr >= m_cached_code_end)
|
||||
update_code_cache();
|
||||
|
||||
u8 value = *m_cached_code_ptr;
|
||||
m_cached_code_ptr += 1;
|
||||
m_eip += 1;
|
||||
return value;
|
||||
}
|
||||
|
||||
u16 SoftCPU::read16()
|
||||
{
|
||||
auto value = read_memory16({ cs(), eip() });
|
||||
if (!m_cached_code_ptr || (m_cached_code_ptr + 2) >= m_cached_code_end)
|
||||
update_code_cache();
|
||||
|
||||
u16 value = *reinterpret_cast<const u16*>(m_cached_code_ptr);
|
||||
m_cached_code_ptr += 2;
|
||||
m_eip += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
u32 SoftCPU::read32()
|
||||
{
|
||||
auto value = read_memory32({ cs(), eip() });
|
||||
if (!m_cached_code_ptr || (m_cached_code_ptr + 4) >= m_cached_code_end)
|
||||
update_code_cache();
|
||||
|
||||
u32 value = *reinterpret_cast<const u32*>(m_cached_code_ptr);
|
||||
m_cached_code_ptr += 4;
|
||||
m_eip += 4;
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -56,7 +56,12 @@ public:
|
|||
void dump() const;
|
||||
|
||||
u32 eip() const { return m_eip; }
|
||||
void set_eip(u32 eip) { m_eip = eip; }
|
||||
void set_eip(u32 eip)
|
||||
{
|
||||
m_eip = eip;
|
||||
m_cached_code_ptr = nullptr;
|
||||
m_cached_code_end = nullptr;
|
||||
}
|
||||
|
||||
struct Flags {
|
||||
enum Flag {
|
||||
|
@ -792,6 +797,8 @@ private:
|
|||
template<bool check_zf, typename Callback>
|
||||
void do_once_or_repeat(const X86::Instruction& insn, Callback);
|
||||
|
||||
void update_code_cache();
|
||||
|
||||
private:
|
||||
Emulator& m_emulator;
|
||||
|
||||
|
@ -800,6 +807,9 @@ private:
|
|||
u32 m_eflags { 0 };
|
||||
|
||||
u32 m_eip { 0 };
|
||||
|
||||
const u8* m_cached_code_ptr { nullptr };
|
||||
const u8* m_cached_code_end { nullptr };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ public:
|
|||
virtual u16 read16(u32 offset) = 0;
|
||||
virtual u32 read32(u32 offset) = 0;
|
||||
|
||||
virtual u8* cacheable_ptr([[maybe_unused]] u32 offset) { return nullptr; }
|
||||
|
||||
protected:
|
||||
Region(u32 base, u32 size)
|
||||
: m_base(base)
|
||||
|
|
Loading…
Add table
Reference in a new issue