mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-02 11:02:28 +02:00
JitCache: Drop block_map.
It is only used for invalidation, and in a bad way. Just scan over all elements, as it is still in O(n), this shouldn't matter much.
This commit is contained in:
parent
98311cd9f4
commit
dc0fbc15f0
@ -36,6 +36,15 @@ static void ClearCacheThreadSafe(u64 userdata, s64 cyclesdata)
|
|||||||
JitInterface::ClearCache();
|
JitInterface::ClearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool JitBlock::Overlap(u32 addr, u32 length)
|
||||||
|
{
|
||||||
|
if (addr >= physicalAddress + originalSize)
|
||||||
|
return false;
|
||||||
|
if (physicalAddress >= addr + length)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
JitBaseBlockCache::JitBaseBlockCache(JitBase& jit) : m_jit{jit}
|
JitBaseBlockCache::JitBaseBlockCache(JitBase& jit) : m_jit{jit}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -64,13 +73,12 @@ void JitBaseBlockCache::Clear()
|
|||||||
#endif
|
#endif
|
||||||
m_jit.js.fifoWriteAddresses.clear();
|
m_jit.js.fifoWriteAddresses.clear();
|
||||||
m_jit.js.pairedQuantizeAddresses.clear();
|
m_jit.js.pairedQuantizeAddresses.clear();
|
||||||
for (auto& e : start_block_map)
|
for (auto& e : block_map)
|
||||||
{
|
{
|
||||||
DestroyBlock(e.second);
|
DestroyBlock(e.second);
|
||||||
}
|
}
|
||||||
start_block_map.clear();
|
|
||||||
links_to.clear();
|
|
||||||
block_map.clear();
|
block_map.clear();
|
||||||
|
links_to.clear();
|
||||||
|
|
||||||
valid_block.ClearAll();
|
valid_block.ClearAll();
|
||||||
|
|
||||||
@ -95,14 +103,14 @@ JitBlock** JitBaseBlockCache::GetFastBlockMap()
|
|||||||
|
|
||||||
void JitBaseBlockCache::RunOnBlocks(std::function<void(const JitBlock&)> f)
|
void JitBaseBlockCache::RunOnBlocks(std::function<void(const JitBlock&)> f)
|
||||||
{
|
{
|
||||||
for (const auto& e : start_block_map)
|
for (const auto& e : block_map)
|
||||||
f(e.second);
|
f(e.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address)
|
JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address)
|
||||||
{
|
{
|
||||||
u32 physicalAddress = PowerPC::JitCache_TranslateAddress(em_address).address;
|
u32 physicalAddress = PowerPC::JitCache_TranslateAddress(em_address).address;
|
||||||
JitBlock& b = start_block_map.emplace(physicalAddress, JitBlock())->second;
|
JitBlock& b = block_map.emplace(physicalAddress, JitBlock())->second;
|
||||||
b.effectiveAddress = em_address;
|
b.effectiveAddress = em_address;
|
||||||
b.physicalAddress = physicalAddress;
|
b.physicalAddress = physicalAddress;
|
||||||
b.msrBits = MSR & JIT_CACHE_MSR_MASK;
|
b.msrBits = MSR & JIT_CACHE_MSR_MASK;
|
||||||
@ -111,18 +119,6 @@ JitBlock* JitBaseBlockCache::AllocateBlock(u32 em_address)
|
|||||||
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)
|
|
||||||
iter.first = 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)
|
||||||
{
|
{
|
||||||
size_t index = FastLookupIndexForAddress(block.effectiveAddress);
|
size_t index = FastLookupIndexForAddress(block.effectiveAddress);
|
||||||
@ -134,8 +130,6 @@ void JitBaseBlockCache::FinalizeBlock(JitBlock& block, bool block_link, const u8
|
|||||||
for (u32 addr = pAddr / 32; addr <= (pAddr + (block.originalSize - 1) * 4) / 32; ++addr)
|
for (u32 addr = pAddr / 32; addr <= (pAddr + (block.originalSize - 1) * 4) / 32; ++addr)
|
||||||
valid_block.Set(addr);
|
valid_block.Set(addr);
|
||||||
|
|
||||||
block_map.emplace(std::make_pair(pAddr + 4 * block.originalSize - 1, pAddr), &block);
|
|
||||||
|
|
||||||
if (block_link)
|
if (block_link)
|
||||||
{
|
{
|
||||||
for (const auto& e : block.linkData)
|
for (const auto& e : block.linkData)
|
||||||
@ -162,7 +156,7 @@ JitBlock* JitBaseBlockCache::GetBlockFromStartAddress(u32 addr, u32 msr)
|
|||||||
translated_addr = translated.address;
|
translated_addr = translated.address;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto iter = start_block_map.equal_range(translated_addr);
|
auto iter = 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;
|
||||||
@ -204,17 +198,20 @@ void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool for
|
|||||||
}
|
}
|
||||||
|
|
||||||
// destroy JIT blocks
|
// destroy JIT blocks
|
||||||
// !! this works correctly under assumption that any two overlapping blocks end at the same
|
|
||||||
// address
|
|
||||||
if (destroy_block)
|
if (destroy_block)
|
||||||
{
|
{
|
||||||
auto it = block_map.lower_bound(std::make_pair(pAddr, 0));
|
auto iter = block_map.begin();
|
||||||
while (it != block_map.end() && it->first.second < pAddr + length)
|
while (iter != block_map.end())
|
||||||
{
|
{
|
||||||
JitBlock* block = it->second;
|
if (iter->second.Overlap(pAddr, length))
|
||||||
DestroyBlock(*block);
|
{
|
||||||
FreeBlock(block);
|
DestroyBlock(iter->second);
|
||||||
it = block_map.erase(it);
|
iter = block_map.erase(iter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the code was actually modified, we need to clear the relevant entries from the
|
// If the code was actually modified, we need to clear the relevant entries from the
|
||||||
|
@ -24,6 +24,8 @@ class JitBase;
|
|||||||
// address.
|
// address.
|
||||||
struct JitBlock
|
struct JitBlock
|
||||||
{
|
{
|
||||||
|
bool Overlap(u32 addr, u32 length);
|
||||||
|
|
||||||
// A special entry point for block linking; usually used to check the
|
// A special entry point for block linking; usually used to check the
|
||||||
// downcount.
|
// downcount.
|
||||||
const u8* checkedEntry;
|
const u8* checkedEntry;
|
||||||
@ -35,8 +37,8 @@ struct JitBlock
|
|||||||
// The MSR bits expected for this block to be valid; see JIT_CACHE_MSR_MASK.
|
// The MSR bits expected for this block to be valid; see JIT_CACHE_MSR_MASK.
|
||||||
u32 msrBits;
|
u32 msrBits;
|
||||||
// The physical address of the code represented by this block.
|
// The physical address of the code represented by this block.
|
||||||
// Various maps in the cache are indexed by this (start_block_map,
|
// Various maps in the cache are indexed by this (block_map
|
||||||
// block_map, and valid_block in particular). This is useful because of
|
// and valid_block in particular). This is useful because of
|
||||||
// of the way the instruction cache works on PowerPC.
|
// of the way the instruction cache works on PowerPC.
|
||||||
u32 physicalAddress;
|
u32 physicalAddress;
|
||||||
// The number of bytes of JIT'ed code contained in this block. Mostly
|
// The number of bytes of JIT'ed code contained in this block. Mostly
|
||||||
@ -124,7 +126,6 @@ public:
|
|||||||
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.
|
||||||
@ -163,20 +164,15 @@ private:
|
|||||||
// 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
|
||||||
|
|
||||||
// Map indexed by the physical memory location.
|
|
||||||
// It is used to invalidate blocks based on memory location.
|
|
||||||
std::multimap<std::pair<u32, u32>, JitBlock*> block_map; // (end_addr, start_addr) -> block
|
|
||||||
|
|
||||||
// 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.
|
std::multimap<u32, JitBlock> 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.
|
||||||
ValidBlockBitSet valid_block;
|
ValidBlockBitSet valid_block;
|
||||||
|
|
||||||
// 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 block_map used in the assembly dispatcher.
|
||||||
std::array<JitBlock*, FAST_BLOCK_MAP_ELEMENTS> fast_block_map; // start_addr & mask -> number
|
std::array<JitBlock*, FAST_BLOCK_MAP_ELEMENTS> fast_block_map; // start_addr & mask -> number
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user