Merge pull request #11696 from AdmiralCurtiss/jit-interface-class

JitInterface: Refactor to class, move to System.
This commit is contained in:
Mai 2023-03-27 10:31:53 -04:00 committed by GitHub
commit c096ee64f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 250 additions and 183 deletions

View file

@ -397,8 +397,9 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling
{ {
std::lock_guard<std::mutex> guard(s_host_identity_lock); std::lock_guard<std::mutex> guard(s_host_identity_lock);
Core::SetState(Core::State::Paused); Core::SetState(Core::State::Paused);
JitInterface::ClearCache(); auto& jit_interface = Core::System::GetInstance().GetJitInterface();
JitInterface::SetProfilingState(enable ? JitInterface::ProfilingState::Enabled : jit_interface.ClearCache();
jit_interface.SetProfilingState(enable ? JitInterface::ProfilingState::Enabled :
JitInterface::ProfilingState::Disabled); JitInterface::ProfilingState::Disabled);
Core::SetState(Core::State::Running); Core::SetState(Core::State::Running);
} }
@ -409,7 +410,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfile
std::lock_guard<std::mutex> guard(s_host_identity_lock); std::lock_guard<std::mutex> guard(s_host_identity_lock);
std::string filename = File::GetUserPath(D_DUMP_IDX) + "Debug/profiler.txt"; std::string filename = File::GetUserPath(D_DUMP_IDX) + "Debug/profiler.txt";
File::CreateFullPath(filename); File::CreateFullPath(filename);
JitInterface::WriteProfileResults(filename); auto& jit_interface = Core::System::GetInstance().GetJitInterface();
jit_interface.WriteProfileResults(filename);
} }
// Surface Handling // Surface Handling

View file

@ -986,7 +986,7 @@ void UpdateWantDeterminism(bool initial)
// We need to clear the cache because some parts of the JIT depend on want_determinism, // We need to clear the cache because some parts of the JIT depend on want_determinism,
// e.g. use of FMA. // e.g. use of FMA.
JitInterface::ClearCache(); system.GetJitInterface().ClearCache();
}); });
} }
} }

View file

@ -132,7 +132,7 @@ void GPFifoManager::CheckGatherPipe()
UpdateGatherPipe(); UpdateGatherPipe();
// Profile where slow FIFO writes are occurring. // Profile where slow FIFO writes are occurring.
JitInterface::CompileExceptionCheck(JitInterface::ExceptionType::FIFOWrite); m_system.GetJitInterface().CompileExceptionCheck(JitInterface::ExceptionType::FIFOWrite);
} }
} }

View file

