diff --git a/Source/Core/Core/HLE/HLE.h b/Source/Core/Core/HLE/HLE.h index a944c6b56c..9f851e0396 100644 --- a/Source/Core/Core/HLE/HLE.h +++ b/Source/Core/Core/HLE/HLE.h @@ -42,4 +42,33 @@ HookType GetFunctionTypeByIndex(u32 index); HookFlag GetFunctionFlagsByIndex(u32 index); bool IsEnabled(HookFlag flag); + +// Performs the backend-independent preliminary checking before calling a +// FunctionObject to do the actual replacing. Typically, this callback will +// be in the backend itself, containing the backend-specific portions +// required in replacing a function. +// +// fn may be any object that satisfies the FunctionObject concept in the C++ +// standard library. That is, any lambda, object with an overloaded function +// call operator, or regular function pointer. +// +// fn must return a bool indicating whether or not function replacing occurred. +// fn must also accept a parameter list of the form: fn(u32 function, HLE::HookType type). +template +bool ReplaceFunctionIfPossible(u32 address, FunctionObject fn) +{ + const u32 function = GetFirstFunctionIndex(address); + if (function == 0) + return false; + + const HookType type = GetFunctionTypeByIndex(function); + if (type != HookType::Start && type != HookType::Replace) + return false; + + const HookFlag flags = GetFunctionFlagsByIndex(function); + if (!IsEnabled(flags)) + return false; + + return fn(function, type); } +} // namespace HLE diff --git a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp index d6d85f727d..d2da611cfb 100644 --- a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp +++ b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp @@ -171,6 +171,21 @@ static bool CheckDSI(u32 data) return false; } +bool CachedInterpreter::HandleFunctionHooking(u32 address) +{ + return HLE::ReplaceFunctionIfPossible(address, [&](u32 function, HLE::HookType type) { + m_code.emplace_back(WritePC, address); + m_code.emplace_back(Interpreter::HLEFunction, function); + + if (type != HLE::HookType::Replace) + return false; + + m_code.emplace_back(EndBlock, js.downcountAmount); + m_code.emplace_back(); + return true; + }); +} + void CachedInterpreter::Jit(u32 address) { if (m_code.size() >= CODE_SIZE / sizeof(Instruction) - 0x1000 || @@ -208,26 +223,8 @@ void CachedInterpreter::Jit(u32 address) js.downcountAmount += op.opinfo->numCycles; - u32 function = HLE::GetFirstFunctionIndex(op.address); - if (function != 0) - { - HLE::HookType type = HLE::GetFunctionTypeByIndex(function); - if (type == HLE::HookType::Start || type == HLE::HookType::Replace) - { - HLE::HookFlag flags = HLE::GetFunctionFlagsByIndex(function); - if (HLE::IsEnabled(flags)) - { - m_code.emplace_back(WritePC, op.address); - m_code.emplace_back(Interpreter::HLEFunction, function); - if (type == HLE::HookType::Replace) - { - m_code.emplace_back(EndBlock, js.downcountAmount); - m_code.emplace_back(); - break; - } - } - } - } + if (HandleFunctionHooking(op.address)) + break; if (!op.skip) { diff --git a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.h b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.h index 733072b0f5..b7dbd5cfdd 100644 --- a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.h +++ b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.h @@ -38,6 +38,8 @@ private: const u8* GetCodePtr() const; void ExecuteOneBlock(); + bool HandleFunctionHooking(u32 address); + BlockCache m_block_cache{*this}; std::vector m_code; PPCAnalyst::CodeBuffer code_buffer; diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp index 946a3d8101..f88936654f 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp @@ -99,32 +99,17 @@ static void Trace(UGeckoInstruction& inst) PowerPC::ppcState.spr[8], regs.c_str(), inst.hex, ppc_inst.c_str()); } +bool Interpreter::HandleFunctionHooking(u32 address) +{ + return HLE::ReplaceFunctionIfPossible(address, [](u32 function, HLE::HookType type) { + HLEFunction(function); + return type != HLE::HookType::Start; + }); +} + int Interpreter::SingleStepInner() { - u32 function = HLE::GetFirstFunctionIndex(PC); - if (function != 0) - { - HLE::HookType type = HLE::GetFunctionTypeByIndex(function); - if (type == HLE::HookType::Start || type == HLE::HookType::Replace) - { - HLE::HookFlag flags = HLE::GetFunctionFlagsByIndex(function); - if (HLE::IsEnabled(flags)) - { - HLEFunction(function); - if (type == HLE::HookType::Start) - { - // Run the original. - function = 0; - } - } - else - { - function = 0; - } - } - } - - if (function == 0) + if (!HandleFunctionHooking(PC)) { #ifdef USE_GDBSTUB if (gdb_active() && gdb_bp_x(PC)) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.h b/Source/Core/Core/PowerPC/Interpreter/Interpreter.h index 863dc0cb5b..dd4c88d94c 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.h +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.h @@ -284,6 +284,8 @@ public: private: static void InitializeInstructionTables(); + static bool HandleFunctionHooking(u32 address); + // flag helper static void Helper_UpdateCR0(u32 value); static void Helper_UpdateCR1(); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index b266962324..9f45027415 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -806,26 +806,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBloc SetJumpTarget(noExtIntEnable); } - u32 function = HLE::GetFirstFunctionIndex(op.address); - if (function != 0) - { - HLE::HookType type = HLE::GetFunctionTypeByIndex(function); - if (type == HLE::HookType::Start || type == HLE::HookType::Replace) - { - HLE::HookFlag flags = HLE::GetFunctionFlagsByIndex(function); - if (HLE::IsEnabled(flags)) - { - HLEFunction(function); - if (type == HLE::HookType::Replace) - { - MOV(32, R(RSCRATCH), PPCSTATE(npc)); - js.downcountAmount += js.st.numCycles; - WriteExitDestInRSCRATCH(); - break; - } - } - } - } + if (HandleFunctionHooking(op.address)) + break; if (!op.skip) { @@ -1042,3 +1024,18 @@ void Jit64::IntializeSpeculativeConstants() } } } + +bool Jit64::HandleFunctionHooking(u32 address) +{ + return HLE::ReplaceFunctionIfPossible(address, [&](u32 function, HLE::HookType type) { + HLEFunction(function); + + if (type != HLE::HookType::Replace) + return false; + + MOV(32, R(RSCRATCH), PPCSTATE(npc)); + js.downcountAmount += js.st.numCycles; + WriteExitDestInRSCRATCH(); + return true; + }); +} diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.h b/Source/Core/Core/PowerPC/Jit64/Jit.h index 634eb68b6c..ce8de7509b 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/PowerPC/Jit64/Jit.h @@ -234,6 +234,8 @@ private: static void InitializeInstructionTables(); void CompileInstruction(PPCAnalyst::CodeOp& op); + bool HandleFunctionHooking(u32 address); + void AllocStack(); void FreeStack();