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)
{
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)
{
ClearCache();

View File

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

View File

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

View File

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

View File

@ -47,14 +47,11 @@ void JitBaseBlockCache::Init()
s_clear_jit_cache_thread_safe = CoreTiming::RegisterEvent("clearJitCache", ClearCacheThreadSafe);
JitRegister::Init(SConfig::GetInstance().m_perfDir);
iCache.fill(nullptr);
Clear();
}
void JitBaseBlockCache::Shutdown()
{
num_blocks = 1;
JitRegister::Shutdown();
}
@ -63,26 +60,21 @@ void JitBaseBlockCache::Shutdown()
void JitBaseBlockCache::Clear()
{
#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
m_jit.js.fifoWriteAddresses.clear();
m_jit.js.pairedQuantizeAddresses.clear();
for (int i = 1; i < num_blocks; i++)
for (auto& e : start_block_map)
{
if (!block.invalid)
DestroyBlock(blocks[i]);
DestroyBlock(e.second);
}
start_block_map.clear();
links_to.clear();
block_map.clear();
valid_block.ClearAll();
num_blocks = 1;
blocks[0].msrBits = 0xFFFFFFFF;
blocks[0].invalid = true;
iCache.fill(nullptr);
}
void JitBaseBlockCache::Reset()
@ -96,11 +88,6 @@ void JitBaseBlockCache::SchedulateClearCacheThreadSafe()
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()
{
return iCache.data();
@ -108,26 +95,36 @@ JitBlock** JitBaseBlockCache::GetICache()
void JitBaseBlockCache::RunOnBlocks(std::function<void(const JitBlock&)> f)
{
for (int i = 0; i < num_blocks; i++)
f(blocks[i]);
for (const auto& e : start_block_map)
f(e.second);
}
JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address)
{
JitBlock& b = blocks[num_blocks];
b.invalid = false;
u32 physicalAddress = PowerPC::JitCache_TranslateAddress(em_address).address;
JitBlock& b = start_block_map.emplace(physicalAddress, JitBlock())->second;
b.effectiveAddress = em_address;
b.physicalAddress = PowerPC::JitCache_TranslateAddress(em_address).address;
b.physicalAddress = physicalAddress;
b.msrBits = MSR & JIT_CACHE_MSR_MASK;
b.linkData.clear();
b.in_icache = 0;
num_blocks++; // commit the current block
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)
{
start_block_map.emplace(block.physicalAddress, &block);
size_t icache = FastLookupEntryForAddress(block.effectiveAddress);
iCache[icache] = &block;
block.in_icache = icache;
@ -168,8 +165,8 @@ JitBlock* JitBaseBlockCache::GetBlockFromStartAddress(u32 addr, u32 msr)
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))
JitBlock& b = iter.first->second;
if (b.effectiveAddress == addr && b.msrBits == (msr & JIT_CACHE_MSR_MASK))
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));
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);
}
@ -250,17 +249,12 @@ void JitBaseBlockCache::WriteDestroyBlock(const JitBlock& block)
void JitBaseBlockCache::LinkBlockExits(JitBlock& block)
{
if (block.invalid)
{
// This block is dead. Don't relink it.
return;
}
for (auto& e : block.linkData)
{
if (!e.linkStatus)
{
JitBlock* destinationBlock = GetBlockFromStartAddress(e.exitAddress, block.msrBits);
if (destinationBlock && !destinationBlock->invalid)
if (destinationBlock)
{
WriteLinkBlock(e, destinationBlock);
e.linkStatus = true;
@ -305,24 +299,9 @@ void JitBaseBlockCache::UnlinkBlock(const 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)
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

View File

@ -47,11 +47,6 @@ struct JitBlock
u32 originalSize;
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.
// This is used to implement block linking.
struct LinkData
@ -112,7 +107,6 @@ public:
// is valid (MSR.IR and MSR.DR, the address translation bits).
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_Mask = iCache_Num_Elements - 1;
@ -125,13 +119,12 @@ public:
void Reset();
void SchedulateClearCacheThreadSafe();
bool IsFull() const;
// Code Cache
JitBlock** GetICache();
void RunOnBlocks(std::function<void(const JitBlock&)> 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.
@ -166,11 +159,6 @@ private:
// Fast but risky block lookup based on iCache.
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.
// It is used to query all blocks which links to an address.
std::multimap<u32, JitBlock*> links_to; // destination_PC -> number
@ -182,7 +170,7 @@ private:
// 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<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.
// It is used to provide a fast way to query if no icache invalidation is needed.