JitCache: Store the JitBlock in the std::map.

This commit is contained in:
degasus 2017-01-11 22:41:30 +01:00
parent 43cdbab515
commit 830ae6a2c1
6 changed files with 34 additions and 68 deletions

View File

@ -123,7 +123,7 @@ static bool CheckDSI(u32 data)
void CachedInterpreter::Jit(u32 address) void CachedInterpreter::Jit(u32 address)
{ {
if (m_code.size() >= CODE_SIZE / sizeof(Instruction) - 0x1000 || m_block_cache.IsFull() || if (m_code.size() >= CODE_SIZE / sizeof(Instruction) - 0x1000 ||
SConfig::GetInstance().bJITNoBlockCache) SConfig::GetInstance().bJITNoBlockCache)
{ {
ClearCache(); ClearCache();

View File

@ -543,7 +543,7 @@ void Jit64::Jit(u32 em_address)
} }
if (IsAlmostFull() || m_far_code.IsAlmostFull() || trampolines.IsAlmostFull() || if (IsAlmostFull() || m_far_code.IsAlmostFull() || trampolines.IsAlmostFull() ||
blocks.IsFull() || SConfig::GetInstance().bJITNoBlockCache) SConfig::GetInstance().bJITNoBlockCache)
{ {
ClearCache(); ClearCache();
} }

View File

@ -466,7 +466,7 @@ void JitIL::Trace()
void JitIL::Jit(u32 em_address) void JitIL::Jit(u32 em_address)
{ {
if (IsAlmostFull() || m_far_code.IsAlmostFull() || trampolines.IsAlmostFull() || if (IsAlmostFull() || m_far_code.IsAlmostFull() || trampolines.IsAlmostFull() ||
blocks.IsFull() || SConfig::GetInstance().bJITNoBlockCache) SConfig::GetInstance().bJITNoBlockCache)
{ {
ClearCache(); ClearCache();
} }

View File

@ -368,8 +368,7 @@ void JitArm64::SingleStep()
void JitArm64::Jit(u32) void JitArm64::Jit(u32)
{ {
if (IsAlmostFull() || farcode.IsAlmostFull() || blocks.IsFull() || if (IsAlmostFull() || farcode.IsAlmostFull() || SConfig::GetInstance().bJITNoBlockCache)
SConfig::GetInstance().bJITNoBlockCache)
{ {
ClearCache(); ClearCache();
} }

View File

@ -47,14 +47,11 @@ void JitBaseBlockCache::Init()
s_clear_jit_cache_thread_safe = CoreTiming::RegisterEvent("clearJitCache", ClearCacheThreadSafe); s_clear_jit_cache_thread_safe = CoreTiming::RegisterEvent("clearJitCache", ClearCacheThreadSafe);
JitRegister::Init(SConfig::GetInstance().m_perfDir); JitRegister::Init(SConfig::GetInstance().m_perfDir);
iCache.fill(nullptr);
Clear(); Clear();
} }
void JitBaseBlockCache::Shutdown() void JitBaseBlockCache::Shutdown()
{ {
num_blocks = 1;
JitRegister::Shutdown(); JitRegister::Shutdown();
} }
@ -63,26 +60,21 @@ void JitBaseBlockCache::Shutdown()
void JitBaseBlockCache::Clear() void JitBaseBlockCache::Clear()
{ {
#if defined(_DEBUG) || defined(DEBUGFAST) #if defined(_DEBUG) || defined(DEBUGFAST)
if (IsFull())
Core::DisplayMessage("Clearing block cache.", 3000);
else
Core::DisplayMessage("Clearing code cache.", 3000); Core::DisplayMessage("Clearing code cache.", 3000);
#endif #endif
m_jit.js.fifoWriteAddresses.clear(); m_jit.js.fifoWriteAddresses.clear();
m_jit.js.pairedQuantizeAddresses.clear(); m_jit.js.pairedQuantizeAddresses.clear();
for (int i = 1; i < num_blocks; i++) for (auto& e : start_block_map)
{ {
if (!block.invalid) DestroyBlock(e.second);
DestroyBlock(blocks[i]);
} }
start_block_map.clear();
links_to.clear(); links_to.clear();
block_map.clear(); block_map.clear();
valid_block.ClearAll(); valid_block.ClearAll();
num_blocks = 1; iCache.fill(nullptr);
blocks[0].msrBits = 0xFFFFFFFF;
blocks[0].invalid = true;
} }
void JitBaseBlockCache::Reset() void JitBaseBlockCache::Reset()
@ -96,11 +88,6 @@ void JitBaseBlockCache::SchedulateClearCacheThreadSafe()
CoreTiming::ScheduleEvent(0, s_clear_jit_cache_thread_safe, 0, CoreTiming::FromThread::NON_CPU); CoreTiming::ScheduleEvent(0, s_clear_jit_cache_thread_safe, 0, CoreTiming::FromThread::NON_CPU);
} }
bool JitBaseBlockCache::IsFull() const
{
return num_blocks >= MAX_NUM_BLOCKS - 1;
}
JitBlock** JitBaseBlockCache::GetICache() JitBlock** JitBaseBlockCache::GetICache()
{ {
return iCache.data(); return iCache.data();
@ -108,26 +95,36 @@ JitBlock** JitBaseBlockCache::GetICache()
void JitBaseBlockCache::RunOnBlocks(std::function<void(const JitBlock&)> f) void JitBaseBlockCache::RunOnBlocks(std::function<void(const JitBlock&)> f)
{ {
for (int i = 0; i < num_blocks; i++) for (const auto& e : start_block_map)
f(blocks[i]); f(e.second);
} }
JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address) JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address)
{ {
JitBlock& b = blocks[num_blocks]; u32 physicalAddress = PowerPC::JitCache_TranslateAddress(em_address).address;
b.invalid = false; JitBlock& b = start_block_map.emplace(physicalAddress, JitBlock())->second;
b.effectiveAddress = em_address; b.effectiveAddress = em_address;
b.physicalAddress = PowerPC::JitCache_TranslateAddress(em_address).address; b.physicalAddress = physicalAddress;
b.msrBits = MSR & JIT_CACHE_MSR_MASK; b.msrBits = MSR & JIT_CACHE_MSR_MASK;
b.linkData.clear(); b.linkData.clear();
b.in_icache = 0; b.in_icache = 0;
num_blocks++; // commit the current block
return &b; 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)
start_block_map.erase(iter.first);
else
iter.first++;
}
}
void JitBaseBlockCache::FinalizeBlock(JitBlock& block, bool block_link, const u8* code_ptr) void JitBaseBlockCache::FinalizeBlock(JitBlock& block, bool block_link, const u8* code_ptr)
{ {
start_block_map.emplace(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;
@ -168,8 +165,8 @@ JitBlock* JitBaseBlockCache::GetBlockFromStartAddress(u32 addr, u32 msr)
auto iter = start_block_map.equal_range(translated_addr); auto iter = start_block_map.equal_range(translated_addr);
for (; iter.first != iter.second; iter.first++) for (; iter.first != iter.second; iter.first++)
{ {
JitBlock& b = *iter.first->second; JitBlock& b = iter.first->second;
if (!b.invalid && b.effectiveAddress == addr && b.msrBits == (msr & JIT_CACHE_MSR_MASK)) if (b.effectiveAddress == addr && b.msrBits == (msr & JIT_CACHE_MSR_MASK))
return &b; return &b;
} }
@ -214,7 +211,9 @@ void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool for
auto it = block_map.lower_bound(std::make_pair(pAddr, 0)); auto it = block_map.lower_bound(std::make_pair(pAddr, 0));
while (it != block_map.end() && it->first.second < pAddr + length) while (it != block_map.end() && it->first.second < pAddr + length)
{ {
DestroyBlock(*it->second); JitBlock* block = it->second;
DestroyBlock(*block);
FreeBlock(block);
it = block_map.erase(it); it = block_map.erase(it);
} }
@ -250,17 +249,12 @@ void JitBaseBlockCache::WriteDestroyBlock(const JitBlock& block)
void JitBaseBlockCache::LinkBlockExits(JitBlock& block) void JitBaseBlockCache::LinkBlockExits(JitBlock& block)
{ {
if (block.invalid)
{
// This block is dead. Don't relink it.
return;
}
for (auto& e : block.linkData) for (auto& e : block.linkData)
{ {
if (!e.linkStatus) if (!e.linkStatus)
{ {
JitBlock* destinationBlock = GetBlockFromStartAddress(e.exitAddress, block.msrBits); JitBlock* destinationBlock = GetBlockFromStartAddress(e.exitAddress, block.msrBits);
if (destinationBlock && !destinationBlock->invalid) if (destinationBlock)
{ {
WriteLinkBlock(e, destinationBlock); WriteLinkBlock(e, destinationBlock);
e.linkStatus = true; e.linkStatus = true;
@ -305,24 +299,9 @@ void JitBaseBlockCache::UnlinkBlock(const JitBlock& block)
void JitBaseBlockCache::DestroyBlock(JitBlock& block) void JitBaseBlockCache::DestroyBlock(JitBlock& block)
{ {
if (block.invalid)
{
PanicAlert("Invalidating invalid block %p", &block);
return;
}
block.invalid = true;
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

@ -47,11 +47,6 @@ struct JitBlock
u32 originalSize; u32 originalSize;
int runCount; // for profiling. int runCount; // for profiling.
// Whether this struct refers to a valid block. This is mostly useful as
// a debugging aid.
// FIXME: Change current users of invalid bit to assertions?
bool invalid;
// Information about exits to a known address from this block. // Information about exits to a known address from this block.
// This is used to implement block linking. // This is used to implement block linking.
struct LinkData struct LinkData
@ -112,7 +107,6 @@ public:
// is valid (MSR.IR and MSR.DR, the address translation bits). // is valid (MSR.IR and MSR.DR, the address translation bits).
static constexpr u32 JIT_CACHE_MSR_MASK = 0x30; static constexpr u32 JIT_CACHE_MSR_MASK = 0x30;
static constexpr int MAX_NUM_BLOCKS = 65536 * 2;
static constexpr u32 iCache_Num_Elements = 0x10000; static constexpr u32 iCache_Num_Elements = 0x10000;
static constexpr u32 iCache_Mask = iCache_Num_Elements - 1; static constexpr u32 iCache_Mask = iCache_Num_Elements - 1;
@ -125,13 +119,12 @@ public:
void Reset(); void Reset();
void SchedulateClearCacheThreadSafe(); void SchedulateClearCacheThreadSafe();
bool IsFull() const;
// Code Cache // Code Cache
JitBlock** GetICache(); JitBlock** GetICache();
void RunOnBlocks(std::function<void(const JitBlock&)> f); void RunOnBlocks(std::function<void(const JitBlock&)> f);
JitBlock* AllocateBlock(u32 em_address); JitBlock* AllocateBlock(u32 em_address);
void FreeBlock(JitBlock* block);
void FinalizeBlock(JitBlock& block, bool block_link, const u8* code_ptr); void FinalizeBlock(JitBlock& block, bool block_link, const u8* code_ptr);
// Look for the block in the slow but accurate way. // Look for the block in the slow but accurate way.
@ -166,11 +159,6 @@ private:
// Fast but risky block lookup based on iCache. // Fast but risky block lookup based on iCache.
size_t FastLookupEntryForAddress(u32 address); size_t FastLookupEntryForAddress(u32 address);
// 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<JitBlock, MAX_NUM_BLOCKS> blocks; // number -> JitBlock
int num_blocks = 1;
// links_to hold all exit points of all valid blocks in a reverse way. // links_to hold all exit points of all valid blocks in a reverse way.
// It is used to query all blocks which links to an address. // It is used to query all blocks which links to an address.
std::multimap<u32, JitBlock*> links_to; // destination_PC -> number std::multimap<u32, JitBlock*> links_to; // destination_PC -> number
@ -182,7 +170,7 @@ private:
// 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. // TODO: This is redundant with block_map.
std::multimap<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.