Merge pull request #439 from unknownbrackets/jit-minor2

Jit breakpoints (x86 only)
This commit is contained in:
Henrik Rydgård 2013-01-19 01:15:37 -08:00
commit f93f348a46
9 changed files with 108 additions and 41 deletions

View File

@ -19,6 +19,7 @@
#include "Breakpoints.h"
#include "SymbolMap.h"
#include "FixedSizeUnorderedSet.h"
#include "../MIPS/JitCommon/JitCommon.h"
#include <cstdio>
#define MAX_BREAKPOINTS 16
@ -73,6 +74,7 @@ void CBreakPoints::RemoveBreakPoint(u32 _iAddress)
if (m_iBreakPoints[i].iAddress == _iAddress)
{
m_iBreakPoints.remove(m_iBreakPoints[i]);
InvalidateJit(_iAddress);
break;
}
}
@ -81,6 +83,7 @@ void CBreakPoints::RemoveBreakPoint(u32 _iAddress)
void CBreakPoints::ClearAllBreakPoints()
{
m_iBreakPoints.clear();
InvalidateJit();
}
MemCheck *CBreakPoints::GetMemCheck(u32 address)
@ -123,5 +126,20 @@ void CBreakPoints::AddBreakPoint(u32 _iAddress, bool temp)
pt.iAddress = _iAddress;
m_iBreakPoints.insert(pt);
InvalidateJit(_iAddress);
}
}
void CBreakPoints::InvalidateJit(u32 _iAddress)
{
// Don't want to clear cache while running, I think?
if (MIPSComp::jit && coreState == CORE_STEPPING)
MIPSComp::jit->ClearCacheAt(_iAddress);
}
void CBreakPoints::InvalidateJit()
{
// Don't want to clear cache while running, I think?
if (MIPSComp::jit && coreState == CORE_STEPPING)
MIPSComp::jit->ClearCache();
}

View File

@ -80,6 +80,9 @@ public:
static void RemoveBreakPoint(u32 _iAddress);
static void ClearAllBreakPoints();
static void InvalidateJit(u32 _iAddress);
static void InvalidateJit();
};

View File

@ -76,6 +76,12 @@ void Jit::ClearCache()
GenerateFixedCode();
}
void Jit::ClearCacheAt(u32 em_address)
{
// TODO: Properly.
ClearCache();
}
void Jit::CompileAt(u32 addr)
{
u32 op = Memory::Read_Instruction(addr);

View File

@ -89,6 +89,7 @@ public:
ArmJitBlockCache *GetBlockCache() { return &blocks; }
void ClearCache();
void ClearCacheAt(u32 em_address);
private:
void GenerateFixedCode();

View File

@ -45,20 +45,6 @@ using namespace MIPSAnalyst;
namespace MIPSComp
{
#ifdef _M_IX86
#define SAVE_FLAGS PUSHF();
#define LOAD_FLAGS POPF();
#else
static u64 saved_flags;
#define SAVE_FLAGS {PUSHF(); POP(64, R(EAX)); MOV(64, M(&saved_flags), R(EAX));}
#define LOAD_FLAGS {MOV(64, R(EAX), M(&saved_flags)); PUSH(64, R(EAX)); POPF();}
#endif
void Jit::BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely)
{
if (js.inDelaySlot) {
@ -96,12 +82,7 @@ void Jit::BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely)
Gen::FixupBranch ptr;
if (!likely)
{
if (!delaySlotIsNice)
SAVE_FLAGS; // preserve flag around the delay slot!
CompileAt(js.compilerPC + 4);
FlushAll();
if (!delaySlotIsNice)
LOAD_FLAGS; // restore flag!
CompileDelaySlot(js.compilerPC + 4, !delaySlotIsNice);
ptr = J_CC(cc, true);
}
else
@ -149,12 +130,7 @@ void Jit::BranchRSZeroComp(u32 op, Gen::CCFlags cc, bool likely)
js.inDelaySlot = true;
if (!likely)
{
if (!delaySlotIsNice)
SAVE_FLAGS; // preserve flag around the delay slot! Better hope the delay slot instruction doesn't need to fall back to interpreter...
CompileAt(js.compilerPC + 4);
FlushAll();
if (!delaySlotIsNice)
LOAD_FLAGS; // restore flag!
CompileDelaySlot(js.compilerPC + 4, !delaySlotIsNice);
ptr = J_CC(cc, true);
}
else
@ -241,12 +217,7 @@ void Jit::BranchFPFlag(u32 op, Gen::CCFlags cc, bool likely)
js.inDelaySlot = true;
if (!likely)
{
if (!delaySlotIsNice)
SAVE_FLAGS; // preserve flag around the delay slot!
CompileAt(js.compilerPC + 4);
FlushAll();
if (!delaySlotIsNice)
LOAD_FLAGS; // restore flag!
CompileDelaySlot(js.compilerPC + 4, !delaySlotIsNice);
ptr = J_CC(cc, true);
}
else
@ -314,12 +285,7 @@ void Jit::BranchVFPUFlag(u32 op, Gen::CCFlags cc, bool likely)
js.inDelaySlot = true;
if (!likely)
{
if (!delaySlotIsNice)
SAVE_FLAGS; // preserve flag around the delay slot!
CompileAt(js.compilerPC + 4);
FlushAll();
if (!delaySlotIsNice)
LOAD_FLAGS; // restore flag!
CompileDelaySlot(js.compilerPC + 4, !delaySlotIsNice);
ptr = J_CC(cc, true);
}
else

View File

@ -25,9 +25,35 @@
#include "RegCache.h"
#include "Jit.h"
#include "../../Host.h"
#include "../../Debugger/Breakpoints.h"
namespace MIPSComp
{
#ifdef _M_IX86
#define SAVE_FLAGS PUSHF();
#define LOAD_FLAGS POPF();
#else
static u64 saved_flags;
#define SAVE_FLAGS {PUSHF(); POP(64, R(EAX)); MOV(64, M(&saved_flags), R(EAX));}
#define LOAD_FLAGS {MOV(64, R(EAX), M(&saved_flags)); PUSH(64, R(EAX)); POPF();}
#endif
void JitBreakpoint()
{
Core_EnableStepping(true);
host->SetDebugMode(true);
if (CBreakPoints::IsTempBreakPoint(currentMIPS->pc))
CBreakPoints::RemoveBreakPoint(currentMIPS->pc);
}
Jit::Jit(MIPSState *mips) : blocks(mips), mips_(mips)
{
blocks.Init();
@ -49,8 +75,31 @@ void Jit::ClearCache()
ClearCodeSpace();
}
void Jit::ClearCacheAt(u32 em_address)
{
// TODO: Properly.
ClearCache();
}
void Jit::CompileDelaySlot(u32 addr, bool saveFlags)
{
// TODO: If we ever support conditional breakpoints, we need to handle the flags more carefully.
CheckJitBreakpoint(addr);
if (saveFlags)
SAVE_FLAGS; // preserve flag around the delay slot!
u32 op = Memory::Read_Instruction(addr);
MIPSCompileOp(op);
FlushAll();
if (saveFlags)
LOAD_FLAGS; // restore flag!
}
void Jit::CompileAt(u32 addr)
{
CheckJitBreakpoint(addr);
u32 op = Memory::Read_Instruction(addr);
MIPSCompileOp(op);
}
@ -105,6 +154,9 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b)
u32 inst = Memory::Read_Instruction(js.compilerPC);
js.downcountAmount += MIPSGetInstructionCycleEstimate(inst);
// Jit breakpoints are quite fast, so let's do them in release too.
CheckJitBreakpoint(js.compilerPC);
MIPSCompileOp(inst);
js.compilerPC += 4;
@ -171,4 +223,19 @@ void Jit::WriteSyscallExit()
JMP(asm_.dispatcherCheckCoreState, true);
}
bool Jit::CheckJitBreakpoint(u32 addr)
{
if (CBreakPoints::IsAddressBreakPoint(addr))
{
FlushAll();
MOV(32, M(&mips_->pc), Imm32(js.compilerPC));
CALL(&JitBreakpoint);
WriteSyscallExit();
return true;
}
return false;
}
} // namespace