@ -16,6 +16,7 @@
#include "Core/MachineContext.h" #include "Core/MachineContext.h"
#include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/JitInterface.h"
#include "Core/System.h"
#if defined(__FreeBSD__) || defined(__NetBSD__) #if defined(__FreeBSD__) || defined(__NetBSD__)
#include <signal.h> #include <signal.h>
@ -60,7 +61,7 @@ static LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs)
uintptr_t fault_address = (uintptr_t)pPtrs->ExceptionRecord->ExceptionInformation[1]; uintptr_t fault_address = (uintptr_t)pPtrs->ExceptionRecord->ExceptionInformation[1];
SContext* ctx = pPtrs->ContextRecord; SContext* ctx = pPtrs->ContextRecord;
if (JitInterface::HandleFault(fault_address, ctx)) if (Core::System::GetInstance().GetJitInterface().HandleFault(fault_address, ctx))
{ {
return EXCEPTION_CONTINUE_EXECUTION; return EXCEPTION_CONTINUE_EXECUTION;
} }
@ -72,7 +73,7 @@ static LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs)
} }
case EXCEPTION_STACK_OVERFLOW: case EXCEPTION_STACK_OVERFLOW:
if (JitInterface::HandleStackFault()) if (Core::System::GetInstance().GetJitInterface().HandleStackFault())
return EXCEPTION_CONTINUE_EXECUTION; return EXCEPTION_CONTINUE_EXECUTION;
else else
return EXCEPTION_CONTINUE_SEARCH; 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; 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. // Set up the reply.
msg_out.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(msg_in.Head.msgh_bits), 0); msg_out.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(msg_in.Head.msgh_bits), 0);
@ -281,7 +283,7 @@ static void sigsegv_handler(int sig, siginfo_t* info, void* raw_context)
mcontext_t* ctx = &context->uc_mcontext; mcontext_t* ctx = &context->uc_mcontext;
#endif #endif
// assume it's not a write // assume it's not a write
if (!JitInterface::HandleFault(bad_address, if (!Core::System::GetInstance().GetJitInterface().HandleFault(bad_address,
#ifdef __APPLE__ #ifdef __APPLE__
*ctx *ctx
#else #else

View file

@ -16,6 +16,7 @@
#include "Core/PowerPC/Expression.h" #include "Core/PowerPC/Expression.h"
#include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/System.h"
bool BreakPoints::IsAddressBreakPoint(u32 address) const bool BreakPoints::IsAddressBreakPoint(u32 address) const
{ {
@ -105,7 +106,7 @@ void BreakPoints::Add(TBreakPoint bp)
if (IsAddressBreakPoint(bp.address)) if (IsAddressBreakPoint(bp.address))
return; return;
JitInterface::InvalidateICache(bp.address, 4, true); Core::System::GetInstance().GetJitInterface().InvalidateICache(bp.address, 4, true);
m_breakpoints.emplace_back(std::move(bp)); 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)); 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) bool BreakPoints::ToggleBreakPoint(u32 address)
@ -165,14 +166,14 @@ void BreakPoints::Remove(u32 address)
return; return;
m_breakpoints.erase(iter); m_breakpoints.erase(iter);
JitInterface::InvalidateICache(address, 4, true); Core::System::GetInstance().GetJitInterface().InvalidateICache(address, 4, true);
} }
void BreakPoints::Clear() void BreakPoints::Clear()
{ {
for (const TBreakPoint& bp : m_breakpoints) for (const TBreakPoint& bp : m_breakpoints)
{ {
JitInterface::InvalidateICache(bp.address, 4, true); Core::System::GetInstance().GetJitInterface().InvalidateICache(bp.address, 4, true);
} }
m_breakpoints.clear(); m_breakpoints.clear();
@ -185,7 +186,7 @@ void BreakPoints::ClearAllTemporary()
{ {
if (bp->is_temporary) if (bp->is_temporary)
{ {
JitInterface::InvalidateICache(bp->address, 4, true); Core::System::GetInstance().GetJitInterface().InvalidateICache(bp->address, 4, true);
bp = m_breakpoints.erase(bp); bp = m_breakpoints.erase(bp);
} }
else 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 // If this is the first one, clear the JIT cache so it can switch to
// watchpoint-compatible code. // watchpoint-compatible code.
if (!had_any) if (!had_any)
JitInterface::ClearCache(); Core::System::GetInstance().GetJitInterface().ClearCache();
PowerPC::DBATUpdated(); PowerPC::DBATUpdated();
}); });
} }
@ -307,7 +308,7 @@ void MemChecks::Remove(u32 address)
Core::RunAsCPUThread([&] { Core::RunAsCPUThread([&] {
m_mem_checks.erase(iter); m_mem_checks.erase(iter);
if (!HasAny()) if (!HasAny())
JitInterface::ClearCache(); Core::System::GetInstance().GetJitInterface().ClearCache();
PowerPC::DBATUpdated(); PowerPC::DBATUpdated();
}); });
} }
@ -316,7 +317,7 @@ void MemChecks::Clear()
{ {
Core::RunAsCPUThread([&] { Core::RunAsCPUThread([&] {
m_mem_checks.clear(); m_mem_checks.clear();
JitInterface::ClearCache(); Core::System::GetInstance().GetJitInterface().ClearCache();
PowerPC::DBATUpdated(); PowerPC::DBATUpdated();
}); });
} }

View file

@ -16,6 +16,7 @@
#include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
static u32 Helper_Get_EA(const PowerPC::PowerPCState& ppcs, const UGeckoInstruction inst) 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 // Invalidate the JIT cache here as a heuristic to compensate for
// the lack of precise L1 icache emulation in the JIT. (Portable software // the lack of precise L1 icache emulation in the JIT. (Portable software
// should use icbi consistently, but games aren't portable.) // should use icbi consistently, but games aren't portable.)
JitInterface::InvalidateICacheLine(address); interpreter.m_system.GetJitInterface().InvalidateICacheLine(address);
return; return;
} }
@ -495,7 +496,7 @@ void Interpreter::dcbi(Interpreter& interpreter, UGeckoInstruction inst)
// Invalidate the JIT cache here as a heuristic to compensate for // Invalidate the JIT cache here as a heuristic to compensate for
// the lack of precise L1 icache emulation in the JIT. (Portable software // the lack of precise L1 icache emulation in the JIT. (Portable software
// should use icbi consistently, but games aren't portable.) // should use icbi consistently, but games aren't portable.)
JitInterface::InvalidateICacheLine(address); interpreter.m_system.GetJitInterface().InvalidateICacheLine(address);
return; return;
} }
@ -511,7 +512,7 @@ void Interpreter::dcbst(Interpreter& interpreter, UGeckoInstruction inst)
// Invalidate the JIT cache here as a heuristic to compensate for // Invalidate the JIT cache here as a heuristic to compensate for
// the lack of precise L1 icache emulation in the JIT. (Portable software // the lack of precise L1 icache emulation in the JIT. (Portable software
// should use icbi consistently, but games aren't portable.) // should use icbi consistently, but games aren't portable.)
JitInterface::InvalidateICacheLine(address); interpreter.m_system.GetJitInterface().InvalidateICacheLine(address);
return; return;
} }

