diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp index 016e214fd4..e358f473e4 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp @@ -35,11 +35,6 @@ static void ClearCacheThreadSafe(u64 userdata, s64 cyclesdata) JitInterface::ClearCache(); } -bool JitBaseBlockCache::IsFull() const -{ - return GetNumBlocks() >= MAX_NUM_BLOCKS - 1; -} - void JitBaseBlockCache::Init() { s_clear_jit_cache_thread_safe = CoreTiming::RegisterEvent("clearJitCache", ClearCacheThreadSafe); @@ -82,15 +77,20 @@ void JitBaseBlockCache::Clear() blocks[0].invalid = true; } +void JitBaseBlockCache::Reset() +{ + Shutdown(); + Init(); +} + void JitBaseBlockCache::SchedulateClearCacheThreadSafe() { CoreTiming::ScheduleEvent(0, s_clear_jit_cache_thread_safe, 0, CoreTiming::FromThread::NON_CPU); } -void JitBaseBlockCache::Reset() +bool JitBaseBlockCache::IsFull() const { - Shutdown(); - Init(); + return GetNumBlocks() >= MAX_NUM_BLOCKS - 1; } JitBlock* JitBaseBlockCache::GetBlock(int no) @@ -180,20 +180,6 @@ int JitBaseBlockCache::GetBlockNumberFromStartAddress(u32 addr, u32 msr) return block_num; } -void JitBaseBlockCache::MoveBlockIntoFastCache(u32 addr, u32 msr) -{ - int block_num = GetBlockNumberFromStartAddress(addr, msr); - if (block_num < 0) - { - Jit(addr); - } - else - { - FastLookupEntryForAddress(addr) = block_num; - LinkBlock(block_num); - } -} - const u8* JitBaseBlockCache::Dispatch() { int block_num = FastLookupEntryForAddress(PC); @@ -208,6 +194,54 @@ const u8* JitBaseBlockCache::Dispatch() return blocks[block_num].normalEntry; } +void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool forced) +{ + auto translated = PowerPC::JitCache_TranslateAddress(address); + if (!translated.valid) + return; + u32 pAddr = translated.address; + + // Optimize the common case of length == 32 which is used by Interpreter::dcb* + bool destroy_block = true; + if (length == 32) + { + if (!valid_block.Test(pAddr / 32)) + destroy_block = false; + else + valid_block.Clear(pAddr / 32); + } + + // 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) + { + DestroyBlock(it->second, true); + it = block_map.erase(it); + } + + // If the code was actually modified, we need to clear the relevant entries from the + // FIFO write address cache, so we don't end up with FIFO checks in places they shouldn't + // be (this can clobber flags, and thus break any optimization that relies on flags + // being in the right place between instructions). + if (!forced) + { + for (u32 i = address; i < address + length; i += 4) + { + g_jit->js.fifoWriteAddresses.erase(i); + g_jit->js.pairedQuantizeAddresses.erase(i); + } + } + } +} + +void JitBaseBlockCache::WriteDestroyBlock(const JitBlock& block) +{ +} + // Block linker // Make sure to have as many blocks as possible compiled before calling this // It's O(N), so it's fast :) @@ -309,46 +343,16 @@ void JitBaseBlockCache::DestroyBlock(int block_num, bool invalidate) WriteDestroyBlock(b); } -void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool forced) +void JitBaseBlockCache::MoveBlockIntoFastCache(u32 addr, u32 msr) { - auto translated = PowerPC::JitCache_TranslateAddress(address); - if (!translated.valid) - return; - u32 pAddr = translated.address; - - // Optimize the common case of length == 32 which is used by Interpreter::dcb* - bool destroy_block = true; - if (length == 32) + int block_num = GetBlockNumberFromStartAddress(addr, msr); + if (block_num < 0) { - if (!valid_block.Test(pAddr / 32)) - destroy_block = false; - else - valid_block.Clear(pAddr / 32); + Jit(addr); } - - // destroy JIT blocks - // !! this works correctly under assumption that any two overlapping blocks end at the same - // address - if (destroy_block) + else { - auto it = block_map.lower_bound(std::make_pair(pAddr, 0)); - while (it != block_map.end() && it->first.second < pAddr + length) - { - DestroyBlock(it->second, true); - it = block_map.erase(it); - } - - // If the code was actually modified, we need to clear the relevant entries from the - // FIFO write address cache, so we don't end up with FIFO checks in places they shouldn't - // be (this can clobber flags, and thus break any optimization that relies on flags - // being in the right place between instructions). - if (!forced) - { - for (u32 i = address; i < address + length; i += 4) - { - g_jit->js.fifoWriteAddresses.erase(i); - g_jit->js.pairedQuantizeAddresses.erase(i); - } - } + FastLookupEntryForAddress(addr) = block_num; + LinkBlock(block_num); } } diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/PowerPC/JitCommon/JitCache.h index 0694400177..7837603a64 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.h @@ -112,7 +112,53 @@ public: static constexpr u32 iCache_Num_Elements = 0x10000; static constexpr u32 iCache_Mask = iCache_Num_Elements - 1; + JitBaseBlockCache() : num_blocks(1) {} + virtual ~JitBaseBlockCache() {} + void Init(); + void Shutdown(); + void Clear(); + void Reset(); + void SchedulateClearCacheThreadSafe(); + + bool IsFull() const; + + // Code Cache + JitBlock* GetBlock(int block_num); + JitBlock* GetBlocks() { return blocks.data(); } + int GetNumBlocks() const; + int* GetICache() { return iCache.data(); } + + int AllocateBlock(u32 em_address); + void FinalizeBlock(int block_num, bool block_link, const u8* code_ptr); + + // Look for the block in the slow but accurate way. + // This function shall be used if FastLookupEntryForAddress() failed. + int GetBlockNumberFromStartAddress(u32 em_address, u32 msr); + + // Get the normal entry for the block associated with the current program + // counter. This will JIT code if necessary. (This is the reference + // implementation; high-performance JITs will want to use a custom + // assembly version.) + const u8* Dispatch(); + + void InvalidateICache(u32 address, const u32 length, bool forced); + + u32* GetBlockBitSet() const { return valid_block.m_valid_block.get(); } + private: + virtual void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) = 0; + virtual void WriteDestroyBlock(const JitBlock& block); + + void LinkBlockExits(int i); + void LinkBlock(int i); + void UnlinkBlock(int i); + void DestroyBlock(int block_num, bool invalidate); + + void MoveBlockIntoFastCache(u32 em_address, u32 msr); + + // Fast but risky block lookup based on iCache. + int& FastLookupEntryForAddress(u32 address) { return iCache[(address >> 2) & iCache_Mask]; } + // We store the metadata of all blocks in a linear way within this array. // Note: blocks[0] must not be used as it is referenced as invalid block in iCache. std::array blocks; // number -> JitBlock @@ -138,51 +184,4 @@ private: // 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. std::array iCache; // start_addr & mask -> number - - void LinkBlockExits(int i); - void LinkBlock(int i); - void UnlinkBlock(int i); - - void DestroyBlock(int block_num, bool invalidate); - - void MoveBlockIntoFastCache(u32 em_address, u32 msr); - - // Fast but risky block lookup based on iCache. - int& FastLookupEntryForAddress(u32 address) { return iCache[(address >> 2) & iCache_Mask]; } - // Virtual for overloaded - virtual void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) = 0; - virtual void WriteDestroyBlock(const JitBlock& block) {} -public: - JitBaseBlockCache() : num_blocks(1) {} - virtual ~JitBaseBlockCache() {} - int AllocateBlock(u32 em_address); - void FinalizeBlock(int block_num, bool block_link, const u8* code_ptr); - - void Clear(); - void SchedulateClearCacheThreadSafe(); - void Init(); - void Shutdown(); - void Reset(); - - bool IsFull() const; - - // Code Cache - JitBlock* GetBlock(int block_num); - JitBlock* GetBlocks() { return blocks.data(); } - int* GetICache() { return iCache.data(); } - int GetNumBlocks() const; - - // Look for the block in the slow but accurate way. - // This function shall be used if FastLookupEntryForAddress() failed. - int GetBlockNumberFromStartAddress(u32 em_address, u32 msr); - - // Get the normal entry for the block associated with the current program - // counter. This will JIT code if necessary. (This is the reference - // implementation; high-performance JITs will want to use a custom - // assembly version.) - const u8* Dispatch(); - - void InvalidateICache(u32 address, const u32 length, bool forced); - - u32* GetBlockBitSet() const { return valid_block.m_valid_block.get(); } };