diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp index c2ac9fd07a..1a8d1c6df9 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp @@ -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 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 diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/PowerPC/JitCommon/JitCache.h index c5aaa8d1e8..28111437fb 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.h @@ -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 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 links_to; // destination_PC -> number - // Map indexed by the physical memory location. - // It is used to invalidate blocks based on memory location. - 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. - std::multimap start_block_map; // start_addr -> block + std::multimap 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 fast_block_map; // start_addr & mask -> number };