mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
JitCache: Store the JitBlock in the std::map.
This commit is contained in:
parent
43cdbab515
commit
830ae6a2c1
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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.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
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user