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();
}
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}
{
}
@ -64,13 +73,12 @@ void JitBaseBlockCache::Clear()
#endif
m_jit.js.fifoWriteAddresses.clear();
m_jit.js.pairedQuantizeAddresses.clear();
for (auto& e : start_block_map)
for (auto& e : block_map)
{
DestroyBlock(e.second);
}
start_block_map.clear();
links_to.clear();
block_map.clear();
links_to.clear();
valid_block.ClearAll();
@ -95,14 +103,14 @@ JitBlock** JitBaseBlockCache::GetFastBlockMap()
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);
}
JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_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.physicalAddress = physicalAddress;
b.msrBits = MSR & JIT_CACHE_MSR_MASK;
@ -111,18 +119,6 @@ JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address)
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)
{
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)
valid_block.Set(addr);
block_map.emplace(std::make_pair(pAddr + 4 * block.originalSize - 1, pAddr), &block);
if (block_link)
{
for (const auto& e : block.linkData)
@ -162,7 +156,7 @@ JitBlock* JitBaseBlockCache::GetBlockFromStartAddress(u32 addr, u32 msr)
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++)
{
JitBlock& b = iter.first->second;
@ -204,17 +198,20 @@ void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool for
}
// destroy JIT blocks
// !! this works correctly under assumption that any two overlapping blocks end at the same
// address
if (destroy_block)
{
auto it = block_map.lower_bound(std::make_pair(pAddr, 0));
while (it != block_map.end() && it->first.second < pAddr + length)
auto iter = block_map.begin();
while (iter != block_map.end())
{
JitBlock* block = it->second;
DestroyBlock(*block);
FreeBlock(block);
it = block_map.erase(it);
if (iter->second.Overlap(pAddr, length))
{
DestroyBlock(iter->second);
iter = block_map.erase(iter);
}
else
{
iter++;
}
}
// If the code was actually modified, we need to clear the relevant entries from the

View file

@ -24,6 +24,8 @@ class JitBase;
// address.
struct JitBlock
{
bool Overlap(u32 addr, u32 length);
// A special entry point for block linking; usually used to check the
// downcount.
const u8* checkedEntry;
@ -35,8 +37,8 @@ struct JitBlock
// The MSR bits expected for this block to be valid; see JIT_CACHE_MSR_MASK.
u32 msrBits;
// The physical address of the code represented by this block.
// Various maps in the cache are indexed by this (start_block_map,
// block_map, and valid_block in particular). This is useful because of
// Various maps in the cache are indexed by this (block_map
// and valid_block in particular). This is useful because of
// of the way the instruction cache works on PowerPC.
u32 physicalAddress;
// 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);
JitBlock* AllocateBlock(u32 em_address);
void FreeBlock(JitBlock* block);
void FinalizeBlock(JitBlock& block, bool block_link, const u8* code_ptr);
// 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.
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.
// 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> start_block_map; // start_addr -> block
std::multimap<u32, JitBlock> block_map; // start_addr -> block
// 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.
ValidBlockBitSet valid_block;
// 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
};