View file

@ -877,7 +877,7 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
const u8* target = GetCodePtr(); const u8* target = GetCodePtr();
MOV(32, PPCSTATE(pc), Imm32(js.blockStart)); MOV(32, PPCSTATE(pc), Imm32(js.blockStart));
ABI_PushRegistersAndAdjustStack({}, 0); ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunctionC(JitInterface::CompileExceptionCheck, ABI_CallFunctionPC(JitInterface::CompileExceptionCheckFromJIT, &m_system.GetJitInterface(),
static_cast<u32>(JitInterface::ExceptionType::PairedQuantize)); static_cast<u32>(JitInterface::ExceptionType::PairedQuantize));
ABI_PopRegistersAndAdjustStack({}, 0); ABI_PopRegistersAndAdjustStack({}, 0);
JMP(asm_routines.dispatcher_no_check, true); JMP(asm_routines.dispatcher_no_check, true);
@ -1193,7 +1193,7 @@ void Jit64::IntializeSpeculativeConstants()
target = GetCodePtr(); target = GetCodePtr();
MOV(32, PPCSTATE(pc), Imm32(js.blockStart)); MOV(32, PPCSTATE(pc), Imm32(js.blockStart));
ABI_PushRegistersAndAdjustStack({}, 0); ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunctionC(JitInterface::CompileExceptionCheck, ABI_CallFunctionPC(JitInterface::CompileExceptionCheckFromJIT, &m_system.GetJitInterface(),
static_cast<u32>(JitInterface::ExceptionType::SpeculativeConstants)); static_cast<u32>(JitInterface::ExceptionType::SpeculativeConstants));
ABI_PopRegistersAndAdjustStack({}, 0); ABI_PopRegistersAndAdjustStack({}, 0);
JMP(asm_routines.dispatcher_no_check, true); JMP(asm_routines.dispatcher_no_check, true);

View file

@ -22,6 +22,7 @@
#include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
using namespace Gen; using namespace Gen;
@ -362,12 +363,14 @@ void Jit64::dcbx(UGeckoInstruction inst)
{ {
MOV(32, R(ABI_PARAM1), R(effective_address)); MOV(32, R(ABI_PARAM1), R(effective_address));
MOV(32, R(ABI_PARAM2), R(loop_counter)); MOV(32, R(ABI_PARAM2), R(loop_counter));
ABI_CallFunction(JitInterface::InvalidateICacheLines); MOV(64, R(ABI_PARAM3), Imm64(reinterpret_cast<u64>(&m_system.GetJitInterface())));
ABI_CallFunction(JitInterface::InvalidateICacheLinesFromJIT);
} }
else else
{ {
MOV(32, R(ABI_PARAM1), R(effective_address)); MOV(32, R(ABI_PARAM1), R(effective_address));
ABI_CallFunction(JitInterface::InvalidateICacheLine); MOV(64, R(ABI_PARAM3), Imm64(reinterpret_cast<u64>(&m_system.GetJitInterface())));
ABI_CallFunction(JitInterface::InvalidateICacheLineFromJIT);
} }
ABI_PopRegistersAndAdjustStack(registersInUse, 0); ABI_PopRegistersAndAdjustStack(registersInUse, 0);
asm_routines.ResetStack(*this); asm_routines.ResetStack(*this);

View file

