Merge pull request #1678 from shygoo/debugger-opt
[Debugger] Optimize interpreter breakpoint and callback checks
This commit is contained in:
commit
b78a8d182d
|
@ -18,6 +18,7 @@
|
||||||
#include <Project64-core/N64System/N64Class.h>
|
#include <Project64-core/N64System/N64Class.h>
|
||||||
|
|
||||||
CBreakpoints::CBreakpoints() :
|
CBreakpoints::CBreakpoints() :
|
||||||
|
m_bHaveRegBP(false),
|
||||||
m_GPRWriteBP(0),
|
m_GPRWriteBP(0),
|
||||||
m_GPRReadBP(0),
|
m_GPRReadBP(0),
|
||||||
m_HIWriteBP(false),
|
m_HIWriteBP(false),
|
||||||
|
@ -359,22 +360,17 @@ size_t CBreakpoints::NumMemLocks()
|
||||||
return m_MemLocks.size();
|
return m_MemLocks.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBreakpoints::HaveAnyGPRWriteBP(void) { return m_GPRWriteBP != 0; }
|
void CBreakpoints::UpdateHaveRegBP(void)
|
||||||
bool CBreakpoints::HaveAnyGPRReadBP(void) { return m_GPRReadBP != 0; }
|
{
|
||||||
bool CBreakpoints::HaveGPRWriteBP(int nReg) { return (m_GPRWriteBP & (1 << nReg)) != 0; }
|
m_bHaveRegBP = HaveAnyGPRWriteBP() || HaveAnyGPRReadBP() || HaveHIWriteBP() || HaveHIReadBP() || HaveLOWriteBP() || HaveLOReadBP();
|
||||||
bool CBreakpoints::HaveGPRReadBP(int nReg) { return (m_GPRReadBP & (1 << nReg)) != 0; }
|
}
|
||||||
void CBreakpoints::ToggleGPRWriteBP(int nReg) { m_GPRWriteBP ^= (1 << nReg); }
|
|
||||||
void CBreakpoints::ToggleGPRReadBP(int nReg) { m_GPRReadBP ^= (1 << nReg); }
|
|
||||||
|
|
||||||
bool CBreakpoints::HaveHIWriteBP(void) { return m_HIWriteBP; }
|
void CBreakpoints::ToggleGPRWriteBP(int nReg) { m_GPRWriteBP ^= (1 << nReg); UpdateHaveRegBP(); }
|
||||||
bool CBreakpoints::HaveHIReadBP(void) { return m_HIReadBP; }
|
void CBreakpoints::ToggleGPRReadBP(int nReg) { m_GPRReadBP ^= (1 << nReg); UpdateHaveRegBP(); }
|
||||||
bool CBreakpoints::HaveLOWriteBP(void) { return m_LOWriteBP; }
|
void CBreakpoints::ToggleHIWriteBP(void) { m_HIWriteBP = !m_HIWriteBP; UpdateHaveRegBP(); }
|
||||||
bool CBreakpoints::HaveLOReadBP(void) { return m_LOReadBP; }
|
void CBreakpoints::ToggleHIReadBP(void) { m_HIReadBP = !m_HIReadBP; UpdateHaveRegBP(); }
|
||||||
|
void CBreakpoints::ToggleLOWriteBP(void) { m_LOWriteBP = !m_LOWriteBP; UpdateHaveRegBP(); }
|
||||||
void CBreakpoints::ToggleHIWriteBP(void) { m_HIWriteBP = !m_HIWriteBP; }
|
void CBreakpoints::ToggleLOReadBP(void) { m_LOReadBP = !m_LOReadBP; UpdateHaveRegBP(); }
|
||||||
void CBreakpoints::ToggleHIReadBP(void) { m_HIReadBP = !m_HIReadBP; }
|
|
||||||
void CBreakpoints::ToggleLOWriteBP(void) { m_LOWriteBP = !m_LOWriteBP; }
|
|
||||||
void CBreakpoints::ToggleLOReadBP(void) { m_LOReadBP = !m_LOReadBP; }
|
|
||||||
|
|
||||||
void CBreakpoints::PreUpdateBP()
|
void CBreakpoints::PreUpdateBP()
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,17 +67,19 @@ public:
|
||||||
void ClearMemLocks(void);
|
void ClearMemLocks(void);
|
||||||
size_t NumMemLocks(void);
|
size_t NumMemLocks(void);
|
||||||
|
|
||||||
bool HaveAnyGPRReadBP(void);
|
inline bool HaveRegBP(void) { return m_bHaveRegBP; }
|
||||||
bool HaveAnyGPRWriteBP(void);
|
inline bool HaveAnyGPRWriteBP(void) { return m_GPRWriteBP != 0; }
|
||||||
bool HaveGPRWriteBP(int nReg);
|
inline bool HaveAnyGPRReadBP(void) { return m_GPRReadBP != 0; }
|
||||||
bool HaveGPRReadBP(int nReg);
|
inline bool HaveGPRWriteBP(int nReg) { return (m_GPRWriteBP & (1 << nReg)) != 0; }
|
||||||
|
inline bool HaveGPRReadBP(int nReg) { return (m_GPRReadBP & (1 << nReg)) != 0; }
|
||||||
|
inline bool HaveHIWriteBP(void) { return m_HIWriteBP; }
|
||||||
|
inline bool HaveHIReadBP(void) { return m_HIReadBP; }
|
||||||
|
inline bool HaveLOWriteBP(void) { return m_LOWriteBP; }
|
||||||
|
inline bool HaveLOReadBP(void) { return m_LOReadBP; }
|
||||||
|
|
||||||
|
void UpdateHaveRegBP(void);
|
||||||
void ToggleGPRWriteBP(int nReg);
|
void ToggleGPRWriteBP(int nReg);
|
||||||
void ToggleGPRReadBP(int nReg);
|
void ToggleGPRReadBP(int nReg);
|
||||||
|
|
||||||
bool HaveHIWriteBP(void);
|
|
||||||
bool HaveHIReadBP(void);
|
|
||||||
bool HaveLOWriteBP(void);
|
|
||||||
bool HaveLOReadBP(void);
|
|
||||||
void ToggleHIWriteBP(void);
|
void ToggleHIWriteBP(void);
|
||||||
void ToggleHIReadBP(void);
|
void ToggleHIReadBP(void);
|
||||||
void ToggleLOWriteBP(void);
|
void ToggleLOWriteBP(void);
|
||||||
|
@ -95,6 +97,7 @@ private:
|
||||||
|
|
||||||
memlocks_t m_MemLocks;
|
memlocks_t m_MemLocks;
|
||||||
|
|
||||||
|
bool m_bHaveRegBP;
|
||||||
uint32_t m_GPRWriteBP, m_GPRReadBP;
|
uint32_t m_GPRWriteBP, m_GPRReadBP;
|
||||||
bool m_HIWriteBP, m_HIReadBP, m_LOWriteBP, m_LOReadBP;
|
bool m_HIWriteBP, m_HIReadBP, m_LOWriteBP, m_LOReadBP;
|
||||||
};
|
};
|
|
@ -24,28 +24,6 @@ CDebugStackTrace::~CDebugStackTrace()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDebugStackTrace::PushEntry(uint32_t routineAddress, uint32_t callingAddress)
|
|
||||||
{
|
|
||||||
if (m_EntriesIndex < STACKTRACE_MAX_ENTRIES)
|
|
||||||
{
|
|
||||||
m_Entries[m_EntriesIndex] = { routineAddress, callingAddress };
|
|
||||||
m_EntriesIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDebugStackTrace::PopEntry()
|
|
||||||
{
|
|
||||||
if (m_EntriesIndex > 0)
|
|
||||||
{
|
|
||||||
m_EntriesIndex--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDebugStackTrace::ClearEntries()
|
|
||||||
{
|
|
||||||
m_EntriesIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
LRESULT CDebugStackTrace::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
|
LRESULT CDebugStackTrace::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
|
||||||
{
|
{
|
||||||
DlgResize_Init();
|
DlgResize_Init();
|
||||||
|
|
|
@ -32,9 +32,27 @@ public:
|
||||||
|
|
||||||
void Refresh();
|
void Refresh();
|
||||||
|
|
||||||
void PushEntry(uint32_t routineAddress, uint32_t callingAddress);
|
inline void PushEntry(uint32_t routineAddress, uint32_t callingAddress)
|
||||||
void PopEntry();
|
{
|
||||||
void ClearEntries();
|
if (m_EntriesIndex < STACKTRACE_MAX_ENTRIES)
|
||||||
|
{
|
||||||
|
m_Entries[m_EntriesIndex] = { routineAddress, callingAddress };
|
||||||
|
m_EntriesIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PopEntry()
|
||||||
|
{
|
||||||
|
if (m_EntriesIndex > 0)
|
||||||
|
{
|
||||||
|
m_EntriesIndex--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ClearEntries()
|
||||||
|
{
|
||||||
|
m_EntriesIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -540,19 +540,19 @@ void CDebuggerUI::HandleCartToRamDMA(void)
|
||||||
// Called from the interpreter core at the beginning of every CPU step
|
// Called from the interpreter core at the beginning of every CPU step
|
||||||
void CDebuggerUI::CPUStepStarted()
|
void CDebuggerUI::CPUStepStarted()
|
||||||
{
|
{
|
||||||
|
uint32_t pc = g_Reg->m_PROGRAM_COUNTER;
|
||||||
|
COpInfo opInfo(R4300iOp::m_Opcode);
|
||||||
|
bool bStoreOp = opInfo.IsStoreCommand();
|
||||||
|
uint32_t storeAddress = bStoreOp ? opInfo.GetLoadStoreAddress() : 0;
|
||||||
|
|
||||||
if (isStepping() && bCPULoggingEnabled())
|
if (isStepping() && bCPULoggingEnabled())
|
||||||
{
|
{
|
||||||
Debug_RefreshCPULogWindow();
|
Debug_RefreshCPULogWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t pc = g_Reg->m_PROGRAM_COUNTER;
|
if(bStoreOp && m_Breakpoints->NumMemLocks() > 0)
|
||||||
COpInfo opInfo(R4300iOp::m_Opcode);
|
|
||||||
|
|
||||||
if (opInfo.IsStoreCommand())
|
|
||||||
{
|
{
|
||||||
uint32_t memoryAddress = opInfo.GetLoadStoreAddress();
|
if (m_Breakpoints->MemLockExists(storeAddress, opInfo.NumBytesToStore()))
|
||||||
|
|
||||||
if (m_Breakpoints->MemLockExists(memoryAddress, opInfo.NumBytesToStore()))
|
|
||||||
{
|
{
|
||||||
// Memory is locked, skip op
|
// Memory is locked, skip op
|
||||||
g_Settings->SaveBool(Debugger_SkipOp, true);
|
g_Settings->SaveBool(Debugger_SkipOp, true);
|
||||||
|
@ -560,6 +560,8 @@ void CDebuggerUI::CPUStepStarted()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_ScriptSystem->HaveCallbacks())
|
||||||
|
{
|
||||||
m_ScriptSystem->HookCPUExec()->InvokeByAddressInRange(pc);
|
m_ScriptSystem->HookCPUExec()->InvokeByAddressInRange(pc);
|
||||||
if (SkipOp()) { return; }
|
if (SkipOp()) { return; }
|
||||||
|
|
||||||
|
@ -569,27 +571,23 @@ void CDebuggerUI::CPUStepStarted()
|
||||||
m_ScriptSystem->HookCPUGPRValue()->InvokeByAddressInRange_GPRValue(pc);
|
m_ScriptSystem->HookCPUGPRValue()->InvokeByAddressInRange_GPRValue(pc);
|
||||||
if (SkipOp()) { return; }
|
if (SkipOp()) { return; }
|
||||||
|
|
||||||
// Memory events, pi cart -> ram dma
|
if (bStoreOp)
|
||||||
if (opInfo.IsLoadStoreCommand()) // Read and write instructions
|
|
||||||
{
|
{
|
||||||
uint32_t memoryAddress = opInfo.GetLoadStoreAddress();
|
m_ScriptSystem->HookCPUWrite()->InvokeByAddressInRange(storeAddress);
|
||||||
|
|
||||||
if (opInfo.IsLoadCommand()) // Read instructions
|
|
||||||
{
|
|
||||||
m_ScriptSystem->HookCPURead()->InvokeByAddressInRange(memoryAddress);
|
|
||||||
if (SkipOp()) { return; }
|
if (SkipOp()) { return; }
|
||||||
}
|
}
|
||||||
else // Write instructions
|
|
||||||
{
|
|
||||||
m_ScriptSystem->HookCPUWrite()->InvokeByAddressInRange(memoryAddress);
|
|
||||||
if (SkipOp()) { return; }
|
|
||||||
|
|
||||||
if (memoryAddress == 0xA460000C) // PI_WR_LEN_REG
|
if (opInfo.IsLoadCommand())
|
||||||
|
{
|
||||||
|
m_ScriptSystem->HookCPURead()->InvokeByAddressInRange(opInfo.GetLoadStoreAddress());
|
||||||
|
if (SkipOp()) { return; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bStoreOp && storeAddress == 0xA460000C) // PI_WR_LEN_REG
|
||||||
{
|
{
|
||||||
HandleCartToRamDMA();
|
HandleCartToRamDMA();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CDebugSettings::ExceptionBreakpoints() != 0)
|
if (CDebugSettings::ExceptionBreakpoints() != 0)
|
||||||
{
|
{
|
||||||
|
@ -603,6 +601,8 @@ void CDebuggerUI::CPUStepStarted()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_Breakpoints->HaveRegBP())
|
||||||
|
{
|
||||||
if (m_Breakpoints->HaveAnyGPRWriteBP())
|
if (m_Breakpoints->HaveAnyGPRWriteBP())
|
||||||
{
|
{
|
||||||
int nReg = 0;
|
int nReg = 0;
|
||||||
|
@ -633,6 +633,7 @@ void CDebuggerUI::CPUStepStarted()
|
||||||
{
|
{
|
||||||
g_Settings->SaveBool(Debugger_SteppingOps, true);
|
g_Settings->SaveBool(Debugger_SteppingOps, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called before opcode is executed (not called if SkipOp is set)
|
// Called before opcode is executed (not called if SkipOp is set)
|
||||||
|
@ -647,15 +648,15 @@ void CDebuggerUI::CPUStep()
|
||||||
// Called after opcode has been executed
|
// Called after opcode has been executed
|
||||||
void CDebuggerUI::CPUStepEnded()
|
void CDebuggerUI::CPUStepEnded()
|
||||||
{
|
{
|
||||||
|
if (m_StackTrace == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
OPCODE Opcode = R4300iOp::m_Opcode;
|
OPCODE Opcode = R4300iOp::m_Opcode;
|
||||||
uint32_t op = Opcode.op;
|
uint32_t op = Opcode.op;
|
||||||
uint32_t funct = Opcode.funct;
|
uint32_t funct = Opcode.funct;
|
||||||
|
|
||||||
if (m_StackTrace == NULL)
|
|
||||||
{
|
|
||||||
m_StackTrace = new CDebugStackTrace(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op == R4300i_JAL || ((op == R4300i_SPECIAL) && (funct == R4300i_SPECIAL_JALR) && (Opcode.rd == 31))) // JAL or JALR RA, x
|
if (op == R4300i_JAL || ((op == R4300i_SPECIAL) && (funct == R4300i_SPECIAL_JALR) && (Opcode.rd == 31))) // JAL or JALR RA, x
|
||||||
{
|
{
|
||||||
m_StackTrace->PushEntry(R4300iOp::m_JumpToLocation, g_Reg->m_PROGRAM_COUNTER);
|
m_StackTrace->PushEntry(R4300iOp::m_JumpToLocation, g_Reg->m_PROGRAM_COUNTER);
|
||||||
|
|
|
@ -17,6 +17,7 @@ int CScriptHook::Add(CScriptInstance* scriptInstance, void* heapptr, uint32_t pa
|
||||||
jsCallback.param4 = param4;
|
jsCallback.param4 = param4;
|
||||||
jsCallback.bOnce = bOnce;
|
jsCallback.bOnce = bOnce;
|
||||||
m_Callbacks.push_back(jsCallback);
|
m_Callbacks.push_back(jsCallback);
|
||||||
|
m_ScriptSystem->CallbackAdded();
|
||||||
return jsCallback.callbackId;
|
return jsCallback.callbackId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +123,7 @@ void CScriptHook::RemoveById(int callbackId)
|
||||||
if (m_Callbacks[i].callbackId == callbackId)
|
if (m_Callbacks[i].callbackId == callbackId)
|
||||||
{
|
{
|
||||||
m_Callbacks.erase(m_Callbacks.begin() + i);
|
m_Callbacks.erase(m_Callbacks.begin() + i);
|
||||||
|
m_ScriptSystem->CallbackRemoved();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,6 +137,7 @@ void CScriptHook::RemoveByParam(uint32_t param)
|
||||||
if (m_Callbacks[i].param == param)
|
if (m_Callbacks[i].param == param)
|
||||||
{
|
{
|
||||||
m_Callbacks.erase(m_Callbacks.begin() + i);
|
m_Callbacks.erase(m_Callbacks.begin() + i);
|
||||||
|
m_ScriptSystem->CallbackRemoved();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,6 +151,7 @@ void CScriptHook::RemoveByInstance(CScriptInstance* scriptInstance)
|
||||||
if (m_Callbacks[i].scriptInstance == scriptInstance)
|
if (m_Callbacks[i].scriptInstance == scriptInstance)
|
||||||
{
|
{
|
||||||
m_Callbacks.erase(m_Callbacks.begin() + i);
|
m_Callbacks.erase(m_Callbacks.begin() + i);
|
||||||
|
m_ScriptSystem->CallbackRemoved();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ CScriptSystem::CScriptSystem(CDebuggerUI* debugger)
|
||||||
WSAStartup(MAKEWORD(2, 2), &wsaData);
|
WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||||
|
|
||||||
m_NextCallbackId = 0;
|
m_NextCallbackId = 0;
|
||||||
|
m_NumCallbacks = 0;
|
||||||
|
|
||||||
m_Debugger = debugger;
|
m_Debugger = debugger;
|
||||||
|
|
||||||
|
@ -208,3 +209,16 @@ int CScriptSystem::GetNextCallbackId()
|
||||||
{
|
{
|
||||||
return m_NextCallbackId++;
|
return m_NextCallbackId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CScriptSystem::CallbackAdded()
|
||||||
|
{
|
||||||
|
m_NumCallbacks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScriptSystem::CallbackRemoved()
|
||||||
|
{
|
||||||
|
if (m_NumCallbacks > 0)
|
||||||
|
{
|
||||||
|
m_NumCallbacks--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ private:
|
||||||
} INSTANCE_ENTRY;
|
} INSTANCE_ENTRY;
|
||||||
|
|
||||||
CDebuggerUI* m_Debugger;
|
CDebuggerUI* m_Debugger;
|
||||||
|
int m_NumCallbacks;
|
||||||
char* m_APIScript;
|
char* m_APIScript;
|
||||||
|
|
||||||
vector<HOOKENTRY> m_Hooks;
|
vector<HOOKENTRY> m_Hooks;
|
||||||
|
@ -103,6 +103,13 @@ public:
|
||||||
CScriptHook* GetHook(const char* hookId);
|
CScriptHook* GetHook(const char* hookId);
|
||||||
|
|
||||||
int GetNextCallbackId();
|
int GetNextCallbackId();
|
||||||
|
void CallbackAdded();
|
||||||
|
void CallbackRemoved();
|
||||||
|
|
||||||
|
inline int HaveCallbacks()
|
||||||
|
{
|
||||||
|
return m_NumCallbacks != 0;
|
||||||
|
}
|
||||||
|
|
||||||
void DeleteStoppedInstances();
|
void DeleteStoppedInstances();
|
||||||
INSTANCE_STATE GetInstanceState(char* scriptName);
|
INSTANCE_STATE GetInstanceState(char* scriptName);
|
||||||
|
|
Loading…
Reference in New Issue