From 4b25538f2f45a61cb345b00662698846dc454f4e Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 14 May 2018 03:02:46 -0400 Subject: [PATCH 1/3] CachedInterpreter: Factor function hooking code out of Jit() Extracts the self-contained code into its own function to clean up the flow of Jit() a little more. This also introduces a helper function to HLE.h that will be used to reduce the boilerplate here and in the interpreter and Jit64 in the following commits. This function performs all of the preliminary checks required prior to attempting to hook/replace a function at a given address. The function then calls a provided object that satisfies the FunctionObject concept in the C++ standard library. This can be a lambda, a regular function pointer, an object with an overloaded function call operator, etc. The only requirement is that the function return a bool, indicating whether or not the function was replaced, and that it can take parameters in the form: fn(u32 function, HLE::HookType type) --- Source/Core/Core/HLE/HLE.h | 29 +++++++++++++++ .../CachedInterpreter/CachedInterpreter.cpp | 37 +++++++++---------- .../CachedInterpreter/CachedInterpreter.h | 2 + 3 files changed, 48 insertions(+), 20 deletions(-) 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; From f3c13402e80aa390a014fc767a6b80d7c91c7e7c Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 16 May 2018 18:16:59 -0400 Subject: [PATCH 2/3] Interpreter: Factor function hooking code out of SingleStepInner() --- .../Core/PowerPC/Interpreter/Interpreter.cpp | 33 +++++-------------- .../Core/PowerPC/Interpreter/Interpreter.h | 2 ++ 2 files changed, 11 insertions(+), 24 deletions(-) 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(); From 3400165171962c1405e486477a6668eb8a3af902 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 16 May 2018 18:29:09 -0400 Subject: [PATCH 3/3] Jit64: Factor function hooking out of DoJit() --- Source/Core/Core/PowerPC/Jit64/Jit.cpp | 37 ++++++++++++-------------- Source/Core/Core/PowerPC/Jit64/Jit.h | 2 ++ 2 files changed, 19 insertions(+), 20 deletions(-) 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();