@ -327,8 +327,9 @@ void JitArm64::IntializeSpeculativeConstants()
fail = GetCodePtr(); fail = GetCodePtr();
MOVI2R(DISPATCHER_PC, js.blockStart); MOVI2R(DISPATCHER_PC, js.blockStart);
STR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); STR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc));
MOVP2R(ARM64Reg::X8, &JitInterface::CompileExceptionCheck); MOVP2R(ARM64Reg::X8, &JitInterface::CompileExceptionCheckFromJIT);
MOVI2R(ARM64Reg::W0, static_cast<u32>(JitInterface::ExceptionType::SpeculativeConstants)); MOVP2R(ARM64Reg::X0, &m_system.GetJitInterface());
MOVI2R(ARM64Reg::W1, static_cast<u32>(JitInterface::ExceptionType::SpeculativeConstants));
BLR(ARM64Reg::X8); BLR(ARM64Reg::X8);
B(dispatcher_no_check); B(dispatcher_no_check);
SwitchToNearCode(); SwitchToNearCode();
@ -866,9 +867,10 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
SetJumpTarget(fail); SetJumpTarget(fail);
MOVI2R(DISPATCHER_PC, js.blockStart); MOVI2R(DISPATCHER_PC, js.blockStart);
STR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); STR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc));
MOVI2R(ARM64Reg::W0, static_cast<u32>(JitInterface::ExceptionType::PairedQuantize)); MOVP2R(ARM64Reg::X0, &m_system.GetJitInterface());
MOVP2R(ARM64Reg::X1, &JitInterface::CompileExceptionCheck); MOVI2R(ARM64Reg::W1, static_cast<u32>(JitInterface::ExceptionType::PairedQuantize));
BLR(ARM64Reg::X1); MOVP2R(ARM64Reg::X2, &JitInterface::CompileExceptionCheckFromJIT);
BLR(ARM64Reg::X2);
B(dispatcher_no_check); B(dispatcher_no_check);
SwitchToNearCode(); SwitchToNearCode();
SetJumpTarget(no_fail); SetJumpTarget(no_fail);

View file

@ -770,11 +770,12 @@ void JitArm64::dcbx(UGeckoInstruction inst)
ABI_PushRegisters(gprs_to_push); ABI_PushRegisters(gprs_to_push);
m_float_emit.ABI_PushRegisters(fprs_to_push, WA); 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) if (make_loop)
MOVP2R(ARM64Reg::X8, &JitInterface::InvalidateICacheLines); MOVP2R(ARM64Reg::X8, &JitInterface::InvalidateICacheLinesFromJIT);
else else
MOVP2R(ARM64Reg::X8, &JitInterface::InvalidateICacheLine); MOVP2R(ARM64Reg::X8, &JitInterface::InvalidateICacheLineFromJIT);
BLR(ARM64Reg::X8); BLR(ARM64Reg::X8);
m_float_emit.ABI_PopRegisters(fprs_to_push, WA); m_float_emit.ABI_PopRegisters(fprs_to_push, WA);

View file

