JITs: Add EraseSingleBlock Function
This commit is contained in:
parent
d26dc1ba32
commit
46f8fe0eaf
|
@ -402,6 +402,12 @@ bool CachedInterpreter::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CachedInterpreter::EraseSingleBlock(const JitBlock& block)
|
||||||
|
{
|
||||||
|
m_block_cache.EraseSingleBlock(block);
|
||||||
|
FreeRanges();
|
||||||
|
}
|
||||||
|
|
||||||
void CachedInterpreter::ClearCache()
|
void CachedInterpreter::ClearCache()
|
||||||
{
|
{
|
||||||
m_block_cache.Clear();
|
m_block_cache.Clear();
|
||||||
|
|
|
@ -46,6 +46,8 @@ public:
|
||||||
void Jit(u32 address, bool clear_cache_and_retry_on_failure);
|
void Jit(u32 address, bool clear_cache_and_retry_on_failure);
|
||||||
bool DoJit(u32 address, JitBlock* b, u32 nextPC);
|
bool DoJit(u32 address, JitBlock* b, u32 nextPC);
|
||||||
|
|
||||||
|
void EraseSingleBlock(const JitBlock& block) override;
|
||||||
|
|
||||||
static std::size_t Disassemble(const JitBlock& block, std::ostream& stream);
|
static std::size_t Disassemble(const JitBlock& block, std::ostream& stream);
|
||||||
|
|
||||||
JitBaseBlockCache* GetBlockCache() override { return &m_block_cache; }
|
JitBaseBlockCache* GetBlockCache() override { return &m_block_cache; }
|
||||||
|
|
|
@ -1202,6 +1202,12 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Jit64::EraseSingleBlock(const JitBlock& block)
|
||||||
|
{
|
||||||
|
blocks.EraseSingleBlock(block);
|
||||||
|
FreeRanges();
|
||||||
|
}
|
||||||
|
|
||||||
BitSet8 Jit64::ComputeStaticGQRs(const PPCAnalyst::CodeBlock& cb) const
|
BitSet8 Jit64::ComputeStaticGQRs(const PPCAnalyst::CodeBlock& cb) const
|
||||||
{
|
{
|
||||||
return cb.m_gqr_used & ~cb.m_gqr_modified;
|
return cb.m_gqr_used & ~cb.m_gqr_modified;
|
||||||
|
|
|
@ -65,6 +65,8 @@ public:
|
||||||
void Jit(u32 em_address, bool clear_cache_and_retry_on_failure);
|
void Jit(u32 em_address, bool clear_cache_and_retry_on_failure);
|
||||||
bool DoJit(u32 em_address, JitBlock* b, u32 nextPC);
|
bool DoJit(u32 em_address, JitBlock* b, u32 nextPC);
|
||||||
|
|
||||||
|
void EraseSingleBlock(const JitBlock& block) override;
|
||||||
|
|
||||||
// Finds a free memory region and sets the near and far code emitters to point at that region.
|
// Finds a free memory region and sets the near and far code emitters to point at that region.
|
||||||
// Returns false if no free memory region can be found for either of the two.
|
// Returns false if no free memory region can be found for either of the two.
|
||||||
bool SetEmitterStateToFreeCodeRegion();
|
bool SetEmitterStateToFreeCodeRegion();
|
||||||
|
|
|
@ -1034,6 +1034,12 @@ void JitArm64::Jit(u32 em_address, bool clear_cache_and_retry_on_failure)
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JitArm64::EraseSingleBlock(const JitBlock& block)
|
||||||
|
{
|
||||||
|
blocks.EraseSingleBlock(block);
|
||||||
|
FreeRanges();
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<size_t> JitArm64::SetEmitterStateToFreeCodeRegion()
|
std::optional<size_t> JitArm64::SetEmitterStateToFreeCodeRegion()
|
||||||
{
|
{
|
||||||
// Find some large free memory blocks and set code emitters to point at them. If we can't find
|
// Find some large free memory blocks and set code emitters to point at them. If we can't find
|
||||||
|
|
|
@ -48,6 +48,8 @@ public:
|
||||||
void Jit(u32 em_address) override;
|
void Jit(u32 em_address) override;
|
||||||
void Jit(u32 em_address, bool clear_cache_and_retry_on_failure);
|
void Jit(u32 em_address, bool clear_cache_and_retry_on_failure);
|
||||||
|
|
||||||
|
void EraseSingleBlock(const JitBlock& block) override;
|
||||||
|
|
||||||
const char* GetName() const override { return "JITARM64"; }
|
const char* GetName() const override { return "JITARM64"; }
|
||||||
|
|
||||||
// OPCODES
|
// OPCODES
|
||||||
|
|
|
@ -194,6 +194,8 @@ public:
|
||||||
|
|
||||||
virtual void Jit(u32 em_address) = 0;
|
virtual void Jit(u32 em_address) = 0;
|
||||||
|
|
||||||
|
virtual void EraseSingleBlock(const JitBlock& block) = 0;
|
||||||
|
|
||||||
virtual const CommonAsmRoutinesBase* GetAsmRoutines() = 0;
|
virtual const CommonAsmRoutinesBase* GetAsmRoutines() = 0;
|
||||||
|
|
||||||
virtual bool HandleFault(uintptr_t access_address, SContext* ctx) = 0;
|
virtual bool HandleFault(uintptr_t access_address, SContext* ctx) = 0;
|
||||||
|
|
|
@ -155,11 +155,10 @@ void JitBaseBlockCache::FinalizeBlock(JitBlock& block, bool block_link,
|
||||||
|
|
||||||
block.physical_addresses = physical_addresses;
|
block.physical_addresses = physical_addresses;
|
||||||
|
|
||||||
u32 range_mask = ~(BLOCK_RANGE_MAP_ELEMENTS - 1);
|
for (u32 addr : block.physical_addresses)
|
||||||
for (u32 addr : physical_addresses)
|
|
||||||
{
|
{
|
||||||
valid_block.Set(addr / 32);
|
valid_block.Set(addr / 32);
|
||||||
block_range_map[addr & range_mask].insert(&block);
|
block_range_map[addr & BLOCK_RANGE_MAP_MASK].insert(&block);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block_link)
|
if (block_link)
|
||||||
|
@ -333,8 +332,7 @@ void JitBaseBlockCache::InvalidateICacheInternal(u32 physical_address, u32 addre
|
||||||
void JitBaseBlockCache::ErasePhysicalRange(u32 address, u32 length)
|
void JitBaseBlockCache::ErasePhysicalRange(u32 address, u32 length)
|
||||||
{
|
{
|
||||||
// Iterate over all macro blocks which overlap the given range.
|
// Iterate over all macro blocks which overlap the given range.
|
||||||
u32 range_mask = ~(BLOCK_RANGE_MAP_ELEMENTS - 1);
|
auto start = block_range_map.lower_bound(address & BLOCK_RANGE_MAP_MASK);
|
||||||
auto start = block_range_map.lower_bound(address & range_mask);
|
|
||||||
auto end = block_range_map.lower_bound(address + length);
|
auto end = block_range_map.lower_bound(address + length);
|
||||||
while (start != end)
|
while (start != end)
|
||||||
{
|
{
|
||||||
|
@ -348,8 +346,8 @@ void JitBaseBlockCache::ErasePhysicalRange(u32 address, u32 length)
|
||||||
// If the block overlaps, also remove all other occupied slots in the other macro blocks.
|
// If the block overlaps, also remove all other occupied slots in the other macro blocks.
|
||||||
// This will leak empty macro blocks, but they may be reused or cleared later on.
|
// This will leak empty macro blocks, but they may be reused or cleared later on.
|
||||||
for (u32 addr : block->physical_addresses)
|
for (u32 addr : block->physical_addresses)
|
||||||
if ((addr & range_mask) != start->first)
|
if ((addr & BLOCK_RANGE_MAP_MASK) != start->first)
|
||||||
block_range_map[addr & range_mask].erase(block);
|
block_range_map[addr & BLOCK_RANGE_MAP_MASK].erase(block);
|
||||||
|
|
||||||
// And remove the block.
|
// And remove the block.
|
||||||
DestroyBlock(*block);
|
DestroyBlock(*block);
|
||||||
|
@ -379,6 +377,23 @@ void JitBaseBlockCache::ErasePhysicalRange(u32 address, u32 length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JitBaseBlockCache::EraseSingleBlock(const JitBlock& block)
|
||||||
|
{
|
||||||
|
const auto equal_range = block_map.equal_range(block.physicalAddress);
|
||||||
|
const auto block_map_iter = std::ranges::find(equal_range.first, equal_range.second, &block,
|
||||||
|
[](const auto& kv) { return &kv.second; });
|
||||||
|
if (block_map_iter == equal_range.second) [[unlikely]]
|
||||||
|
return;
|
||||||
|
|
||||||
|
JitBlock& mutable_block = block_map_iter->second;
|
||||||
|
|
||||||
|
for (const u32 addr : mutable_block.physical_addresses)
|
||||||
|
block_range_map[addr & BLOCK_RANGE_MAP_MASK].erase(&mutable_block);
|
||||||
|
|
||||||
|
DestroyBlock(mutable_block);
|
||||||
|
block_map.erase(block_map_iter); // The original JitBlock reference is now dangling.
|
||||||
|
}
|
||||||
|
|
||||||
u32* JitBaseBlockCache::GetBlockBitSet() const
|
u32* JitBaseBlockCache::GetBlockBitSet() const
|
||||||
{
|
{
|
||||||
return valid_block.m_valid_block.get();
|
return valid_block.m_valid_block.get();
|
||||||
|
|
|
@ -180,6 +180,7 @@ public:
|
||||||
void InvalidateICache(u32 address, u32 length, bool forced);
|
void InvalidateICache(u32 address, u32 length, bool forced);
|
||||||
void InvalidateICacheLine(u32 address);
|
void InvalidateICacheLine(u32 address);
|
||||||
void ErasePhysicalRange(u32 address, u32 length);
|
void ErasePhysicalRange(u32 address, u32 length);
|
||||||
|
void EraseSingleBlock(const JitBlock& block);
|
||||||
|
|
||||||
u32* GetBlockBitSet() const;
|
u32* GetBlockBitSet() const;
|
||||||
|
|
||||||
|
@ -213,7 +214,7 @@ private:
|
||||||
// Range of overlapping code indexed by a masked physical address.
|
// Range of overlapping code indexed by a masked physical address.
|
||||||
// This is used for invalidation of memory regions. The range is grouped
|
// This is used for invalidation of memory regions. The range is grouped
|
||||||
// in macro blocks of each 0x100 bytes.
|
// in macro blocks of each 0x100 bytes.
|
||||||
static constexpr u32 BLOCK_RANGE_MAP_ELEMENTS = 0x100;
|
static constexpr u32 BLOCK_RANGE_MAP_MASK = ~(0x100 - 1);
|
||||||
std::map<u32, std::unordered_set<JitBlock*>> block_range_map;
|
std::map<u32, std::unordered_set<JitBlock*>> block_range_map;
|
||||||
|
|
||||||
// This bitsets shows which cachelines overlap with any blocks.
|
// This bitsets shows which cachelines overlap with any blocks.
|
||||||
|
|
|
@ -263,6 +263,12 @@ void JitInterface::ClearSafe()
|
||||||
m_jit->GetBlockCache()->Clear();
|
m_jit->GetBlockCache()->Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JitInterface::EraseSingleBlock(const JitBlock& block)
|
||||||
|
{
|
||||||
|
if (m_jit)
|
||||||
|
m_jit->EraseSingleBlock(block);
|
||||||
|
}
|
||||||
|
|
||||||
void JitInterface::InvalidateICache(u32 address, u32 size, bool forced)
|
void JitInterface::InvalidateICache(u32 address, u32 size, bool forced)
|
||||||
{
|
{
|
||||||
if (m_jit)
|
if (m_jit)
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
class CPUCoreBase;
|
class CPUCoreBase;
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
class JitBase;
|
class JitBase;
|
||||||
|
struct JitBlock;
|
||||||
|
|
||||||
namespace Core
|
namespace Core
|
||||||
{
|
{
|
||||||
|
@ -72,6 +73,11 @@ public:
|
||||||
// the JIT'ed code.
|
// the JIT'ed code.
|
||||||
void ClearSafe();
|
void ClearSafe();
|
||||||
|
|
||||||
|
// DolphinQt's JITWidget needs EraseSingleBlock. Nothing else (from outside of the Core) should
|
||||||
|
// use it, or else JitBlockTableModel will contain a dangling reference. If something else from
|
||||||
|
// outside of the Core *must* use this, consider reworking the logic in JITWidget.
|
||||||
|
void EraseSingleBlock(const JitBlock& block);
|
||||||
|
|
||||||
// If "forced" is true, a recompile is being requested on code that hasn't been modified.
|
// If "forced" is true, a recompile is being requested on code that hasn't been modified.
|
||||||
void InvalidateICache(u32 address, u32 size, bool forced);
|
void InvalidateICache(u32 address, u32 size, bool forced);
|
||||||
void InvalidateICacheLine(u32 address);
|
void InvalidateICacheLine(u32 address);
|
||||||
|
|
|
@ -40,6 +40,7 @@ public:
|
||||||
// JitBase methods
|
// JitBase methods
|
||||||
JitBaseBlockCache* GetBlockCache() override { return nullptr; }
|
JitBaseBlockCache* GetBlockCache() override { return nullptr; }
|
||||||
void Jit(u32 em_address) override {}
|
void Jit(u32 em_address) override {}
|
||||||
|
void EraseSingleBlock(const JitBlock&) override {}
|
||||||
const CommonAsmRoutinesBase* GetAsmRoutines() override { return nullptr; }
|
const CommonAsmRoutinesBase* GetAsmRoutines() override { return nullptr; }
|
||||||
virtual bool HandleFault(uintptr_t access_address, SContext* ctx) override
|
virtual bool HandleFault(uintptr_t access_address, SContext* ctx) override
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue