summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authormitaclaw <140017135+mitaclaw@users.noreply.github.com>2024-10-19 18:14:28 -0700
committermitaclaw <140017135+mitaclaw@users.noreply.github.com>2024-10-19 18:19:17 -0700
commitc3bda2e8757b4c37bec504f05ebda39b858e2969 (patch)
tree6d0405765ae5d4197720dd5f20c7a806986767df /Source/Core
parenta035bd95e40d1cd3e103577f5b1c3e584eb67c32 (diff)
Jit64: Make Furthest Exit Micro-Optimization More Correct
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/PowerPC/Jit64/Jit.cpp31
1 files changed, 7 insertions, 24 deletions
diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp
index cc88868fee..0201127a42 100644
--- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp
+++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp
@@ -1192,6 +1192,12 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
WriteExit(nextPC);
}
+ // When linking to an entry point immediately following it in memory, a JIT block's furthest
+ // exit can, as a micro-optimization, overwrite the JMP instruction with a multibyte NOP.
+ // See: 'JitBlockCache::WriteLinkBlock'
+ // In order to do this in a non-sketchy way, a JIT block must own the alignment padding bytes.
+ AlignCode4(); // TODO: Test if this or AlignCode16 make a difference from GetCodePtr
+
if (HasWriteFailed() || m_far_code.HasWriteFailed())
{
if (HasWriteFailed())
@@ -1218,30 +1224,7 @@ std::vector<JitBase::MemoryStats> Jit64::GetMemoryStats() const
std::size_t Jit64::DisassembleNearCode(const JitBlock& block, std::ostream& stream) const
{
- // The last element of the JitBlock::linkData vector is not necessarily the furthest exit.
- // See: Jit64::JustWriteExit
- const auto iter = std::ranges::max_element(block.linkData, {}, &JitBlock::LinkData::exitPtrs);
-
- // Link data is not guaranteed, e.g. Jit64::WriteRfiExitDestInRSCRATCH
- if (iter == block.linkData.end())
- return m_disassembler->Disassemble(block.normalEntry, block.near_end, stream);
-
- // A JitBlock's near_end only records where the XEmitter was after DoJit concludes. However, a
- // JitBlock's exits will be modified by block linking. If Block A wants to link its final exit
- // to the entry_point of Block B, and Block B follows Block A in memory, then the final exit's
- // JMP will not have its destination modified but will instead be overwritten by a multibyte NOP.
- // Trickily, Block A's near_end does not necessarily equal Block B's entry_point because Block B's
- // entry_point is aligned to the next multiple of 4! This means the multibyte NOP may need to
- // extend past Block A's near_end, complicating host code disassembly. If the opcode of a JMP
- // instruction is found at the final exit, the block will be disassembled like normal. If one
- // is not, the exit is assumed to be overwritten, and special action is taken.
- const u8* const furthest_exit = iter->exitPtrs;
- if (*furthest_exit == 0xE9)
- return m_disassembler->Disassemble(block.normalEntry, block.near_end, stream);
-
- const auto inst_count = m_disassembler->Disassemble(block.normalEntry, furthest_exit, stream);
- fmt::println(stream, "{}\tmultibyte nop", fmt::ptr(furthest_exit));
- return inst_count + 1;
+ return m_disassembler->Disassemble(block.normalEntry, block.near_end, stream);
}
std::size_t Jit64::DisassembleFarCode(const JitBlock& block, std::ostream& stream) const