@ -40,19 +40,24 @@
#include "Core/PowerPC/JitArm64/Jit.h" #include "Core/PowerPC/JitArm64/Jit.h"
#endif #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(std::unique_ptr<JitBase> jit)
{ {
if (g_jit && p.IsReadMode()) m_jit = std::move(jit);
g_jit->ClearCache();
} }
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(); auto& system = Core::System::GetInstance();
@ -60,42 +65,42 @@ CPUCoreBase* InitJitCore(PowerPC::CPUCore core)
{ {
#if _M_X86 #if _M_X86
case PowerPC::CPUCore::JIT64: case PowerPC::CPUCore::JIT64:
g_jit = new Jit64(system); m_jit = std::make_unique<Jit64>(system);
break; break;
#endif #endif
#if _M_ARM_64 #if _M_ARM_64
case PowerPC::CPUCore::JITARM64: case PowerPC::CPUCore::JITARM64:
g_jit = new JitArm64(system); m_jit = std::make_unique<JitArm64>(system);
break; break;
#endif #endif
case PowerPC::CPUCore::CachedInterpreter: case PowerPC::CPUCore::CachedInterpreter:
g_jit = new CachedInterpreter(system); m_jit = std::make_unique<CachedInterpreter>(system);
break; break;
default: default:
// Under this case the caller overrides the CPU core to the default and logs that // Under this case the caller overrides the CPU core to the default and logs that
// it performed the override. // it performed the override.
g_jit = nullptr; m_jit.reset();
return nullptr; return nullptr;
} }
g_jit->Init(); m_jit->Init();
return g_jit; return m_jit.get();
} }
CPUCoreBase* GetCore() CPUCoreBase* JitInterface::GetCore() const
{ {
return g_jit; return m_jit.get();
} }
void SetProfilingState(ProfilingState state) void JitInterface::SetProfilingState(ProfilingState state)
{ {
if (!g_jit) if (!m_jit)
return; 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; Profiler::ProfileStats prof_stats;
GetProfileResults(&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 // Can't really do this with no m_jit core available
if (!g_jit) if (!m_jit)
return; return;
prof_stats->cost_sum = 0; prof_stats->cost_sum = 0;
prof_stats->timecost_sum = 0; prof_stats->timecost_sum = 0;
prof_stats->block_stats.clear(); prof_stats->block_stats.clear();
Core::RunAsCPUThread([&prof_stats] { Core::RunAsCPUThread([this, &prof_stats] {
QueryPerformanceFrequency((LARGE_INTEGER*)&prof_stats->countsPerSec); 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; const auto& data = block.profile_data;
u64 cost = data.downcountCounter; u64 cost = data.downcountCounter;
u64 timecost = data.ticCounter; u64 timecost = data.ticCounter;
@ -150,20 +155,21 @@ void GetProfileResults(Profiler::ProfileStats* prof_stats)
}); });
} }
std::variant<GetHostCodeError, GetHostCodeResult> GetHostCode(u32 address) std::variant<JitInterface::GetHostCodeError, JitInterface::GetHostCodeResult>
JitInterface::GetHostCode(u32 address) const
{ {
if (!g_jit) if (!m_jit)
{ {
return GetHostCodeError::NoJitActive; return GetHostCodeError::NoJitActive;
} }
JitBlock* block = JitBlock* block =
g_jit->GetBlockCache()->GetBlockFromStartAddress(address, PowerPC::ppcState.msr.Hex); m_jit->GetBlockCache()->GetBlockFromStartAddress(address, PowerPC::ppcState.msr.Hex);
if (!block) if (!block)
{ {
for (int i = 0; i < 500; i++) 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); PowerPC::ppcState.msr.Hex);
if (block) if (block)
break; break;
@ -190,51 +196,52 @@ std::variant<GetHostCodeError, GetHostCodeResult> GetHostCode(u32 address)
return result; 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 // Prevent nullptr dereference on a crash with no JIT present
if (!g_jit) if (!m_jit)
{ {
return false; 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 false;
} }
return g_jit->HandleStackFault(); return m_jit->HandleStackFault();
} }
void ClearCache() void JitInterface::ClearCache()
{ {
if (g_jit) if (m_jit)
g_jit->ClearCache(); m_jit->ClearCache();
}
void ClearSafe()
{
if (g_jit)
g_jit->GetBlockCache()->Clear();
} }
void InvalidateICache(u32 address, u32 size, bool forced) void JitInterface::ClearSafe()
{ {
if (g_jit) if (m_jit)
g_jit->GetBlockCache()->InvalidateICache(address, size, forced); m_jit->GetBlockCache()->Clear();
} }
void InvalidateICacheLine(u32 address) void JitInterface::InvalidateICache(u32 address, u32 size, bool forced)
{ {
if (g_jit) if (m_jit)
g_jit->GetBlockCache()->InvalidateICacheLine(address); 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: // This corresponds to a PPC code loop that:
// - calls some form of dcb* instruction on 'address' // - calls some form of dcb* instruction on 'address'
@ -250,9 +257,19 @@ void InvalidateICacheLines(u32 address, u32 count)
InvalidateICache(address & ~0x1f, 32 * count, false); 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; return;
std::unordered_set<u32>* exception_addresses = nullptr; std::unordered_set<u32>* exception_addresses = nullptr;
@ -260,13 +277,13 @@ void CompileExceptionCheck(ExceptionType type)
switch (type) switch (type)
{ {
case ExceptionType::FIFOWrite: case ExceptionType::FIFOWrite:
exception_addresses = &g_jit->js.fifoWriteAddresses; exception_addresses = &m_jit->js.fifoWriteAddresses;
break; break;
case ExceptionType::PairedQuantize: case ExceptionType::PairedQuantize:
exception_addresses = &g_jit->js.pairedQuantizeAddresses; exception_addresses = &m_jit->js.pairedQuantizeAddresses;
break; break;
case ExceptionType::SpeculativeConstants: case ExceptionType::SpeculativeConstants:
exception_addresses = &g_jit->js.noSpeculativeConstantsAddresses; exception_addresses = &m_jit->js.noSpeculativeConstantsAddresses;
break; break;
} }
@ -288,17 +305,20 @@ void CompileExceptionCheck(ExceptionType type)
// Invalidate the JIT block so that it gets recompiled with the external exception check // Invalidate the JIT block so that it gets recompiled with the external exception check
// included. // 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()
{ {
g_jit->Shutdown(); if (m_jit)
delete g_jit; {
g_jit = nullptr; m_jit->Shutdown();
m_jit.reset();
} }
} }
} // namespace JitInterface

View file

@ -3,6 +3,7 @@
#pragma once #pragma once
#include <memory>
#include <string> #include <string>
#include <variant> #include <variant>
@ -13,6 +14,10 @@ class CPUCoreBase;
class PointerWrap; class PointerWrap;
class JitBase; class JitBase;
namespace Core
{
class System;
}
namespace PowerPC namespace PowerPC
{ {
enum class CPUCore; enum class CPUCore;
@ -23,19 +28,20 @@ namespace Profiler
struct ProfileStats; struct ProfileStats;
} }
namespace JitInterface class JitInterface
{ {
enum class ExceptionType public:
{ explicit JitInterface(Core::System& system);
FIFOWrite, JitInterface(const JitInterface&) = delete;
PairedQuantize, JitInterface(JitInterface&&) = delete;
SpeculativeConstants JitInterface& operator=(const JitInterface&) = delete;
}; JitInterface& operator=(JitInterface&&) = delete;
~JitInterface();
void DoState(PointerWrap& p); void DoState(PointerWrap& p);
CPUCoreBase* InitJitCore(PowerPC::CPUCore core); CPUCoreBase* InitJitCore(PowerPC::CPUCore core);
CPUCoreBase* GetCore(); CPUCoreBase* GetCore() const;
// Debugging // Debugging
enum class ProfilingState enum class ProfilingState
@ -43,7 +49,6 @@ enum class ProfilingState
Enabled, Enabled,
Disabled Disabled
}; };
enum class GetHostCodeError enum class GetHostCodeError
{ {
NoJitActive, NoJitActive,
@ -57,9 +62,9 @@ struct GetHostCodeResult
}; };
void SetProfilingState(ProfilingState state); void SetProfilingState(ProfilingState state);
void WriteProfileResults(const std::string& filename); void WriteProfileResults(const std::string& filename) const;
void GetProfileResults(Profiler::ProfileStats* prof_stats); void GetProfileResults(Profiler::ProfileStats* prof_stats) const;
std::variant<GetHostCodeError, GetHostCodeResult> GetHostCode(u32 address); std::variant<GetHostCodeError, GetHostCodeResult> GetHostCode(u32 address) const;
// Memory Utilities // Memory Utilities
bool HandleFault(uintptr_t access_address, SContext* ctx); bool HandleFault(uintptr_t access_address, SContext* ctx);
@ -77,11 +82,24 @@ void ClearSafe();
void InvalidateICache(u32 address, u32 size, bool forced); void InvalidateICache(u32 address, u32 size, bool forced);
void InvalidateICacheLine(u32 address); void InvalidateICacheLine(u32 address);
void InvalidateICacheLines(u32 address, u32 count); 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); 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! /// used for the page fault unit test, don't use outside of tests!
void SetJit(JitBase* jit); void SetJit(std::unique_ptr<JitBase> jit);
void Shutdown(); void Shutdown();
} // namespace JitInterface
private:
std::unique_ptr<JitBase> m_jit;
Core::System& m_system;
};

