aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/jsruntime/qv4debugging.cpp49
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h15
-rw-r--r--src/qml/jsruntime/qv4function.cpp25
-rw-r--r--src/qml/jsruntime/qv4function_p.h2
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;
};
}