View File

@ -31,6 +31,9 @@
namespace MIPSComp
{
// This is called when Jit hits a breakpoint.
void JitBreakpoint();
struct JitOptions
{
JitOptions()
@ -67,6 +70,7 @@ public:
void Compile(u32 em_address); // Compiles a block at current MIPS PC
const u8 *DoJit(u32 em_address, JitBlock *b);
void CompileDelaySlot(u32 addr, bool saveFlags = false);
void CompileAt(u32 addr);
void Comp_RunBlock(u32 op);
@ -95,6 +99,7 @@ public:
AsmRoutineManager &Asm() { return asm_; }
void ClearCache();
void ClearCacheAt(u32 em_address);
private:
void FlushAll();
@ -102,6 +107,7 @@ private:
void WriteExitDestInEAX();
// void WriteRfiExitDestInEAX();
void WriteSyscallExit();
bool CheckJitBreakpoint(u32 addr);
// Utility compilation functions
void BranchFPFlag(u32 op, Gen::CCFlags cc, bool likely);

View File

@ -62,7 +62,7 @@ using namespace Gen;
bool JitBlock::ContainsAddress(u32 em_address)
{
// WARNING - THIS DOES NOT WORK WITH INLINING ENABLED.
// WARNING - THIS DOES NOT WORK WITH JIT INLINING ENABLED.
return (em_address >= originalAddress && em_address < originalAddress + 4 * originalSize);
}

View File

@ -118,7 +118,7 @@ public:
int GetBlockNumberFromStartAddress(u32 em_address);
// slower, but can get numbers from within blocks, not just the first instruction.
// WARNING! WILL NOT WORK WITH INLINING ENABLED (not yet a feature but will be soon)
// WARNING! WILL NOT WORK WITH JIT INLINING ENABLED (not yet a feature but will be soon)
// Returns a list of block numbers - only one block can start at a particular address, but they CAN overlap.
// This one is slow so should only be used for one-shots from the debugger UI, not for anything during runtime.
void GetBlockNumbersFromAddress(u32 em_address, std::vector<int> *block_numbers);
@ -126,7 +126,7 @@ public:
u32 GetOriginalFirstOp(int block_num);
CompiledCode GetCompiledCodeFromBlock(int block_num);
// DOES NOT WORK CORRECTLY WITH INLINING
// DOES NOT WORK CORRECTLY WITH JIT INLINING
void InvalidateICache(u32 address, const u32 length);
void DestroyBlock(int block_num, bool invalidate);