View file

@ -1770,7 +1770,7 @@ void DBATUpdated()
#endif #endif
// IsOptimizable*Address and dcbz depends on the BAT mapping, so we need a flush here. // IsOptimizable*Address and dcbz depends on the BAT mapping, so we need a flush here.
JitInterface::ClearSafe(); system.GetJitInterface().ClearSafe();
} }
void IBATUpdated() void IBATUpdated()
@ -1789,7 +1789,7 @@ void IBATUpdated()
UpdateFakeMMUBat(ibat_table, 0x40000000); UpdateFakeMMUBat(ibat_table, 0x40000000);
UpdateFakeMMUBat(ibat_table, 0x70000000); UpdateFakeMMUBat(ibat_table, 0x70000000);
} }
JitInterface::ClearSafe(); system.GetJitInterface().ClearSafe();
} }
// Translate effective address using BAT or PAT. Returns 0 if the address cannot be translated. // Translate effective address using BAT or PAT. Returns 0 if the address cannot be translated.

View file

@ -107,7 +107,7 @@ void Cache::Reset()
void InstructionCache::Reset() void InstructionCache::Reset()
{ {
Cache::Reset(); Cache::Reset();
JitInterface::ClearSafe(); Core::System::GetInstance().GetJitInterface().ClearSafe();
} }
void Cache::Init() void Cache::Init()
@ -424,7 +424,7 @@ void InstructionCache::Invalidate(u32 addr)
valid[set] = 0; valid[set] = 0;
modified[set] = 0; modified[set] = 0;
JitInterface::InvalidateICacheLine(addr); Core::System::GetInstance().GetJitInterface().InvalidateICacheLine(addr);
} }
void InstructionCache::RefreshConfig() void InstructionCache::RefreshConfig()

View file

