Debugger: Performance fixes for conditional breakpoints
This commit is contained in:
parent
51afb5ae3f
commit
4f6776f30b
7 changed files with 85 additions and 55 deletions
|
@ -911,7 +911,7 @@ CartridgeState BaseMapper::GetState()
|
|||
state.PrgPageSize = InternalGetPrgPageSize();
|
||||
state.ChrPageCount = GetCHRPageCount();
|
||||
state.ChrPageSize = InternalGetChrPageSize();
|
||||
for(int i = 0; i < 64; i++) {
|
||||
for(int i = 0, max = 0x8000 / state.PrgPageSize; i < max; i++) {
|
||||
if(_prgPageNumbers[i] != 0xEEEEEEEE) {
|
||||
int16_t pageNumber = (int16_t)_prgPageNumbers[i];
|
||||
state.PrgSelectedPages[i] = pageNumber < 0 ? state.PrgPageCount + pageNumber : pageNumber;
|
||||
|
@ -920,7 +920,7 @@ CartridgeState BaseMapper::GetState()
|
|||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < 64; i++) {
|
||||
for(int i = 0, max = 0x2000 / state.ChrPageSize; i < max; i++) {
|
||||
if(_chrPageNumbers[i] != 0xEEEEEEEE) {
|
||||
int16_t pageNumber = (int16_t)_chrPageNumbers[i];
|
||||
state.ChrSelectedPages[i] = pageNumber < 0 ? state.ChrPageCount + pageNumber : pageNumber;
|
||||
|
|
|
@ -46,6 +46,11 @@ string Breakpoint::GetCondition()
|
|||
return _condition;
|
||||
}
|
||||
|
||||
bool Breakpoint::HasCondition()
|
||||
{
|
||||
return _condition[0] != 0;
|
||||
}
|
||||
|
||||
void Breakpoint::ClearCondition()
|
||||
{
|
||||
memset(_condition, 0, sizeof(_condition));
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
bool Matches(uint32_t memoryAddr, uint32_t absoluteAddr);
|
||||
bool HasBreakpointType(BreakpointType type);
|
||||
string GetCondition();
|
||||
bool HasCondition();
|
||||
void ClearCondition();
|
||||
|
||||
private:
|
||||
|
|
|
@ -200,6 +200,7 @@ void Debugger::UpdateBreakpoints()
|
|||
|
||||
for(int i = 0; i < Debugger::BreakpointTypeCount; i++) {
|
||||
_breakpoints[i].clear();
|
||||
_breakpointRpnList[i].clear();
|
||||
_hasBreakpoint[i] = false;
|
||||
}
|
||||
|
||||
|
@ -208,6 +209,7 @@ void Debugger::UpdateBreakpoints()
|
|||
for(int i = 0; i < Debugger::BreakpointTypeCount; i++) {
|
||||
if(bp.HasBreakpointType((BreakpointType)i)) {
|
||||
_breakpoints[i].push_back(bp);
|
||||
_breakpointRpnList[i].push_back(expEval.GetRpnList(bp.GetCondition()));
|
||||
_hasBreakpoint[i] = true;
|
||||
}
|
||||
}
|
||||
|
@ -225,21 +227,26 @@ bool Debugger::HasMatchingBreakpoint(BreakpointType type, uint32_t addr, int16_t
|
|||
vector<Breakpoint> &breakpoints = _breakpoints[(int)type];
|
||||
|
||||
bool needState = true;
|
||||
EvalResultType resultType;
|
||||
for(size_t i = 0, len = breakpoints.size(); i < len; i++) {
|
||||
Breakpoint &breakpoint = breakpoints[i];
|
||||
if(type == BreakpointType::Global || breakpoint.Matches(addr, absoluteAddr)) {
|
||||
string condition = breakpoint.GetCondition();
|
||||
if(condition.empty()) {
|
||||
if(!breakpoint.HasCondition()) {
|
||||
return true;
|
||||
} else {
|
||||
ExpressionEvaluator expEval(this);
|
||||
if(needState) {
|
||||
GetState(&_debugState);
|
||||
GetState(&_debugState, false);
|
||||
needState = false;
|
||||
}
|
||||
if(expEval.Evaluate(condition, _debugState, value, addr) != 0) {
|
||||
if(_breakpointRpnList[(int)type][i]) {
|
||||
if(_bpExpEval.Evaluate(_breakpointRpnList[(int)type][i], _debugState, resultType, value, addr) != 0) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if(_bpExpEval.Evaluate(breakpoint.GetCondition(), _debugState, resultType, value, addr) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -249,12 +256,9 @@ bool Debugger::HasMatchingBreakpoint(BreakpointType type, uint32_t addr, int16_t
|
|||
|
||||
int32_t Debugger::EvaluateExpression(string expression, EvalResultType &resultType)
|
||||
{
|
||||
ExpressionEvaluator expEval(this);
|
||||
|
||||
DebugState state;
|
||||
GetState(&state);
|
||||
|
||||
return expEval.Evaluate(expression, state, resultType);
|
||||
return _watchExpEval.Evaluate(expression, state, resultType);
|
||||
}
|
||||
|
||||
void Debugger::UpdateCallstack(uint32_t addr)
|
||||
|
@ -461,11 +465,13 @@ void Debugger::PrivateProcessVramOperation(MemoryOperationType type, uint16_t ad
|
|||
}
|
||||
}
|
||||
|
||||
void Debugger::GetState(DebugState *state)
|
||||
void Debugger::GetState(DebugState *state, bool includeMapperInfo)
|
||||
{
|
||||
state->CPU = _cpu->GetState();
|
||||
state->PPU = _ppu->GetState();
|
||||
if(includeMapperInfo) {
|
||||
state->Cartridge = _mapper->GetState();
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::SetState(DebugState state)
|
||||
|
|
|
@ -54,6 +54,7 @@ private:
|
|||
atomic<int32_t> _suspendCount;
|
||||
vector<Breakpoint> _newBreakpoints;
|
||||
vector<Breakpoint> _breakpoints[BreakpointTypeCount];
|
||||
vector<vector<int>*> _breakpointRpnList[BreakpointTypeCount];
|
||||
bool _hasBreakpoint[BreakpointTypeCount] = {};
|
||||
|
||||
vector<uint8_t> _frozenAddresses;
|
||||
|
@ -63,6 +64,8 @@ private:
|
|||
|
||||
unordered_set<uint32_t> _functionEntryPoints;
|
||||
|
||||
ExpressionEvaluator _watchExpEval = ExpressionEvaluator(this);
|
||||
ExpressionEvaluator _bpExpEval = ExpressionEvaluator(this);
|
||||
DebugState _debugState;
|
||||
|
||||
SimpleLock _breakLock;
|
||||
|
@ -117,7 +120,7 @@ public:
|
|||
void GetFunctionEntryPoints(int32_t* entryPoints);
|
||||
void GetCallstack(int32_t* callstackAbsolute, int32_t* callstackRelative);
|
||||
|
||||
void GetState(DebugState *state);
|
||||
void GetState(DebugState *state, bool includeMapperInfo = true);
|
||||
void SetState(DebugState state);
|
||||
|
||||
void Suspend();
|
||||
|
|
|
@ -10,6 +10,11 @@
|
|||
std::unordered_map<string, std::vector<int>, StringHasher> ExpressionEvaluator::_outputCache;
|
||||
SimpleLock ExpressionEvaluator::_cacheLock;
|
||||
|
||||
const vector<string> ExpressionEvaluator::_binaryOperators = { { "*", "/", "%", "+", "-", "<<", ">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||" } };
|
||||
const vector<int> ExpressionEvaluator::_binaryPrecedence = { { 10, 10, 10, 9, 9, 8, 8, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1 } };
|
||||
const vector<string> ExpressionEvaluator::_unaryOperators = { { "+", "-", "!", "~" } };
|
||||
const vector<int> ExpressionEvaluator::_unaryPrecedence = { { 11, 11, 11, 11 } };
|
||||
|
||||
bool ExpressionEvaluator::IsOperator(string token, int &precedence, bool unaryOperator)
|
||||
{
|
||||
if(unaryOperator) {
|
||||
|
@ -256,10 +261,14 @@ bool ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
|
|||
if(!ProcessSpecialOperator(EvalOperators::Braces, opStack, outputQueue)){
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if(token[0] < '0' || token[0] > '9') {
|
||||
return false;
|
||||
} else {
|
||||
outputQueue.push_back(std::stoi(token));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(braceCount || bracketCount || parenthesisCount) {
|
||||
//Mismatching number of brackets/braces/parenthesis
|
||||
|
@ -274,16 +283,15 @@ bool ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
|
|||
return true;
|
||||
}
|
||||
|
||||
int32_t ExpressionEvaluator::EvaluateExpression(vector<int> *outputQueue, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr)
|
||||
int32_t ExpressionEvaluator::Evaluate(vector<int> *rpnList, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr)
|
||||
{
|
||||
int pos = 0;
|
||||
int right = 0;
|
||||
int left = 0;
|
||||
int operandStack[1000];
|
||||
resultType = EvalResultType::Numeric;
|
||||
|
||||
for(size_t i = 0, len = outputQueue->size(); i < len; i++) {
|
||||
int token = (*outputQueue)[i];
|
||||
for(size_t i = 0, len = rpnList->size(); i < len; i++) {
|
||||
int token = (*rpnList)[i];
|
||||
|
||||
if(token >= EvalValues::RegA) {
|
||||
//Replace value with a special value
|
||||
|
@ -291,12 +299,12 @@ int32_t ExpressionEvaluator::EvaluateExpression(vector<int> *outputQueue, DebugS
|
|||
case EvalValues::RegA: token = state.CPU.A; break;
|
||||
case EvalValues::RegX: token = state.CPU.X; break;
|
||||
case EvalValues::RegY: token = state.CPU.Y; break;
|
||||
case EvalValues::RegPS: token = state.CPU.PS; break;
|
||||
case EvalValues::RegSP: token = state.CPU.SP; break;
|
||||
case EvalValues::Irq: token = state.CPU.IRQFlag; break;
|
||||
case EvalValues::Nmi: token = state.CPU.NMIFlag; break;
|
||||
case EvalValues::RegPS: token = state.CPU.PS; break;
|
||||
case EvalValues::PpuCycle: token = state.PPU.Cycle; break;
|
||||
case EvalValues::PpuScanline: token = state.PPU.Scanline; break;
|
||||
case EvalValues::Nmi: token = state.CPU.NMIFlag; break;
|
||||
case EvalValues::Irq: token = state.CPU.IRQFlag; break;
|
||||
case EvalValues::Value: token = memoryValue; break;
|
||||
case EvalValues::Address: token = memoryAddr; break;
|
||||
case EvalValues::AbsoluteAddress: token = _debugger->GetAbsoluteAddress(memoryAddr); break;
|
||||
|
@ -330,12 +338,12 @@ int32_t ExpressionEvaluator::EvaluateExpression(vector<int> *outputQueue, DebugS
|
|||
case EvalOperators::LogicalOr: token = left || right; resultType = EvalResultType::Boolean; break;
|
||||
|
||||
//Unary operators
|
||||
case EvalOperators::Bracket: token = _debugger->GetMemoryValue(right); break;
|
||||
case EvalOperators::Braces: token = _debugger->GetMemoryValue(right) | (_debugger->GetMemoryValue(right+1) << 8); break;
|
||||
case EvalOperators::Plus: token = right; break;
|
||||
case EvalOperators::Minus: token = -right; break;
|
||||
case EvalOperators::BinaryNot: token = ~right; break;
|
||||
case EvalOperators::LogicalNot: token = !right; break;
|
||||
case EvalOperators::Bracket: token = _debugger->GetMemoryValue(right); break;
|
||||
case EvalOperators::Braces: token = _debugger->GetMemoryValue(right) | (_debugger->GetMemoryValue(right+1) << 8); break;
|
||||
default: throw std::runtime_error("Invalid operator");
|
||||
}
|
||||
}
|
||||
|
@ -349,12 +357,16 @@ ExpressionEvaluator::ExpressionEvaluator(Debugger* debugger)
|
|||
_debugger = debugger;
|
||||
}
|
||||
|
||||
int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr, bool& success)
|
||||
vector<int>* ExpressionEvaluator::GetRpnList(string expression)
|
||||
{
|
||||
success = true;
|
||||
vector<int> output;
|
||||
vector<int> *outputQueue = nullptr;
|
||||
bool success;
|
||||
return GetRpnList(expression, output, success);
|
||||
}
|
||||
|
||||
vector<int>* ExpressionEvaluator::GetRpnList(string expression, vector<int> &output, bool& success)
|
||||
{
|
||||
vector<int> *outputQueue = nullptr;
|
||||
{
|
||||
LockHandler lock = _cacheLock.AcquireSafe();
|
||||
|
||||
|
@ -364,35 +376,36 @@ int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &stat
|
|||
}
|
||||
}
|
||||
|
||||
if(outputQueue == nullptr && output.empty()) {
|
||||
if(outputQueue == nullptr) {
|
||||
string fixedExp = expression;
|
||||
fixedExp.erase(std::remove(fixedExp.begin(), fixedExp.end(), ' '), fixedExp.end());
|
||||
success = ToRpn(fixedExp, output);
|
||||
|
||||
if(success) {
|
||||
if(_containsCustomLabels) {
|
||||
outputQueue = &output;
|
||||
} else {
|
||||
if(success && !_containsCustomLabels) {
|
||||
LockHandler lock = _cacheLock.AcquireSafe();
|
||||
_outputCache[expression] = output;
|
||||
outputQueue = &_outputCache[expression];
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(outputQueue) {
|
||||
return EvaluateExpression(outputQueue, state, resultType, memoryValue, memoryAddr);
|
||||
} else {
|
||||
return EvaluateExpression(&output, state, resultType, memoryValue, memoryAddr);
|
||||
}
|
||||
return outputQueue;
|
||||
}
|
||||
|
||||
int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, int16_t memoryValue, uint32_t memoryAddr)
|
||||
int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr, bool& success)
|
||||
{
|
||||
EvalResultType resultType;
|
||||
return Evaluate(expression, state, resultType, memoryValue, memoryAddr);
|
||||
success = true;
|
||||
vector<int> output;
|
||||
vector<int> *rpnList = GetRpnList(expression, output, success);
|
||||
|
||||
if(!success) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!rpnList) {
|
||||
rpnList = &output;
|
||||
}
|
||||
|
||||
return Evaluate(rpnList, state, resultType, memoryValue, memoryAddr);
|
||||
}
|
||||
|
||||
int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr)
|
||||
|
@ -407,7 +420,6 @@ int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, Eval
|
|||
}
|
||||
resultType = EvalResultType::Invalid;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
bool ExpressionEvaluator::Validate(string expression)
|
||||
|
|
|
@ -80,14 +80,15 @@ public:
|
|||
class ExpressionEvaluator
|
||||
{
|
||||
private:
|
||||
const vector<string> _binaryOperators = { { "*", "/", "%", "+", "-", "<<", ">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||" } };
|
||||
const vector<int> _binaryPrecedence = { { 10, 10, 10, 9, 9, 8, 8, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1 } };
|
||||
const vector<string> _unaryOperators = { { "+", "-", "!", "~" } };
|
||||
const vector<int> _unaryPrecedence = { { 11, 11, 11, 11 } };
|
||||
static const vector<string> _binaryOperators;
|
||||
static const vector<int> _binaryPrecedence;
|
||||
static const vector<string> _unaryOperators;
|
||||
static const vector<int> _unaryPrecedence;
|
||||
|
||||
static std::unordered_map<string, std::vector<int>, StringHasher> _outputCache;
|
||||
static SimpleLock _cacheLock;
|
||||
|
||||
int operandStack[1000];
|
||||
Debugger* _debugger;
|
||||
bool _containsCustomLabels = false;
|
||||
|
||||
|
@ -97,13 +98,15 @@ private:
|
|||
string GetNextToken(string expression, size_t &pos);
|
||||
bool ProcessSpecialOperator(EvalOperators evalOp, std::stack<EvalOperators> &opStack, vector<int> &outputQueue);
|
||||
bool ToRpn(string expression, vector<int> &outputQueue);
|
||||
int32_t EvaluateExpression(vector<int> *outputQueue, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr);
|
||||
int32_t PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr, bool &success);
|
||||
vector<int>* GetRpnList(string expression, vector<int> &output, bool& success);
|
||||
|
||||
public:
|
||||
ExpressionEvaluator(Debugger* debugger);
|
||||
|
||||
int32_t Evaluate(string expression, DebugState &state, int16_t memoryValue = 0, uint32_t memoryAddr = 0);
|
||||
int32_t Evaluate(vector<int> *outputQueue, DebugState &state, EvalResultType &resultType, int16_t memoryValue = 0, uint32_t memoryAddr = 0);
|
||||
int32_t Evaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue = 0, uint32_t memoryAddr = 0);
|
||||
vector<int>* GetRpnList(string expression);
|
||||
|
||||
bool Validate(string expression);
|
||||
};
|
Loading…
Add table
Reference in a new issue