diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index 7cb9f46260..14084c0406 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -397,8 +397,9 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling { std::lock_guard guard(s_host_identity_lock); Core::SetState(Core::State::Paused); - JitInterface::ClearCache(); - JitInterface::SetProfilingState(enable ? JitInterface::ProfilingState::Enabled : + auto& jit_interface = Core::System::GetInstance().GetJitInterface(); + jit_interface.ClearCache(); + jit_interface.SetProfilingState(enable ? JitInterface::ProfilingState::Enabled : JitInterface::ProfilingState::Disabled); Core::SetState(Core::State::Running); } @@ -409,7 +410,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfile std::lock_guard guard(s_host_identity_lock); std::string filename = File::GetUserPath(D_DUMP_IDX) + "Debug/profiler.txt"; File::CreateFullPath(filename); - JitInterface::WriteProfileResults(filename); + auto& jit_interface = Core::System::GetInstance().GetJitInterface(); + jit_interface.WriteProfileResults(filename); } // Surface Handling diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index b4f0583420..fbc87d18fd 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -986,7 +986,7 @@ void UpdateWantDeterminism(bool initial) // We need to clear the cache because some parts of the JIT depend on want_determinism, // e.g. use of FMA. - JitInterface::ClearCache(); + system.GetJitInterface().ClearCache(); }); } } diff --git a/Source/Core/Core/HW/GPFifo.cpp b/Source/Core/Core/HW/GPFifo.cpp index 8dc865c379..94d8b905ff 100644 --- a/Source/Core/Core/HW/GPFifo.cpp +++ b/Source/Core/Core/HW/GPFifo.cpp @@ -132,7 +132,7 @@ void GPFifoManager::CheckGatherPipe() UpdateGatherPipe(); // Profile where slow FIFO writes are occurring. - JitInterface::CompileExceptionCheck(JitInterface::ExceptionType::FIFOWrite); + m_system.GetJitInterface().CompileExceptionCheck(JitInterface::ExceptionType::FIFOWrite); } } diff --git a/Source/Core/Core/MemTools.cpp b/Source/Core/Core/MemTools.cpp index 0011fd3bce..75d20dd6a9 100644 --- a/Source/Core/Core/MemTools.cpp +++ b/Source/Core/Core/MemTools.cpp @@ -16,6 +16,7 @@ #include "Core/MachineContext.h" #include "Core/PowerPC/JitInterface.h" +#include "Core/System.h" #if defined(__FreeBSD__) || defined(__NetBSD__) #include @@ -60,7 +61,7 @@ static LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs) uintptr_t fault_address = (uintptr_t)pPtrs->ExceptionRecord->ExceptionInformation[1]; SContext* ctx = pPtrs->ContextRecord; - if (JitInterface::HandleFault(fault_address, ctx)) + if (Core::System::GetInstance().GetJitInterface().HandleFault(fault_address, ctx)) { return EXCEPTION_CONTINUE_EXECUTION; } @@ -72,7 +73,7 @@ static LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs) } case EXCEPTION_STACK_OVERFLOW: - if (JitInterface::HandleStackFault()) + if (Core::System::GetInstance().GetJitInterface().HandleStackFault()) return EXCEPTION_CONTINUE_EXECUTION; else return EXCEPTION_CONTINUE_SEARCH; @@ -190,7 +191,8 @@ static void ExceptionThread(mach_port_t port) thread_state64_t* state = (thread_state64_t*)msg_in.old_state; - bool ok = JitInterface::HandleFault((uintptr_t)msg_in.code[1], state); + bool ok = + Core::System::GetInstance().GetJitInterface().HandleFault((uintptr_t)msg_in.code[1], state); // Set up the reply. msg_out.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(msg_in.Head.msgh_bits), 0); @@ -281,13 +283,13 @@ static void sigsegv_handler(int sig, siginfo_t* info, void* raw_context) mcontext_t* ctx = &context->uc_mcontext; #endif // assume it's not a write - if (!JitInterface::HandleFault(bad_address, + if (!Core::System::GetInstance().GetJitInterface().HandleFault(bad_address, #ifdef __APPLE__ - *ctx + *ctx #else - ctx + ctx #endif - )) + )) { // retry and crash // According to the sigaction man page, if sa_flags "SA_SIGINFO" is set to the sigaction diff --git a/Source/Core/Core/PowerPC/BreakPoints.cpp b/Source/Core/Core/PowerPC/BreakPoints.cpp index 9e3a21c3bc..a3615afb2e 100644 --- a/Source/Core/Core/PowerPC/BreakPoints.cpp +++ b/Source/Core/Core/PowerPC/BreakPoints.cpp @@ -16,6 +16,7 @@ #include "Core/PowerPC/Expression.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/MMU.h" +#include "Core/System.h" bool BreakPoints::IsAddressBreakPoint(u32 address) const { @@ -105,7 +106,7 @@ void BreakPoints::Add(TBreakPoint bp) if (IsAddressBreakPoint(bp.address)) return; - JitInterface::InvalidateICache(bp.address, 4, true); + Core::System::GetInstance().GetJitInterface().InvalidateICache(bp.address, 4, true); m_breakpoints.emplace_back(std::move(bp)); } @@ -141,7 +142,7 @@ void BreakPoints::Add(u32 address, bool temp, bool break_on_hit, bool log_on_hit m_breakpoints.emplace_back(std::move(bp)); } - JitInterface::InvalidateICache(address, 4, true); + Core::System::GetInstance().GetJitInterface().InvalidateICache(address, 4, true); } bool BreakPoints::ToggleBreakPoint(u32 address) @@ -165,14 +166,14 @@ void BreakPoints::Remove(u32 address) return; m_breakpoints.erase(iter); - JitInterface::InvalidateICache(address, 4, true); + Core::System::GetInstance().GetJitInterface().InvalidateICache(address, 4, true); } void BreakPoints::Clear() { for (const TBreakPoint& bp : m_breakpoints) { - JitInterface::InvalidateICache(bp.address, 4, true); + Core::System::GetInstance().GetJitInterface().InvalidateICache(bp.address, 4, true); } m_breakpoints.clear(); @@ -185,7 +186,7 @@ void BreakPoints::ClearAllTemporary() { if (bp->is_temporary) { - JitInterface::InvalidateICache(bp->address, 4, true); + Core::System::GetInstance().GetJitInterface().InvalidateICache(bp->address, 4, true); bp = m_breakpoints.erase(bp); } else @@ -278,7 +279,7 @@ void MemChecks::Add(TMemCheck memory_check) // If this is the first one, clear the JIT cache so it can switch to // watchpoint-compatible code. if (!had_any) - JitInterface::ClearCache(); + Core::System::GetInstance().GetJitInterface().ClearCache(); PowerPC::DBATUpdated(); }); } @@ -307,7 +308,7 @@ void MemChecks::Remove(u32 address) Core::RunAsCPUThread([&] { m_mem_checks.erase(iter); if (!HasAny()) - JitInterface::ClearCache(); + Core::System::GetInstance().GetJitInterface().ClearCache(); PowerPC::DBATUpdated(); }); } @@ -316,7 +317,7 @@ void MemChecks::Clear() { Core::RunAsCPUThread([&] { m_mem_checks.clear(); - JitInterface::ClearCache(); + Core::System::GetInstance().GetJitInterface().ClearCache(); PowerPC::DBATUpdated(); }); } diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStore.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStore.cpp index c87a1e0155..73b0c848b1 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStore.cpp @@ -16,6 +16,7 @@ #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/MMU.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/System.h" static u32 Helper_Get_EA(const PowerPC::PowerPCState& ppcs, const UGeckoInstruction inst) { @@ -473,7 +474,7 @@ void Interpreter::dcbf(Interpreter& interpreter, UGeckoInstruction inst) // Invalidate the JIT cache here as a heuristic to compensate for // the lack of precise L1 icache emulation in the JIT. (Portable software // should use icbi consistently, but games aren't portable.) - JitInterface::InvalidateICacheLine(address); + interpreter.m_system.GetJitInterface().InvalidateICacheLine(address); return; } @@ -495,7 +496,7 @@ void Interpreter::dcbi(Interpreter& interpreter, UGeckoInstruction inst) // Invalidate the JIT cache here as a heuristic to compensate for // the lack of precise L1 icache emulation in the JIT. (Portable software // should use icbi consistently, but games aren't portable.) - JitInterface::InvalidateICacheLine(address); + interpreter.m_system.GetJitInterface().InvalidateICacheLine(address); return; } @@ -511,7 +512,7 @@ void Interpreter::dcbst(Interpreter& interpreter, UGeckoInstruction inst) // Invalidate the JIT cache here as a heuristic to compensate for // the lack of precise L1 icache emulation in the JIT. (Portable software // should use icbi consistently, but games aren't portable.) - JitInterface::InvalidateICacheLine(address); + interpreter.m_system.GetJitInterface().InvalidateICacheLine(address); return; } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index 2624159d23..7783f58c78 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -877,8 +877,8 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC) const u8* target = GetCodePtr(); MOV(32, PPCSTATE(pc), Imm32(js.blockStart)); ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunctionC(JitInterface::CompileExceptionCheck, - static_cast(JitInterface::ExceptionType::PairedQuantize)); + ABI_CallFunctionPC(JitInterface::CompileExceptionCheckFromJIT, &m_system.GetJitInterface(), + static_cast(JitInterface::ExceptionType::PairedQuantize)); ABI_PopRegistersAndAdjustStack({}, 0); JMP(asm_routines.dispatcher_no_check, true); SwitchToNearCode(); @@ -1193,8 +1193,8 @@ void Jit64::IntializeSpeculativeConstants() target = GetCodePtr(); MOV(32, PPCSTATE(pc), Imm32(js.blockStart)); ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunctionC(JitInterface::CompileExceptionCheck, - static_cast(JitInterface::ExceptionType::SpeculativeConstants)); + ABI_CallFunctionPC(JitInterface::CompileExceptionCheckFromJIT, &m_system.GetJitInterface(), + static_cast(JitInterface::ExceptionType::SpeculativeConstants)); ABI_PopRegistersAndAdjustStack({}, 0); JMP(asm_routines.dispatcher_no_check, true); SwitchToNearCode(); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp index 179d88f6ac..ca287c80cc 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp @@ -22,6 +22,7 @@ #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/MMU.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/System.h" using namespace Gen; @@ -362,12 +363,14 @@ void Jit64::dcbx(UGeckoInstruction inst) { MOV(32, R(ABI_PARAM1), R(effective_address)); MOV(32, R(ABI_PARAM2), R(loop_counter)); - ABI_CallFunction(JitInterface::InvalidateICacheLines); + MOV(64, R(ABI_PARAM3), Imm64(reinterpret_cast(&m_system.GetJitInterface()))); + ABI_CallFunction(JitInterface::InvalidateICacheLinesFromJIT); } else { MOV(32, R(ABI_PARAM1), R(effective_address)); - ABI_CallFunction(JitInterface::InvalidateICacheLine); + MOV(64, R(ABI_PARAM3), Imm64(reinterpret_cast(&m_system.GetJitInterface()))); + ABI_CallFunction(JitInterface::InvalidateICacheLineFromJIT); } ABI_PopRegistersAndAdjustStack(registersInUse, 0); asm_routines.ResetStack(*this); diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index bd65c377d8..7e0735f85d 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -327,8 +327,9 @@ void JitArm64::IntializeSpeculativeConstants() fail = GetCodePtr(); MOVI2R(DISPATCHER_PC, js.blockStart); STR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); - MOVP2R(ARM64Reg::X8, &JitInterface::CompileExceptionCheck); - MOVI2R(ARM64Reg::W0, static_cast(JitInterface::ExceptionType::SpeculativeConstants)); + MOVP2R(ARM64Reg::X8, &JitInterface::CompileExceptionCheckFromJIT); + MOVP2R(ARM64Reg::X0, &m_system.GetJitInterface()); + MOVI2R(ARM64Reg::W1, static_cast(JitInterface::ExceptionType::SpeculativeConstants)); BLR(ARM64Reg::X8); B(dispatcher_no_check); SwitchToNearCode(); @@ -866,9 +867,10 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC) SetJumpTarget(fail); MOVI2R(DISPATCHER_PC, js.blockStart); STR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); - MOVI2R(ARM64Reg::W0, static_cast(JitInterface::ExceptionType::PairedQuantize)); - MOVP2R(ARM64Reg::X1, &JitInterface::CompileExceptionCheck); - BLR(ARM64Reg::X1); + MOVP2R(ARM64Reg::X0, &m_system.GetJitInterface()); + MOVI2R(ARM64Reg::W1, static_cast(JitInterface::ExceptionType::PairedQuantize)); + MOVP2R(ARM64Reg::X2, &JitInterface::CompileExceptionCheckFromJIT); + BLR(ARM64Reg::X2); B(dispatcher_no_check); SwitchToNearCode(); SetJumpTarget(no_fail); diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp index ac5f3ac492..d3f920b588 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp @@ -770,11 +770,12 @@ void JitArm64::dcbx(UGeckoInstruction inst) ABI_PushRegisters(gprs_to_push); m_float_emit.ABI_PushRegisters(fprs_to_push, WA); - // The function call arguments are already in the correct registers + // The first two function call arguments are already in the correct registers + MOVP2R(ARM64Reg::X2, &m_system.GetJitInterface()); if (make_loop) - MOVP2R(ARM64Reg::X8, &JitInterface::InvalidateICacheLines); + MOVP2R(ARM64Reg::X8, &JitInterface::InvalidateICacheLinesFromJIT); else - MOVP2R(ARM64Reg::X8, &JitInterface::InvalidateICacheLine); + MOVP2R(ARM64Reg::X8, &JitInterface::InvalidateICacheLineFromJIT); BLR(ARM64Reg::X8); m_float_emit.ABI_PopRegisters(fprs_to_push, WA); diff --git a/Source/Core/Core/PowerPC/JitInterface.cpp b/Source/Core/Core/PowerPC/JitInterface.cpp index ee7493cac5..2f56cf4a95 100644 --- a/Source/Core/Core/PowerPC/JitInterface.cpp +++ b/Source/Core/Core/PowerPC/JitInterface.cpp @@ -40,19 +40,24 @@ #include "Core/PowerPC/JitArm64/Jit.h" #endif -namespace JitInterface +JitInterface::JitInterface(Core::System& system) : m_system(system) { -static JitBase* g_jit = nullptr; -void SetJit(JitBase* jit) -{ - g_jit = jit; } -void DoState(PointerWrap& p) + +JitInterface::~JitInterface() = default; + +void JitInterface::SetJit(JitBase* jit) { - if (g_jit && p.IsReadMode()) - g_jit->ClearCache(); + m_jit = jit; } -CPUCoreBase* InitJitCore(PowerPC::CPUCore core) + +void JitInterface::DoState(PointerWrap& p) +{ + if (m_jit && p.IsReadMode()) + m_jit->ClearCache(); +} + +CPUCoreBase* JitInterface::InitJitCore(PowerPC::CPUCore core) { auto& system = Core::System::GetInstance(); @@ -60,42 +65,42 @@ CPUCoreBase* InitJitCore(PowerPC::CPUCore core) { #if _M_X86 case PowerPC::CPUCore::JIT64: - g_jit = new Jit64(system); + m_jit = new Jit64(system); break; #endif #if _M_ARM_64 case PowerPC::CPUCore::JITARM64: - g_jit = new JitArm64(system); + m_jit = new JitArm64(system); break; #endif case PowerPC::CPUCore::CachedInterpreter: - g_jit = new CachedInterpreter(system); + m_jit = new CachedInterpreter(system); break; default: // Under this case the caller overrides the CPU core to the default and logs that // it performed the override. - g_jit = nullptr; + m_jit = nullptr; return nullptr; } - g_jit->Init(); - return g_jit; + m_jit->Init(); + return m_jit; } -CPUCoreBase* GetCore() +CPUCoreBase* JitInterface::GetCore() const { - return g_jit; + return m_jit; } -void SetProfilingState(ProfilingState state) +void JitInterface::SetProfilingState(ProfilingState state) { - if (!g_jit) + if (!m_jit) return; - g_jit->jo.profile_blocks = state == ProfilingState::Enabled; + m_jit->jo.profile_blocks = state == ProfilingState::Enabled; } -void WriteProfileResults(const std::string& filename) +void JitInterface::WriteProfileResults(const std::string& filename) const { Profiler::ProfileStats prof_stats; GetProfileResults(&prof_stats); @@ -122,19 +127,19 @@ void WriteProfileResults(const std::string& filename) } } -void GetProfileResults(Profiler::ProfileStats* prof_stats) +void JitInterface::GetProfileResults(Profiler::ProfileStats* prof_stats) const { - // Can't really do this with no g_jit core available - if (!g_jit) + // Can't really do this with no m_jit core available + if (!m_jit) return; prof_stats->cost_sum = 0; prof_stats->timecost_sum = 0; prof_stats->block_stats.clear(); - Core::RunAsCPUThread([&prof_stats] { + Core::RunAsCPUThread([this, &prof_stats] { QueryPerformanceFrequency((LARGE_INTEGER*)&prof_stats->countsPerSec); - g_jit->GetBlockCache()->RunOnBlocks([&prof_stats](const JitBlock& block) { + m_jit->GetBlockCache()->RunOnBlocks([&prof_stats](const JitBlock& block) { const auto& data = block.profile_data; u64 cost = data.downcountCounter; u64 timecost = data.ticCounter; @@ -150,20 +155,21 @@ void GetProfileResults(Profiler::ProfileStats* prof_stats) }); } -std::variant GetHostCode(u32 address) +std::variant +JitInterface::GetHostCode(u32 address) const { - if (!g_jit) + if (!m_jit) { return GetHostCodeError::NoJitActive; } JitBlock* block = - g_jit->GetBlockCache()->GetBlockFromStartAddress(address, PowerPC::ppcState.msr.Hex); + m_jit->GetBlockCache()->GetBlockFromStartAddress(address, PowerPC::ppcState.msr.Hex); if (!block) { for (int i = 0; i < 500; i++) { - block = g_jit->GetBlockCache()->GetBlockFromStartAddress(address - 4 * i, + block = m_jit->GetBlockCache()->GetBlockFromStartAddress(address - 4 * i, PowerPC::ppcState.msr.Hex); if (block) break; @@ -190,51 +196,52 @@ std::variant GetHostCode(u32 address) return result; } -bool HandleFault(uintptr_t access_address, SContext* ctx) +bool JitInterface::HandleFault(uintptr_t access_address, SContext* ctx) { // Prevent nullptr dereference on a crash with no JIT present - if (!g_jit) + if (!m_jit) { return false; } - return g_jit->HandleFault(access_address, ctx); + return m_jit->HandleFault(access_address, ctx); } -bool HandleStackFault() +bool JitInterface::HandleStackFault() { - if (!g_jit) + if (!m_jit) { return false; } - return g_jit->HandleStackFault(); + return m_jit->HandleStackFault(); } -void ClearCache() +void JitInterface::ClearCache() { - if (g_jit) - g_jit->ClearCache(); -} -void ClearSafe() -{ - if (g_jit) - g_jit->GetBlockCache()->Clear(); + if (m_jit) + m_jit->ClearCache(); } -void InvalidateICache(u32 address, u32 size, bool forced) +void JitInterface::ClearSafe() { - if (g_jit) - g_jit->GetBlockCache()->InvalidateICache(address, size, forced); + if (m_jit) + m_jit->GetBlockCache()->Clear(); } -void InvalidateICacheLine(u32 address) +void JitInterface::InvalidateICache(u32 address, u32 size, bool forced) { - if (g_jit) - g_jit->GetBlockCache()->InvalidateICacheLine(address); + if (m_jit) + m_jit->GetBlockCache()->InvalidateICache(address, size, forced); } -void InvalidateICacheLines(u32 address, u32 count) +void JitInterface::InvalidateICacheLine(u32 address) +{ + if (m_jit) + m_jit->GetBlockCache()->InvalidateICacheLine(address); +} + +void JitInterface::InvalidateICacheLines(u32 address, u32 count) { // This corresponds to a PPC code loop that: // - calls some form of dcb* instruction on 'address' @@ -250,9 +257,19 @@ void InvalidateICacheLines(u32 address, u32 count) InvalidateICache(address & ~0x1f, 32 * count, false); } -void CompileExceptionCheck(ExceptionType type) +void JitInterface::InvalidateICacheLineFromJIT(u32 address, u32 dummy, JitInterface& jit_interface) { - if (!g_jit) + jit_interface.InvalidateICacheLine(address); +} + +void JitInterface::InvalidateICacheLinesFromJIT(u32 address, u32 count, JitInterface& jit_interface) +{ + jit_interface.InvalidateICacheLines(address, count); +} + +void JitInterface::CompileExceptionCheck(ExceptionType type) +{ + if (!m_jit) return; std::unordered_set* exception_addresses = nullptr; @@ -260,13 +277,13 @@ void CompileExceptionCheck(ExceptionType type) switch (type) { case ExceptionType::FIFOWrite: - exception_addresses = &g_jit->js.fifoWriteAddresses; + exception_addresses = &m_jit->js.fifoWriteAddresses; break; case ExceptionType::PairedQuantize: - exception_addresses = &g_jit->js.pairedQuantizeAddresses; + exception_addresses = &m_jit->js.pairedQuantizeAddresses; break; case ExceptionType::SpeculativeConstants: - exception_addresses = &g_jit->js.noSpeculativeConstantsAddresses; + exception_addresses = &m_jit->js.noSpeculativeConstantsAddresses; break; } @@ -288,17 +305,21 @@ void CompileExceptionCheck(ExceptionType type) // Invalidate the JIT block so that it gets recompiled with the external exception check // included. - g_jit->GetBlockCache()->InvalidateICache(PowerPC::ppcState.pc, 4, true); + m_jit->GetBlockCache()->InvalidateICache(PowerPC::ppcState.pc, 4, true); } } -void Shutdown() +void JitInterface::CompileExceptionCheckFromJIT(JitInterface& jit_interface, ExceptionType type) { - if (g_jit) + jit_interface.CompileExceptionCheck(type); +} + +void JitInterface::Shutdown() +{ + if (m_jit) { - g_jit->Shutdown(); - delete g_jit; - g_jit = nullptr; + m_jit->Shutdown(); + delete m_jit; + m_jit = nullptr; } } -} // namespace JitInterface diff --git a/Source/Core/Core/PowerPC/JitInterface.h b/Source/Core/Core/PowerPC/JitInterface.h index 18b60d5296..9551caadbc 100644 --- a/Source/Core/Core/PowerPC/JitInterface.h +++ b/Source/Core/Core/PowerPC/JitInterface.h @@ -13,6 +13,10 @@ class CPUCoreBase; class PointerWrap; class JitBase; +namespace Core +{ +class System; +} namespace PowerPC { enum class CPUCore; @@ -23,65 +27,78 @@ namespace Profiler struct ProfileStats; } -namespace JitInterface +class JitInterface { -enum class ExceptionType -{ - FIFOWrite, - PairedQuantize, - SpeculativeConstants +public: + explicit JitInterface(Core::System& system); + JitInterface(const JitInterface&) = delete; + JitInterface(JitInterface&&) = delete; + JitInterface& operator=(const JitInterface&) = delete; + JitInterface& operator=(JitInterface&&) = delete; + ~JitInterface(); + + void DoState(PointerWrap& p); + + CPUCoreBase* InitJitCore(PowerPC::CPUCore core); + CPUCoreBase* GetCore() const; + + // Debugging + enum class ProfilingState + { + Enabled, + Disabled + }; + enum class GetHostCodeError + { + NoJitActive, + NoTranslation, + }; + struct GetHostCodeResult + { + const u8* code; + u32 code_size; + u32 entry_address; + }; + + void SetProfilingState(ProfilingState state); + void WriteProfileResults(const std::string& filename) const; + void GetProfileResults(Profiler::ProfileStats* prof_stats) const; + std::variant GetHostCode(u32 address) const; + + // Memory Utilities + bool HandleFault(uintptr_t access_address, SContext* ctx); + bool HandleStackFault(); + + // Clearing CodeCache + void ClearCache(); + + // This clear is "safe" in the sense that it's okay to run from + // inside a JIT'ed block: it clears the instruction cache, but not + // the JIT'ed code. + void ClearSafe(); + + // If "forced" is true, a recompile is being requested on code that hasn't been modified. + void InvalidateICache(u32 address, u32 size, bool forced); + void InvalidateICacheLine(u32 address); + void InvalidateICacheLines(u32 address, u32 count); + static void InvalidateICacheLineFromJIT(u32 address, u32 dummy, JitInterface& jit_interface); + static void InvalidateICacheLinesFromJIT(u32 address, u32 count, JitInterface& jit_interface); + + enum class ExceptionType + { + FIFOWrite, + PairedQuantize, + SpeculativeConstants + }; + void CompileExceptionCheck(ExceptionType type); + static void CompileExceptionCheckFromJIT(JitInterface& jit_interface, ExceptionType type); + + /// used for the page fault unit test, don't use outside of tests! + void SetJit(JitBase* jit); + + void Shutdown(); + +private: + JitBase* m_jit = nullptr; + Core::System& m_system; }; - -void DoState(PointerWrap& p); - -CPUCoreBase* InitJitCore(PowerPC::CPUCore core); -CPUCoreBase* GetCore(); - -// Debugging -enum class ProfilingState -{ - Enabled, - Disabled -}; - -enum class GetHostCodeError -{ - NoJitActive, - NoTranslation, -}; -struct GetHostCodeResult -{ - const u8* code; - u32 code_size; - u32 entry_address; -}; - -void SetProfilingState(ProfilingState state); -void WriteProfileResults(const std::string& filename); -void GetProfileResults(Profiler::ProfileStats* prof_stats); -std::variant GetHostCode(u32 address); - -// Memory Utilities -bool HandleFault(uintptr_t access_address, SContext* ctx); -bool HandleStackFault(); - -// Clearing CodeCache -void ClearCache(); - -// This clear is "safe" in the sense that it's okay to run from -// inside a JIT'ed block: it clears the instruction cache, but not -// the JIT'ed code. -void ClearSafe(); - -// If "forced" is true, a recompile is being requested on code that hasn't been modified. -void InvalidateICache(u32 address, u32 size, bool forced); -void InvalidateICacheLine(u32 address); -void InvalidateICacheLines(u32 address, u32 count); - -void CompileExceptionCheck(ExceptionType type); - -/// used for the page fault unit test, don't use outside of tests! -void SetJit(JitBase* jit); - -void Shutdown(); -} // namespace JitInterface diff --git a/Source/Core/Core/PowerPC/MMU.cpp b/Source/Core/Core/PowerPC/MMU.cpp index 2b3706ae27..6a069b2a76 100644 --- a/Source/Core/Core/PowerPC/MMU.cpp +++ b/Source/Core/Core/PowerPC/MMU.cpp @@ -1770,7 +1770,7 @@ void DBATUpdated() #endif // IsOptimizable*Address and dcbz depends on the BAT mapping, so we need a flush here. - JitInterface::ClearSafe(); + system.GetJitInterface().ClearSafe(); } void IBATUpdated() @@ -1789,7 +1789,7 @@ void IBATUpdated() UpdateFakeMMUBat(ibat_table, 0x40000000); UpdateFakeMMUBat(ibat_table, 0x70000000); } - JitInterface::ClearSafe(); + system.GetJitInterface().ClearSafe(); } // Translate effective address using BAT or PAT. Returns 0 if the address cannot be translated. diff --git a/Source/Core/Core/PowerPC/PPCCache.cpp b/Source/Core/Core/PowerPC/PPCCache.cpp index 9d4cf00083..7818dcb616 100644 --- a/Source/Core/Core/PowerPC/PPCCache.cpp +++ b/Source/Core/Core/PowerPC/PPCCache.cpp @@ -107,7 +107,7 @@ void Cache::Reset() void InstructionCache::Reset() { Cache::Reset(); - JitInterface::ClearSafe(); + Core::System::GetInstance().GetJitInterface().ClearSafe(); } void Cache::Init() @@ -424,7 +424,7 @@ void InstructionCache::Invalidate(u32 addr) valid[set] = 0; modified[set] = 0; - JitInterface::InvalidateICacheLine(addr); + Core::System::GetInstance().GetJitInterface().InvalidateICacheLine(addr); } void InstructionCache::RefreshConfig() diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index 404813d6d4..b18960f473 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -153,7 +153,7 @@ void DoState(PointerWrap& p) // SystemTimers::DecrementerSet(); // SystemTimers::TimeBaseSet(); - JitInterface::DoState(p); + Core::System::GetInstance().GetJitInterface().DoState(p); } static void ResetRegisters() @@ -219,7 +219,8 @@ static void InitializeCPUCore(CPUCore cpu_core) { // We initialize the interpreter because // it is used on boot and code window independently. - auto& interpreter = Core::System::GetInstance().GetInterpreter(); + auto& system = Core::System::GetInstance(); + auto& interpreter = system.GetInterpreter(); interpreter.Init(); switch (cpu_core) @@ -229,12 +230,12 @@ static void InitializeCPUCore(CPUCore cpu_core) break; default: - s_cpu_core_base = JitInterface::InitJitCore(cpu_core); + s_cpu_core_base = system.GetJitInterface().InitJitCore(cpu_core); if (!s_cpu_core_base) // Handle Situations where JIT core isn't available { WARN_LOG_FMT(POWERPC, "CPU core {} not available. Falling back to default.", static_cast(cpu_core)); - s_cpu_core_base = JitInterface::InitJitCore(DefaultCPUCore()); + s_cpu_core_base = system.GetJitInterface().InitJitCore(DefaultCPUCore()); } break; } @@ -315,8 +316,9 @@ void ScheduleInvalidateCacheThreadSafe(u32 address) void Shutdown() { InjectExternalCPUCore(nullptr); - JitInterface::Shutdown(); - auto& interpreter = Core::System::GetInstance().GetInterpreter(); + auto& system = Core::System::GetInstance(); + system.GetJitInterface().Shutdown(); + auto& interpreter = system.GetInterpreter(); interpreter.Shutdown(); s_cpu_core_base = nullptr; } @@ -328,7 +330,8 @@ CoreMode GetMode() static void ApplyMode() { - auto& interpreter = Core::System::GetInstance().GetInterpreter(); + auto& system = Core::System::GetInstance(); + auto& interpreter = system.GetInterpreter(); switch (s_mode) { @@ -338,7 +341,7 @@ static void ApplyMode() case CoreMode::JIT: // Switching from interpreter to JIT. // Don't really need to do much. It'll work, the cache will refill itself. - s_cpu_core_base = JitInterface::GetCore(); + s_cpu_core_base = system.GetJitInterface().GetCore(); if (!s_cpu_core_base) // Has a chance to not get a working JIT core if one isn't active on host s_cpu_core_base = &interpreter; break; diff --git a/Source/Core/Core/System.cpp b/Source/Core/Core/System.cpp index 0a1a0eb77f..1897131041 100644 --- a/Source/Core/Core/System.cpp +++ b/Source/Core/Core/System.cpp @@ -23,6 +23,7 @@ #include "Core/HW/Sram.h" #include "Core/HW/VideoInterface.h" #include "Core/PowerPC/Interpreter/Interpreter.h" +#include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/PowerPC.h" #include "IOS/USB/Emulated/Skylander.h" #include "VideoCommon/CommandProcessor.h" @@ -40,7 +41,7 @@ struct System::Impl : m_audio_interface(system), m_core_timing(system), m_dsp(system), m_dvd_interface(system), m_dvd_thread(system), m_expansion_interface(system), m_gp_fifo(system), m_memory(system), m_ppc_state(PowerPC::ppcState), m_processor_interface(system), m_serial_interface(system), - m_video_interface(system), m_interpreter(system, m_ppc_state) + m_video_interface(system), m_interpreter(system, m_ppc_state), m_jit_interface(system) { } @@ -72,6 +73,7 @@ struct System::Impl VertexShaderManager m_vertex_shader_manager; VideoInterface::VideoInterfaceManager m_video_interface; Interpreter m_interpreter; + JitInterface m_jit_interface; }; System::System() : m_impl{std::make_unique(*this)} @@ -182,6 +184,11 @@ Interpreter& System::GetInterpreter() const return m_impl->m_interpreter; } +JitInterface& System::GetJitInterface() const +{ + return m_impl->m_jit_interface; +} + IOS::HLE::USB::SkylanderPortal& System::GetSkylanderPortal() const { return m_impl->m_skylander_portal; diff --git a/Source/Core/Core/System.h b/Source/Core/Core/System.h index e1c7b9a5b8..d25b5ad609 100644 --- a/Source/Core/Core/System.h +++ b/Source/Core/Core/System.h @@ -7,6 +7,7 @@ class GeometryShaderManager; class Interpreter; +class JitInterface; class PixelShaderManager; class SoundStream; struct Sram; @@ -133,6 +134,7 @@ public: GPFifo::GPFifoManager& GetGPFifo() const; HSP::HSPManager& GetHSP() const; Interpreter& GetInterpreter() const; + JitInterface& GetJitInterface() const; IOS::HLE::USB::SkylanderPortal& GetSkylanderPortal() const; Memory::MemoryManager& GetMemory() const; MemoryInterface::MemoryInterfaceManager& GetMemoryInterface() const; diff --git a/Source/Core/DolphinQt/Debugger/CodeDiffDialog.cpp b/Source/Core/DolphinQt/Debugger/CodeDiffDialog.cpp index 1be7d8c785..11f2a9a287 100644 --- a/Source/Core/DolphinQt/Debugger/CodeDiffDialog.cpp +++ b/Source/Core/DolphinQt/Debugger/CodeDiffDialog.cpp @@ -140,7 +140,8 @@ void CodeDiffDialog::ClearData() // Swap is used instead of clear for efficiency in the case of huge m_include/m_exclude std::vector().swap(m_include); std::vector().swap(m_exclude); - JitInterface::SetProfilingState(JitInterface::ProfilingState::Disabled); + Core::System::GetInstance().GetJitInterface().SetProfilingState( + JitInterface::ProfilingState::Disabled); } void CodeDiffDialog::ClearBlockCache() @@ -150,7 +151,7 @@ void CodeDiffDialog::ClearBlockCache() if (old_state == Core::State::Running) Core::SetState(Core::State::Paused); - JitInterface::ClearCache(); + Core::System::GetInstance().GetJitInterface().ClearCache(); if (old_state == Core::State::Running) Core::SetState(Core::State::Running); @@ -205,7 +206,7 @@ void CodeDiffDialog::OnRecord(bool enabled) } m_record_btn->update(); - JitInterface::SetProfilingState(state); + Core::System::GetInstance().GetJitInterface().SetProfilingState(state); } void CodeDiffDialog::OnInclude() @@ -271,7 +272,7 @@ std::vector CodeDiffDialog::CalculateSymbolsFromProfile() { Profiler::ProfileStats prof_stats; auto& blockstats = prof_stats.block_stats; - JitInterface::GetProfileResults(&prof_stats); + Core::System::GetInstance().GetJitInterface().GetProfileResults(&prof_stats); std::vector current; current.reserve(20000); @@ -391,7 +392,7 @@ void CodeDiffDialog::Update(bool include) m_exclude_size_label->setText(tr("Excluded: %1").arg(m_exclude.size())); m_include_size_label->setText(tr("Included: %1").arg(m_include.size())); - JitInterface::ClearCache(); + Core::System::GetInstance().GetJitInterface().ClearCache(); if (old_state == Core::State::Running) Core::SetState(Core::State::Running); } diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index 1a15d9c100..ea991d1e6f 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -1671,7 +1671,7 @@ void MenuBar::PatchHLEFunctions() void MenuBar::ClearCache() { - Core::RunAsCPUThread(JitInterface::ClearCache); + Core::RunAsCPUThread([] { Core::System::GetInstance().GetJitInterface().ClearCache(); }); } void MenuBar::LogInstructions() diff --git a/Source/Core/UICommon/Disassembler.cpp b/Source/Core/UICommon/Disassembler.cpp index 62e4d32c6d..840af8ec1f 100644 --- a/Source/Core/UICommon/Disassembler.cpp +++ b/Source/Core/UICommon/Disassembler.cpp @@ -16,6 +16,7 @@ #include "Common/Assert.h" #include "Common/VariantUtil.h" #include "Core/PowerPC/JitInterface.h" +#include "Core/System.h" #if defined(HAVE_LLVM) class HostDisassemblerLLVM : public HostDisassembler @@ -170,7 +171,7 @@ std::unique_ptr GetNewDisassembler(const std::string& arch) DisassembleResult DisassembleBlock(HostDisassembler* disasm, u32 address) { - auto res = JitInterface::GetHostCode(address); + auto res = Core::System::GetInstance().GetJitInterface().GetHostCode(address); return std::visit(overloaded{[&](JitInterface::GetHostCodeError error) { DisassembleResult result; diff --git a/Source/UnitTests/Core/PageFaultTest.cpp b/Source/UnitTests/Core/PageFaultTest.cpp index be8de724c1..b9e37a754c 100644 --- a/Source/UnitTests/Core/PageFaultTest.cpp +++ b/Source/UnitTests/Core/PageFaultTest.cpp @@ -76,7 +76,7 @@ TEST(PageFault, PageFault) Common::WriteProtectMemory(data, PAGE_GRAN, false); PageFaultFakeJit pfjit(Core::System::GetInstance()); - JitInterface::SetJit(&pfjit); + Core::System::GetInstance().GetJitInterface().SetJit(&pfjit); pfjit.m_data = data; auto start = std::chrono::high_resolution_clock::now(); @@ -88,7 +88,7 @@ TEST(PageFault, PageFault) }; EMM::UninstallExceptionHandler(); - JitInterface::SetJit(nullptr); + Core::System::GetInstance().GetJitInterface().SetJit(nullptr); fmt::print("page fault timing:\n"); fmt::print("start->HandleFault {} ns\n",