@ -153,7 +153,7 @@ void DoState(PointerWrap& p)
// SystemTimers::DecrementerSet(); // SystemTimers::DecrementerSet();
// SystemTimers::TimeBaseSet(); // SystemTimers::TimeBaseSet();
JitInterface::DoState(p); Core::System::GetInstance().GetJitInterface().DoState(p);
} }
static void ResetRegisters() static void ResetRegisters()
@ -219,7 +219,8 @@ static void InitializeCPUCore(CPUCore cpu_core)
{ {
// We initialize the interpreter because // We initialize the interpreter because
// it is used on boot and code window independently. // 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(); interpreter.Init();
switch (cpu_core) switch (cpu_core)
@ -229,12 +230,12 @@ static void InitializeCPUCore(CPUCore cpu_core)
break; break;
default: 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 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.", WARN_LOG_FMT(POWERPC, "CPU core {} not available. Falling back to default.",
static_cast<int>(cpu_core)); static_cast<int>(cpu_core));
s_cpu_core_base = JitInterface::InitJitCore(DefaultCPUCore()); s_cpu_core_base = system.GetJitInterface().InitJitCore(DefaultCPUCore());
} }
break; break;
} }
@ -315,8 +316,9 @@ void ScheduleInvalidateCacheThreadSafe(u32 address)
void Shutdown() void Shutdown()
{ {
InjectExternalCPUCore(nullptr); InjectExternalCPUCore(nullptr);
JitInterface::Shutdown(); auto& system = Core::System::GetInstance();
auto& interpreter = Core::System::GetInstance().GetInterpreter(); system.GetJitInterface().Shutdown();
auto& interpreter = system.GetInterpreter();
interpreter.Shutdown(); interpreter.Shutdown();
s_cpu_core_base = nullptr; s_cpu_core_base = nullptr;
} }
@ -328,7 +330,8 @@ CoreMode GetMode()
static void ApplyMode() static void ApplyMode()
{ {
auto& interpreter = Core::System::GetInstance().GetInterpreter(); auto& system = Core::System::GetInstance();
auto& interpreter = system.GetInterpreter();
switch (s_mode) switch (s_mode)
{ {
@ -338,7 +341,7 @@ static void ApplyMode()
case CoreMode::JIT: // Switching from interpreter to JIT. case CoreMode::JIT: // Switching from interpreter to JIT.
// Don't really need to do much. It'll work, the cache will refill itself. // 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 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; s_cpu_core_base = &interpreter;
break; break;

View file

@ -23,6 +23,7 @@
#include "Core/HW/Sram.h" #include "Core/HW/Sram.h"
#include "Core/HW/VideoInterface.h" #include "Core/HW/VideoInterface.h"
#include "Core/PowerPC/Interpreter/Interpreter.h" #include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "IOS/USB/Emulated/Skylander.h" #include "IOS/USB/Emulated/Skylander.h"
#include "VideoCommon/CommandProcessor.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_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_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_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; VertexShaderManager m_vertex_shader_manager;
VideoInterface::VideoInterfaceManager m_video_interface; VideoInterface::VideoInterfaceManager m_video_interface;
Interpreter m_interpreter; Interpreter m_interpreter;
JitInterface m_jit_interface;
}; };
System::System() : m_impl{std::make_unique<Impl>(*this)} System::System() : m_impl{std::make_unique<Impl>(*this)}
@ -182,6 +184,11 @@ Interpreter& System::GetInterpreter() const
return m_impl->m_interpreter; return m_impl->m_interpreter;
} }
JitInterface& System::GetJitInterface() const
{
return m_impl->m_jit_interface;
}
IOS::HLE::USB::SkylanderPortal& System::GetSkylanderPortal() const IOS::HLE::USB::SkylanderPortal& System::GetSkylanderPortal() const
{ {
return m_impl->m_skylander_portal; return m_impl->m_skylander_portal;

View file

@ -7,6 +7,7 @@
class GeometryShaderManager; class GeometryShaderManager;
class Interpreter; class Interpreter;
class JitInterface;
class PixelShaderManager; class PixelShaderManager;
class SoundStream; class SoundStream;
struct Sram; struct Sram;
@ -133,6 +134,7 @@ public:
GPFifo::GPFifoManager& GetGPFifo() const; GPFifo::GPFifoManager& GetGPFifo() const;
HSP::HSPManager& GetHSP() const; HSP::HSPManager& GetHSP() const;
Interpreter& GetInterpreter() const; Interpreter& GetInterpreter() const;
JitInterface& GetJitInterface() const;
IOS::HLE::USB::SkylanderPortal& GetSkylanderPortal() const; IOS::HLE::USB::SkylanderPortal& GetSkylanderPortal() const;
Memory::MemoryManager& GetMemory() const; Memory::MemoryManager& GetMemory() const;
MemoryInterface::MemoryInterfaceManager& GetMemoryInterface() const; MemoryInterface::MemoryInterfaceManager& GetMemoryInterface() const;

View file

@ -140,7 +140,8 @@ void CodeDiffDialog::ClearData()
// Swap is used instead of clear for efficiency in the case of huge m_include/m_exclude // Swap is used instead of clear for efficiency in the case of huge m_include/m_exclude
std::vector<Diff>().swap(m_include); std::vector<Diff>().swap(m_include);
std::vector<Diff>().swap(m_exclude); std::vector<Diff>().swap(m_exclude);
JitInterface::SetProfilingState(JitInterface::ProfilingState::Disabled); Core::System::GetInstance().GetJitInterface().SetProfilingState(
JitInterface::ProfilingState::Disabled);
} }
void CodeDiffDialog::ClearBlockCache() void CodeDiffDialog::ClearBlockCache()
@ -150,7 +151,7 @@ void CodeDiffDialog::ClearBlockCache()
if (old_state == Core::State::Running) if (old_state == Core::State::Running)
Core::SetState(Core::State::Paused); Core::SetState(Core::State::Paused);
JitInterface::ClearCache(); Core::System::GetInstance().GetJitInterface().ClearCache();
if (old_state == Core::State::Running) if (old_state == Core::State::Running)
Core::SetState(Core::State::Running); Core::SetState(Core::State::Running);
@ -205,7 +206,7 @@ void CodeDiffDialog::OnRecord(bool enabled)
} }
m_record_btn->update(); m_record_btn->update();
JitInterface::SetProfilingState(state); Core::System::GetInstance().GetJitInterface().SetProfilingState(state);
} }
void CodeDiffDialog::OnInclude() void CodeDiffDialog::OnInclude()
@ -271,7 +272,7 @@ std::vector<Diff> CodeDiffDialog::CalculateSymbolsFromProfile()
{ {
Profiler::ProfileStats prof_stats; Profiler::ProfileStats prof_stats;
auto& blockstats = prof_stats.block_stats; auto& blockstats = prof_stats.block_stats;
JitInterface::GetProfileResults(&prof_stats); Core::System::GetInstance().GetJitInterface().GetProfileResults(&prof_stats);
std::vector<Diff> current; std::vector<Diff> current;
current.reserve(20000); 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_exclude_size_label->setText(tr("Excluded: %1").arg(m_exclude.size()));
m_include_size_label->setText(tr("Included: %1").arg(m_include.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) if (old_state == Core::State::Running)
Core::SetState(Core::State::Running); Core::SetState(Core::State::Running);
} }

View file

@ -1671,7 +1671,7 @@ void MenuBar::PatchHLEFunctions()
void MenuBar::ClearCache() void MenuBar::ClearCache()
{ {
Core::RunAsCPUThread(JitInterface::ClearCache); Core::RunAsCPUThread([] { Core::System::GetInstance().GetJitInterface().ClearCache(); });
} }
void MenuBar::LogInstructions() void MenuBar::LogInstructions()

View file

@ -16,6 +16,7 @@
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/VariantUtil.h" #include "Common/VariantUtil.h"
#include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/JitInterface.h"
#include "Core/System.h"
#if defined(HAVE_LLVM) #if defined(HAVE_LLVM)
class HostDisassemblerLLVM : public HostDisassembler class HostDisassemblerLLVM : public HostDisassembler
@ -170,7 +171,7 @@ std::unique_ptr<HostDisassembler> GetNewDisassembler(const std::string& arch)
DisassembleResult DisassembleBlock(HostDisassembler* disasm, u32 address) 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) { return std::visit(overloaded{[&](JitInterface::GetHostCodeError error) {
DisassembleResult result; DisassembleResult result;

View file

@ -75,8 +75,10 @@ TEST(PageFault, PageFault)
EXPECT_NE(data, nullptr); EXPECT_NE(data, nullptr);
Common::WriteProtectMemory(data, PAGE_GRAN, false); Common::WriteProtectMemory(data, PAGE_GRAN, false);
PageFaultFakeJit pfjit(Core::System::GetInstance()); auto& system = Core::System::GetInstance();
JitInterface::SetJit(&pfjit); auto unique_pfjit = std::make_unique<PageFaultFakeJit>(system);
auto& pfjit = *unique_pfjit;
system.GetJitInterface().SetJit(std::move(unique_pfjit));
pfjit.m_data = data; pfjit.m_data = data;
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
@ -88,7 +90,6 @@ TEST(PageFault, PageFault)
}; };
EMM::UninstallExceptionHandler(); EMM::UninstallExceptionHandler();
JitInterface::SetJit(nullptr);
fmt::print("page fault timing:\n"); fmt::print("page fault timing:\n");
fmt::print("start->HandleFault {} ns\n", fmt::print("start->HandleFault {} ns\n",
@ -98,4 +99,6 @@ TEST(PageFault, PageFault)
fmt::print("HandleFault->end {} ns\n", fmt::print("HandleFault->end {} ns\n",
difference_in_nanoseconds(pfjit.m_post_unprotect_time, end)); difference_in_nanoseconds(pfjit.m_post_unprotect_time, end));
fmt::print("total {} ns\n", difference_in_nanoseconds(start, end)); fmt::print("total {} ns\n", difference_in_nanoseconds(start, end));
system.GetJitInterface().SetJit(nullptr);
} }