diff options
-rw-r--r-- | src/qml/jsruntime/qv4debugging.cpp | 49 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4debugging_p.h | 15 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4function.cpp | 25 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4function_p.h | 2 |
4 files changed, 54 insertions, 37 deletions
diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index 0ba37fa547..95b4100651 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -181,11 +181,11 @@ void Debugger::resume(Speed speed) if (!m_returnedValue.isUndefined()) m_returnedValue = Primitive::undefinedValue(); - clearTemporaryBreakPoint(); + clearTemporaryBreakPoints(); if (speed == StepOver) setTemporaryBreakPointOnNextLine(); if (speed == StepOut) - m_temporaryBreakPoint.function = getFunction(); + m_temporaryBreakPoints = TemporaryBreakPoint(getFunction(), m_engine->current); m_stepping = speed; m_runningCondition.wakeAll(); @@ -491,7 +491,7 @@ void Debugger::maybeBreakAtInstruction(const uchar *code, bool breakPointHit) } if (m_stopForStepping) { - clearTemporaryBreakPoint(); + clearTemporaryBreakPoints(); m_stopForStepping = false; m_pauseRequested = false; pauseAndWait(Step); @@ -499,7 +499,7 @@ void Debugger::maybeBreakAtInstruction(const uchar *code, bool breakPointHit) m_pauseRequested = false; pauseAndWait(PauseRequest); } else if (breakPointHit) { - if (m_stepping == StepOver) + if (m_stepping == StepOver && m_temporaryBreakPoints.context == m_engine->current) pauseAndWait(Step); else if (reallyHitTheBreakPoint(state.fileName, state.lineNumber)) pauseAndWait(BreakPoint); @@ -526,8 +526,9 @@ void Debugger::leavingFunction(const ReturnedValue &retVal) QMutexLocker locker(&m_lock); - if (m_stepping == StepOut && temporaryBreakPointInFunction()) { - clearTemporaryBreakPoint(); + if ((m_stepping == StepOut || m_stepping == StepOver) + && temporaryBreakPointInFunction(m_engine->current)) { + clearTemporaryBreakPoints(); m_stepping = NotStepping; m_stopForStepping = true; m_pauseRequested = true; @@ -544,7 +545,7 @@ void Debugger::aboutToThrow() return; QMutexLocker locker(&m_lock); - clearTemporaryBreakPoint(); + clearTemporaryBreakPoints(); pauseAndWait(Throwing); } @@ -589,28 +590,38 @@ void Debugger::setTemporaryBreakPointOnNextLine() if (!function) return; - qptrdiff offset = function->programCounterForLine(state.lineNumber + 1); - if (offset < 0) + QList<qptrdiff> pcs = function->programCountersForAllLines(); + if (pcs.isEmpty()) return; - if (hasBreakOnInstruction(function, offset)) - return; + m_temporaryBreakPoints = TemporaryBreakPoint(function, m_engine->current); + m_temporaryBreakPoints.codeOffsets.reserve(pcs.size()); + for (QList<qptrdiff>::const_iterator i = pcs.begin(), ei = pcs.end(); i != ei; ++i) { + // note: we do set a breakpoint on the current line, because there could be a loop where + // a step-over would be jump back to the first instruction making up the current line. + qptrdiff offset = *i; + + if (hasBreakOnInstruction(function, offset)) + continue; // do not set a temporary breakpoint if there already is a breakpoint set by the user - setBreakOnInstruction(function, offset, true); - m_temporaryBreakPoint = TemporaryBreakPoint(function, offset); + setBreakOnInstruction(function, offset, true); + m_temporaryBreakPoints.codeOffsets.append(offset); + } } -void Debugger::clearTemporaryBreakPoint() +void Debugger::clearTemporaryBreakPoints() { - if (m_temporaryBreakPoint.function && m_temporaryBreakPoint.codeOffset) { - setBreakOnInstruction(m_temporaryBreakPoint.function, m_temporaryBreakPoint.codeOffset, false); - m_temporaryBreakPoint = TemporaryBreakPoint(); + if (m_temporaryBreakPoints.function) { + foreach (quintptr offset, m_temporaryBreakPoints.codeOffsets) + setBreakOnInstruction(m_temporaryBreakPoints.function, offset, false); + m_temporaryBreakPoints = TemporaryBreakPoint(); } } -bool Debugger::temporaryBreakPointInFunction() const +bool Debugger::temporaryBreakPointInFunction(ExecutionContext *context) const { - return m_temporaryBreakPoint.function == getFunction(); + return m_temporaryBreakPoints.function == getFunction() + && m_temporaryBreakPoints.context == context; } void Debugger::applyPendingBreakPoints() diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h index b6f39d86ba..98b549995e 100644 --- a/src/qml/jsruntime/qv4debugging_p.h +++ b/src/qml/jsruntime/qv4debugging_p.h @@ -181,9 +181,9 @@ private: // requires lock to be held void setTemporaryBreakPointOnNextLine(); // requires lock to be held - void clearTemporaryBreakPoint(); + void clearTemporaryBreakPoints(); // requires lock to be held - bool temporaryBreakPointInFunction() const; + bool temporaryBreakPointInFunction(ExecutionContext *context) const; void applyPendingBreakPoints(); static void setBreakOnInstruction(Function *function, qptrdiff codeOffset, bool onoff); @@ -220,11 +220,14 @@ private: struct TemporaryBreakPoint { Function *function; - qptrdiff codeOffset; - TemporaryBreakPoint(Function *function = 0, qptrdiff codeOffset = 0) - : function(function), codeOffset(codeOffset) + QVector<qptrdiff> codeOffsets; + ExecutionContext *context; + TemporaryBreakPoint(): function(0), context(0) {} + TemporaryBreakPoint(Function *function, ExecutionContext *context) + : function(function) + , context(context) {} - } m_temporaryBreakPoint; + } m_temporaryBreakPoints; bool m_breakOnThrow; diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index b96fdb1fe5..ebe214ad72 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -147,19 +147,22 @@ int Function::lineNumberForProgramCounter(qptrdiff offset) const return helper.table[pos * 2 + 1]; } -qptrdiff Function::programCounterForLine(quint32 line) const +QList<qptrdiff> Function::programCountersForAllLines() const { - // Access the second field, the line number - LineNumberMappingHelper<1, quint32> helper; - helper.table = compiledFunction->lineNumberMapping(); - const int count = static_cast<int>(compiledFunction->nLineNumberMappingEntries); + // Only store 1 breakpoint per line... + QHash<quint32, qptrdiff> offsetsPerLine; + const quint32 *mapping = compiledFunction->lineNumberMapping(); + + // ... and make it the first instruction by walking backwards over the line mapping table + // and inserting all entries keyed on line. + for (quint32 i = compiledFunction->nLineNumberMappingEntries; i > 0; ) { + --i; // the loop is written this way, because starting at endIndex-1 and checking for i>=0 will never end: i>=0 is always true for unsigned. + quint32 offset = mapping[i * 2]; + quint32 line = mapping[i * 2 + 1]; + offsetsPerLine.insert(line, offset); + } - int pos = helper.upperBound(0, count, line); - if (pos != 0 && count > 0) - --pos; - if (pos == count) - return -1; - return helper.table[pos * 2]; + return offsetsPerLine.values(); } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 8a8f6a5d79..5d284f1b2b 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -112,7 +112,7 @@ struct Function { void mark(ExecutionEngine *e); int lineNumberForProgramCounter(qptrdiff offset) const; - qptrdiff programCounterForLine(quint32 line) const; + QList<qptrdiff> programCountersForAllLines() const; }; } |