JitCache: Move private class details below public details
Also organizes cpp file organization to match the function layout.
This commit is contained in:
parent
0869c63048
commit
cf18aeb1eb
|
@ -35,11 +35,6 @@ static void ClearCacheThreadSafe(u64 userdata, s64 cyclesdata)
|
||||||
JitInterface::ClearCache();
|
JitInterface::ClearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JitBaseBlockCache::IsFull() const
|
|
||||||
{
|
|
||||||
return GetNumBlocks() >= MAX_NUM_BLOCKS - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void JitBaseBlockCache::Init()
|
void JitBaseBlockCache::Init()
|
||||||
{
|
{
|
||||||
s_clear_jit_cache_thread_safe = CoreTiming::RegisterEvent("clearJitCache", ClearCacheThreadSafe);
|
s_clear_jit_cache_thread_safe = CoreTiming::RegisterEvent("clearJitCache", ClearCacheThreadSafe);
|
||||||
|
@ -82,15 +77,20 @@ void JitBaseBlockCache::Clear()
|
||||||
blocks[0].invalid = true;
|
blocks[0].invalid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JitBaseBlockCache::Reset()
|
||||||
|
{
|
||||||
|
Shutdown();
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
void JitBaseBlockCache::SchedulateClearCacheThreadSafe()
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitBaseBlockCache::Reset()
|
bool JitBaseBlockCache::IsFull() const
|
||||||
{
|
{
|
||||||
Shutdown();
|
return GetNumBlocks() >= MAX_NUM_BLOCKS - 1;
|
||||||
Init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JitBlock* JitBaseBlockCache::GetBlock(int no)
|
JitBlock* JitBaseBlockCache::GetBlock(int no)
|
||||||
|
@ -180,20 +180,6 @@ int JitBaseBlockCache::GetBlockNumberFromStartAddress(u32 addr, u32 msr)
|
||||||
return block_num;
|
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()
|
const u8* JitBaseBlockCache::Dispatch()
|
||||||
{
|
{
|
||||||
int block_num = FastLookupEntryForAddress(PC);
|
int block_num = FastLookupEntryForAddress(PC);
|
||||||
|
@ -208,6 +194,54 @@ const u8* JitBaseBlockCache::Dispatch()
|
||||||
return blocks[block_num].normalEntry;
|
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
|
// Block linker
|
||||||
// Make sure to have as many blocks as possible compiled before calling this
|
// Make sure to have as many blocks as possible compiled before calling this
|
||||||
// It's O(N), so it's fast :)
|
// It's O(N), so it's fast :)
|
||||||
|
@ -309,46 +343,16 @@ void JitBaseBlockCache::DestroyBlock(int block_num, bool invalidate)
|
||||||
WriteDestroyBlock(b);
|
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);
|
int block_num = GetBlockNumberFromStartAddress(addr, msr);
|
||||||
if (!translated.valid)
|
if (block_num < 0)
|
||||||
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))
|
Jit(addr);
|
||||||
destroy_block = false;
|
|
||||||
else
|
|
||||||
valid_block.Clear(pAddr / 32);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// 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));
|
FastLookupEntryForAddress(addr) = block_num;
|
||||||
while (it != block_map.end() && it->first.second < pAddr + length)
|
LinkBlock(block_num);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,53 @@ public:
|
||||||
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;
|
||||||
|
|
||||||
|
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:
|
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.
|
// 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.
|
// 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
|
std::array<JitBlock, MAX_NUM_BLOCKS> blocks; // number -> JitBlock
|
||||||
|
@ -138,51 +184,4 @@ private:
|
||||||
// This array is indexed with the masked PC and likely holds the correct block id.
|
// 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.
|
// This is used as a fast cache of start_block_map used in the assembly dispatcher.
|
||||||
std::array<int, iCache_Num_Elements> iCache; // start_addr & mask -> number
|
std::array<int, iCache_Num_Elements> 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(); }
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue