Merge pull request #6856 from lioncash/cached-hook

PowerPC: Factor common part of function hooking code out of the interpreter and JITs
This commit is contained in:
Markus Wick 2018-05-17 09:45:17 +02:00 committed by GitHub
commit 1424964678
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 78 additions and 64 deletions

View File

@ -42,4 +42,33 @@ HookType GetFunctionTypeByIndex(u32 index);
HookFlag GetFunctionFlagsByIndex(u32 index); HookFlag GetFunctionFlagsByIndex(u32 index);
bool IsEnabled(HookFlag flag); 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 <typename FunctionObject>
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

View File

@ -171,6 +171,21 @@ static bool CheckDSI(u32 data)
return false; 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) void CachedInterpreter::Jit(u32 address)
{ {
if (m_code.size() >= CODE_SIZE / sizeof(Instruction) - 0x1000 || if (m_code.size() >= CODE_SIZE / sizeof(Instruction) - 0x1000 ||
@ -208,26 +223,8 @@ void CachedInterpreter::Jit(u32 address)
js.downcountAmount += op.opinfo->numCycles; js.downcountAmount += op.opinfo->numCycles;
u32 function = HLE::GetFirstFunctionIndex(op.address); if (HandleFunctionHooking(op.address))
if (function != 0) break;
{
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 (!op.skip) if (!op.skip)
{ {

View File

@ -38,6 +38,8 @@ private:
const u8* GetCodePtr() const; const u8* GetCodePtr() const;
void ExecuteOneBlock(); void ExecuteOneBlock();
bool HandleFunctionHooking(u32 address);
BlockCache m_block_cache{*this}; BlockCache m_block_cache{*this};
std::vector<Instruction> m_code; std::vector<Instruction> m_code;
PPCAnalyst::CodeBuffer code_buffer; PPCAnalyst::CodeBuffer code_buffer;

View File

@ -99,32 +99,17 @@ static void Trace(UGeckoInstruction& inst)
PowerPC::ppcState.spr[8], regs.c_str(), inst.hex, ppc_inst.c_str()); 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() int Interpreter::SingleStepInner()
{ {
u32 function = HLE::GetFirstFunctionIndex(PC); if (!HandleFunctionHooking(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)
{ {
#ifdef USE_GDBSTUB #ifdef USE_GDBSTUB
if (gdb_active() && gdb_bp_x(PC)) if (gdb_active() && gdb_bp_x(PC))

View File

@ -284,6 +284,8 @@ public:
private: private:
static void InitializeInstructionTables(); static void InitializeInstructionTables();
static bool HandleFunctionHooking(u32 address);
// flag helper // flag helper
static void Helper_UpdateCR0(u32 value); static void Helper_UpdateCR0(u32 value);
static void Helper_UpdateCR1(); static void Helper_UpdateCR1();

View File

@ -806,26 +806,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer* code_buf, JitBloc
SetJumpTarget(noExtIntEnable); SetJumpTarget(noExtIntEnable);
} }
u32 function = HLE::GetFirstFunctionIndex(op.address); if (HandleFunctionHooking(op.address))
if (function != 0) break;
{
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 (!op.skip) 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;
});
}

View File

@ -234,6 +234,8 @@ private:
static void InitializeInstructionTables(); static void InitializeInstructionTables();
void CompileInstruction(PPCAnalyst::CodeOp& op); void CompileInstruction(PPCAnalyst::CodeOp& op);
bool HandleFunctionHooking(u32 address);
void AllocStack(); void AllocStack();
void FreeStack(); void FreeStack();