JitCache: Drop block_map.

It is only used for invalidation, and in a bad way. Just scan over all elements,
as it is still in O(n), this shouldn't matter much.
This commit is contained in:
degasus 2017-01-22 11:57:51 +01:00
parent 98311cd9f4
commit dc0fbc15f0
2 changed files with 31 additions and 38 deletions

View File

@ -36,6 +36,15 @@ static void ClearCacheThreadSafe(u64 userdata, s64 cyclesdata)
JitInterface::ClearCache(); JitInterface::ClearCache();
} }
bool JitBlock::Overlap(u32 addr, u32 length)
{
if (addr >= physicalAddress + originalSize)
return false;
if (physicalAddress >= addr + length)
return false;
return true;
}
JitBaseBlockCache::JitBaseBlockCache(JitBase& jit) : m_jit{jit} JitBaseBlockCache::JitBaseBlockCache(JitBase& jit) : m_jit{jit}
{ {
} }
@ -64,13 +73,12 @@ void JitBaseBlockCache::Clear()
#endif #endif
m_jit.js.fifoWriteAddresses.clear(); m_jit.js.fifoWriteAddresses.clear();
m_jit.js.pairedQuantizeAddresses.clear(); m_jit.js.pairedQuantizeAddresses.clear();
for (auto& e : start_block_map) for (auto& e : block_map)
{ {
DestroyBlock(e.second); DestroyBlock(e.second);
} }
start_block_map.clear();
links_to.clear();
block_map.clear(); block_map.clear();
links_to.clear();
valid_block.ClearAll(); valid_block.ClearAll();
@ -95,14 +103,14 @@ JitBlock** JitBaseBlockCache::GetFastBlockMap()
void JitBaseBlockCache::RunOnBlocks(std::function<void(const JitBlock&)> f) void JitBaseBlockCache::RunOnBlocks(std::function<void(const JitBlock&)> f)
{ {
for (const auto& e : start_block_map) for (const auto& e : block_map)
f(e.second); f(e.second);
} }
JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address) JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address)
{ {
u32 physicalAddress = PowerPC::JitCache_TranslateAddress(em_address).address; u32 physicalAddress = PowerPC::JitCache_TranslateAddress(em_address).address;
JitBlock& b = start_block_map.emplace(physicalAddress, JitBlock())->second; JitBlock& b = block_map.emplace(physicalAddress, JitBlock())->second;
b.effectiveAddress = em_address; b.effectiveAddress = em_address;
b.physicalAddress = physicalAddress; b.physicalAddress = physicalAddress;
b.msrBits = MSR & JIT_CACHE_MSR_MASK; b.msrBits = MSR & JIT_CACHE_MSR_MASK;
@ -111,18 +119,6 @@ JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address)
return &b; return &b;
} }
void JitBaseBlockCache::FreeBlock(JitBlock* block)
{
auto iter = start_block_map.equal_range(block->physicalAddress);
while (iter.first != iter.second)
{
if (&iter.first->second == block)
iter.first = start_block_map.erase(iter.first);
else
iter.first++;
}
}
void JitBaseBlockCache::FinalizeBlock(JitBlock& block, bool block_link, const u8* code_ptr) void JitBaseBlockCache::FinalizeBlock(JitBlock& block, bool block_link, const u8* code_ptr)
{ {
size_t index = FastLookupIndexForAddress(block.effectiveAddress); size_t index = FastLookupIndexForAddress(block.effectiveAddress);
@ -134,8 +130,6 @@ void JitBaseBlockCache::FinalizeBlock(JitBlock& block, bool block_link, const u8
for (u32 addr = pAddr / 32; addr <= (pAddr + (block.originalSize - 1) * 4) / 32; ++addr) for (u32 addr = pAddr / 32; addr <= (pAddr + (block.originalSize - 1) * 4) / 32; ++addr)
valid_block.Set(addr); valid_block.Set(addr);
block_map.emplace(std::make_pair(pAddr + 4 * block.originalSize - 1, pAddr), &block);
if (block_link) if (block_link)
{ {
for (const auto& e : block.linkData) for (const auto& e : block.linkData)
@ -162,7 +156,7 @@ JitBlock* JitBaseBlockCache::GetBlockFromStartAddress(u32 addr, u32 msr)
translated_addr = translated.address; translated_addr = translated.address;
} }
auto iter = start_block_map.equal_range(translated_addr); auto iter = block_map.equal_range(translated_addr);
for (; iter.first != iter.second; iter.first++) for (; iter.first != iter.second; iter.first++)
{ {
JitBlock& b = iter.first->second; JitBlock& b = iter.first->second;
@ -204,17 +198,20 @@ void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool for
} }
// destroy JIT blocks // destroy JIT blocks
// !! this works correctly under assumption that any two overlapping blocks end at the same
// address
if (destroy_block) if (destroy_block)
{ {
auto it = block_map.lower_bound(std::make_pair(pAddr, 0)); auto iter = block_map.begin();
while (it != block_map.end() && it->first.second < pAddr + length) while (iter != block_map.end())
{ {
JitBlock* block = it->second; if (iter->second.Overlap(pAddr, length))
DestroyBlock(*block); {
FreeBlock(block); DestroyBlock(iter->second);
it = block_map.erase(it); iter = block_map.erase(iter);
}
else
{
iter++;
}
} }
// If the code was actually modified, we need to clear the relevant entries from the // If the code was actually modified, we need to clear the relevant entries from the

View File

@ -24,6 +24,8 @@ class JitBase;
// address. // address.
struct JitBlock struct JitBlock
{ {
bool Overlap(u32 addr, u32 length);
// A special entry point for block linking; usually used to check the // A special entry point for block linking; usually used to check the
// downcount. // downcount.
const u8* checkedEntry; const u8* checkedEntry;
@ -35,8 +37,8 @@ struct JitBlock
// The MSR bits expected for this block to be valid; see JIT_CACHE_MSR_MASK. // The MSR bits expected for this block to be valid; see JIT_CACHE_MSR_MASK.
u32 msrBits; u32 msrBits;
// The physical address of the code represented by this block. // The physical address of the code represented by this block.
// Various maps in the cache are indexed by this (start_block_map, // Various maps in the cache are indexed by this (block_map
// block_map, and valid_block in particular). This is useful because of // and valid_block in particular). This is useful because of
// of the way the instruction cache works on PowerPC. // of the way the instruction cache works on PowerPC.
u32 physicalAddress; u32 physicalAddress;
// The number of bytes of JIT'ed code contained in this block. Mostly // The number of bytes of JIT'ed code contained in this block. Mostly
@ -124,7 +126,6 @@ public:
void RunOnBlocks(std::function<void(const JitBlock&)> f); void RunOnBlocks(std::function<void(const JitBlock&)> f);
JitBlock* AllocateBlock(u32 em_address); JitBlock* AllocateBlock(u32 em_address);
void FreeBlock(JitBlock* block);
void FinalizeBlock(JitBlock& block, bool block_link, const u8* code_ptr); void FinalizeBlock(JitBlock& block, bool block_link, const u8* code_ptr);
// Look for the block in the slow but accurate way. // Look for the block in the slow but accurate way.
@ -163,20 +164,15 @@ private:
// It is used to query all blocks which links to an address. // It is used to query all blocks which links to an address.
std::multimap<u32, JitBlock*> links_to; // destination_PC -> number std::multimap<u32, JitBlock*> links_to; // destination_PC -> number
// Map indexed by the physical memory location.
// It is used to invalidate blocks based on memory location.
std::multimap<std::pair<u32, u32>, JitBlock*> block_map; // (end_addr, start_addr) -> block
// Map indexed by the physical address of the entry point. // Map indexed by the physical address of the entry point.
// This is used to query the block based on the current PC in a slow way. // This is used to query the block based on the current PC in a slow way.
// TODO: This is redundant with block_map. std::multimap<u32, JitBlock> block_map; // start_addr -> block
std::multimap<u32, JitBlock> start_block_map; // start_addr -> block
// This bitsets shows which cachelines overlap with any blocks. // This bitsets shows which cachelines overlap with any blocks.
// It is used to provide a fast way to query if no icache invalidation is needed. // It is used to provide a fast way to query if no icache invalidation is needed.
ValidBlockBitSet valid_block; ValidBlockBitSet valid_block;
// This array is indexed with the masked PC and likely holds the correct block id. // This array is indexed with the masked PC and likely holds the correct block id.
// This is used as a fast cache of start_block_map used in the assembly dispatcher. // This is used as a fast cache of block_map used in the assembly dispatcher.
std::array<JitBlock*, FAST_BLOCK_MAP_ELEMENTS> fast_block_map; // start_addr & mask -> number std::array<JitBlock*, FAST_BLOCK_MAP_ELEMENTS> fast_block_map; // start_addr & mask -> number
}; };