From 814f29b25b9e6ea6a55ddcb1fe7d02f7627dec65 Mon Sep 17 00:00:00 2001 From: degasus Date: Mon, 11 Jul 2016 18:23:58 +0200 Subject: [PATCH] JitCache: Implement block unlinking. --- .../Core/Core/PowerPC/CachedInterpreter.cpp | 8 ---- Source/Core/Core/PowerPC/CachedInterpreter.h | 7 +-- Source/Core/Core/PowerPC/JitArm64/Jit.cpp | 1 - .../Core/PowerPC/JitArm64/JitArm64Cache.cpp | 35 +++++++++------ .../Core/PowerPC/JitArm64/JitArm64Cache.h | 4 +- .../Core/Core/PowerPC/JitCommon/JitCache.cpp | 43 +++++++++++++------ Source/Core/Core/PowerPC/JitCommon/JitCache.h | 9 ++-- 7 files changed, 58 insertions(+), 49 deletions(-) diff --git a/Source/Core/Core/PowerPC/CachedInterpreter.cpp b/Source/Core/Core/PowerPC/CachedInterpreter.cpp index 8f63a2381c..5a560d9d24 100644 --- a/Source/Core/Core/PowerPC/CachedInterpreter.cpp +++ b/Source/Core/Core/PowerPC/CachedInterpreter.cpp @@ -212,11 +212,3 @@ void CachedInterpreter::ClearCache() JitBaseBlockCache::Clear(); UpdateMemoryOptions(); } - -void CachedInterpreter::WriteDestroyBlock(const u8* location, u32 address) -{ -} - -void CachedInterpreter::WriteLinkBlock(u8* location, const JitBlock& block) -{ -} diff --git a/Source/Core/Core/PowerPC/CachedInterpreter.h b/Source/Core/Core/PowerPC/CachedInterpreter.h index d43fa7e9ff..f91322eb4d 100644 --- a/Source/Core/Core/PowerPC/CachedInterpreter.h +++ b/Source/Core/Core/PowerPC/CachedInterpreter.h @@ -28,11 +28,8 @@ public: JitBaseBlockCache* GetBlockCache() override { return this; } const char* GetName() override { return "Cached Interpreter"; } - void WriteLinkBlock(u8* location, const JitBlock& block) override; - - void WriteDestroyBlock(const u8* location, u32 address) override; - - const CommonAsmRoutinesBase* GetAsmRoutines() override { return nullptr; }; + void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) override {} + const CommonAsmRoutinesBase* GetAsmRoutines() override { return nullptr; } private: struct Instruction { diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index 1139a8dfeb..d615248083 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -196,7 +196,6 @@ void JitArm64::WriteExit(u32 destination) linkData.linkStatus = false; b->linkData.push_back(linkData); - // the code generated in JitArm64BlockCache::WriteDestroyBlock must fit in this block MOVI2R(DISPATCHER_PC, destination); B(dispatcher); } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.cpp index 7a52d869f3..3a00f13e89 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.cpp @@ -7,32 +7,39 @@ #include "Core/PowerPC/JitArm64/JitArm64Cache.h" #include "Core/PowerPC/JitInterface.h" -void JitArm64BlockCache::WriteLinkBlock(u8* location, const JitBlock& block) +void JitArm64BlockCache::WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) { + u8* location = source.exitPtrs; ARM64XEmitter emit(location); - // Are we able to jump directly to the normal entry? - s64 distance = ((s64)block.normalEntry - (s64)location) >> 2; - if (distance >= -0x40000 && distance <= 0x3FFFF) + if (dest) { - emit.B(CC_LE, block.normalEntry); + // Are we able to jump directly to the normal entry? + s64 distance = ((s64)dest->normalEntry - (s64)location) >> 2; + if (distance >= -0x40000 && distance <= 0x3FFFF) + { + emit.B(CC_LE, dest->normalEntry); + } - // We can't write DISPATCHER_PC here, as block linking may only use 8 bytes. - // So we'll hit two jumps when calling Advance. - emit.B(block.checkedEntry); + // Use the checked entry if either downcount is smaller zero, + // or if we're not able to inline the downcount check here. + emit.B(dest->checkedEntry); } else { - emit.B(block.checkedEntry); + emit.MOVI2R(DISPATCHER_PC, source.exitAddress); + emit.B(jit->GetAsmRoutines()->dispatcher); } emit.FlushIcache(); } -void JitArm64BlockCache::WriteDestroyBlock(const u8* location, u32 address) +void JitArm64BlockCache::WriteDestroyBlock(const JitBlock& block) { - // must fit within the code generated in JitArm64::WriteExit - ARM64XEmitter emit((u8*)location); - emit.MOVI2R(DISPATCHER_PC, address); - emit.B(jit->GetAsmRoutines()->dispatcher); + // Only clear the entry points as we might still be within this block. + ARM64XEmitter emit((u8*)block.checkedEntry); + + while (emit.GetWritableCodePtr() <= block.normalEntry) + emit.BRK(0x123); + emit.FlushIcache(); } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.h b/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.h index 0b29a9b8d8..7d5ee9fb49 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.h +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64Cache.h @@ -11,6 +11,6 @@ typedef void (*CompiledCode)(); class JitArm64BlockCache : public JitBaseBlockCache { private: - void WriteLinkBlock(u8* location, const JitBlock& block); - void WriteDestroyBlock(const u8* location, u32 address); + void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) override; + void WriteDestroyBlock(const JitBlock& block) override; }; diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp index 659ec20d31..d3c0be127b 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.cpp @@ -134,7 +134,6 @@ void JitBaseBlockCache::FinalizeBlock(int block_num, bool block_link, const u8* } LinkBlock(block_num); - LinkBlockExits(block_num); } JitRegister::Register(b.checkedEntry, b.codeSize, "JIT_PPC_%08x", b.physicalAddress); @@ -216,8 +215,11 @@ void JitBaseBlockCache::LinkBlockExits(int i) int destinationBlock = GetBlockNumberFromStartAddress(e.exitAddress, b.msrBits); if (destinationBlock != -1) { - WriteLinkBlock(e.exitPtrs, blocks[destinationBlock]); - e.linkStatus = true; + if (!blocks[destinationBlock].invalid) + { + WriteLinkBlock(e, &blocks[destinationBlock]); + e.linkStatus = true; + } } } } @@ -251,10 +253,12 @@ void JitBaseBlockCache::UnlinkBlock(int i) for (auto& e : sourceBlock.linkData) { if (e.exitAddress == b.effectiveAddress) + { + WriteLinkBlock(e, nullptr); e.linkStatus = false; + } } } - links_to.erase(b.effectiveAddress); } void JitBaseBlockCache::DestroyBlock(int block_num, bool invalidate) @@ -277,10 +281,18 @@ void JitBaseBlockCache::DestroyBlock(int block_num, bool invalidate) UnlinkBlock(block_num); - // Send anyone who tries to run this block back to the dispatcher. - // Not entirely ideal, but .. pretty good. - // Spurious entrances from previously linked blocks can only come through checkedEntry - WriteDestroyBlock(b.checkedEntry, b.effectiveAddress); + // Delete linking adresses + auto it = links_to.equal_range(b.effectiveAddress); + while (it.first != it.second) + { + if (it.first->second == block_num) + it.first = links_to.erase(it.first); + else + it.first++; + } + + // Raise an signal if we are going to call this block again + WriteDestroyBlock(b); } void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool forced) @@ -327,9 +339,10 @@ void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool for } } -void JitBlockCache::WriteLinkBlock(u8* location, const JitBlock& block) +void JitBlockCache::WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) { - const u8* address = block.checkedEntry; + u8* location = source.exitPtrs; + const u8* address = dest ? dest->checkedEntry : jit->GetAsmRoutines()->dispatcher; XEmitter emit(location); if (*location == 0xE8) { @@ -348,9 +361,11 @@ void JitBlockCache::WriteLinkBlock(u8* location, const JitBlock& block) } } -void JitBlockCache::WriteDestroyBlock(const u8* location, u32 address) +void JitBlockCache::WriteDestroyBlock(const JitBlock& block) { - XEmitter emit((u8*)location); - emit.MOV(32, PPCSTATE(pc), Imm32(address)); - emit.JMP(jit->GetAsmRoutines()->dispatcher, true); + // Only clear the entry points as we might still be within this block. + XEmitter emit((u8*)block.checkedEntry); + emit.INT3(); + XEmitter emit2((u8*)block.normalEntry); + emit2.INT3(); } diff --git a/Source/Core/Core/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/PowerPC/JitCommon/JitCache.h index 91c4f8b78c..aeae78e696 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitCache.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitCache.h @@ -149,9 +149,8 @@ private: // Fast but risky block lookup based on iCache. int& FastLookupEntryForAddress(u32 address) { return iCache[(address >> 2) & iCache_Mask]; } // Virtual for overloaded - virtual void WriteLinkBlock(u8* location, const JitBlock& block) = 0; - virtual void WriteDestroyBlock(const u8* location, u32 address) = 0; - + virtual void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) = 0; + virtual void WriteDestroyBlock(const JitBlock& block) {} public: JitBaseBlockCache() : num_blocks(0) {} virtual ~JitBaseBlockCache() {} @@ -190,6 +189,6 @@ public: class JitBlockCache : public JitBaseBlockCache { private: - void WriteLinkBlock(u8* location, const JitBlock& block) override; - void WriteDestroyBlock(const u8* location, u32 address) override; + void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) override; + void WriteDestroyBlock(const JitBlock& block) override; };