From 113d6b3b8469143f008f4459d035337ff8b4a5ce Mon Sep 17 00:00:00 2001 From: degasus Date: Mon, 16 Jan 2017 23:43:43 +0100 Subject: [PATCH] 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. --- .../Core/Core/PowerPC/JitCommon/JitCache.cpp | 42 +++++++++---------- Source/Core/Core/PowerPC/JitCommon/JitCache.h | 6 +-- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp index f8dabcef69..309f94993e 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp @@ -9,6 +9,7 @@ // performance hit, it's not enabled by default, but it's useful for // locating performance issues. +#include #include #include #include @@ -125,18 +126,7 @@ JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address) void JitBaseBlockCache::FinalizeBlock(JitBlock& block, bool block_link, const u8* code_ptr) { - if (start_block_map.count(block.physicalAddress)) - { - // 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] = █ + start_block_map.emplace(block.physicalAddress, &block); size_t icache = FastLookupEntryForAddress(block.effectiveAddress); 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) valid_block.Set(addr); - block_map[std::make_pair(pAddr + 4 * block.originalSize - 1, pAddr)] = █ + block_map.emplace(std::make_pair(pAddr + 4 * block.originalSize - 1, pAddr), &block); if (block_link) { @@ -174,15 +164,15 @@ JitBlock* JitBaseBlockCache::GetBlockFromStartAddress(u32 addr, u32 msr) translated_addr = translated.address; } - auto map_result = start_block_map.find(translated_addr); - if (map_result == start_block_map.end()) - return nullptr; + auto iter = start_block_map.equal_range(translated_addr); + for (; iter.first != iter.second; iter.first++) + { + 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; - if (b->invalid || b->effectiveAddress != addr || - b->msrBits != (msr & JIT_CACHE_MSR_MASK)) - return nullptr; - return b; + return nullptr; } const u8* JitBaseBlockCache::Dispatch() @@ -321,10 +311,18 @@ void JitBaseBlockCache::DestroyBlock(JitBlock& block, bool invalidate) return; } block.invalid = true; - start_block_map.erase(block.physicalAddress); if (iCache[block.in_icache] == &block) 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); // Delete linking addresses diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/PowerPC/JitCommon/JitCache.h index d9f3e9944d..0fd6b84e85 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.h @@ -177,12 +177,12 @@ private: // Map indexed by the physical memory location. // It is used to invalidate blocks based on memory location. - std::map, JitBlock*> block_map; // (end_addr, start_addr) -> block + std::multimap, 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, and both should be a multimap. - std::map start_block_map; // start_addr -> block + // TODO: This is redundant with block_map. + std::multimap start_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.