JitCache: Use a multimap for block_map and start_block_map.

We may have duplicated entries here because of MSR mismatch. Just
store both and validate the matching one on cache access.
This commit is contained in:
degasus 2017-01-16 23:43:43 +01:00
parent 9d58127dec
commit 113d6b3b84
2 changed files with 23 additions and 25 deletions

View File

@ -9,6 +9,7 @@
// performance hit, it's not enabled by default, but it's useful for // performance hit, it's not enabled by default, but it's useful for
// locating performance issues. // locating performance issues.
#include <algorithm>
#include <cstring> #include <cstring>
#include <map> #include <map>
#include <utility> #include <utility>
@ -125,18 +126,7 @@ JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address)
void JitBaseBlockCache::FinalizeBlock(JitBlock& block, bool block_link, const u8* code_ptr) void JitBaseBlockCache::FinalizeBlock(JitBlock& block, bool block_link, const u8* code_ptr)
{ {
if (start_block_map.count(block.physicalAddress)) start_block_map.emplace(block.physicalAddress, &block);
{
// We already have a block at this address; invalidate the old block.
// This should be very rare. This will only happen if the same block
// is called both with DR/IR enabled or disabled.
WARN_LOG(DYNA_REC, "Invalidating compiled block at same address %08x", block.physicalAddress);
JitBlock& old_b = *start_block_map[block.physicalAddress];
block_map.erase(
std::make_pair(old_b.physicalAddress + 4 * old_b.originalSize - 1, old_b.physicalAddress));
DestroyBlock(old_b, true);
}
start_block_map[block.physicalAddress] = &block;
size_t icache = FastLookupEntryForAddress(block.effectiveAddress); size_t icache = FastLookupEntryForAddress(block.effectiveAddress);
iCache[icache] = &block; iCache[icache] = &block;
block.in_icache = icache; block.in_icache = icache;
@ -146,7 +136,7 @@ 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[std::make_pair(pAddr + 4 * block.originalSize - 1, pAddr)] = &block; block_map.emplace(std::make_pair(pAddr + 4 * block.originalSize - 1, pAddr), &block);
if (block_link) if (block_link)
{ {
@ -174,15 +164,15 @@ JitBlock* JitBaseBlockCache::GetBlockFromStartAddress(u32 addr, u32 msr)
translated_addr = translated.address; translated_addr = translated.address;
} }
auto map_result = start_block_map.find(translated_addr); auto iter = start_block_map.equal_range(translated_addr);
if (map_result == start_block_map.end()) for (; iter.first != iter.second; iter.first++)
return nullptr; {
JitBlock& b = *iter.first->second;
if (!b.invalid && b.effectiveAddress == addr && b.msrBits == (msr & JIT_CACHE_MSR_MASK))
return &b;
}
JitBlock* b = map_result->second; return nullptr;
if (b->invalid || b->effectiveAddress != addr ||
b->msrBits != (msr & JIT_CACHE_MSR_MASK))
return nullptr;
return b;
} }
const u8* JitBaseBlockCache::Dispatch() const u8* JitBaseBlockCache::Dispatch()
@ -321,10 +311,18 @@ void JitBaseBlockCache::DestroyBlock(JitBlock& block, bool invalidate)
return; return;
} }
block.invalid = true; block.invalid = true;
start_block_map.erase(block.physicalAddress);
if (iCache[block.in_icache] == &block) if (iCache[block.in_icache] == &block)
iCache[block.in_icache] = nullptr; iCache[block.in_icache] = nullptr;
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++;
}
UnlinkBlock(block); UnlinkBlock(block);
// Delete linking addresses // Delete linking addresses

View File

@ -177,12 +177,12 @@ private:
// Map indexed by the physical memory location. // Map indexed by the physical memory location.
// It is used to invalidate blocks based on memory location. // It is used to invalidate blocks based on memory location.
std::map<std::pair<u32, u32>, JitBlock*> block_map; // (end_addr, start_addr) -> block 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, and both should be a multimap. // TODO: This is redundant with block_map.
std::map<u32, JitBlock*> start_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.