QML Debugging: Fix crash when stepping through try-catch block.
Also fix the stack-trace generation, otherwise the debugger engine would report a breakpoint hit on the wrong line. Task-number: QTBUG-42723 Change-Id: I1f655a5174b28a1c9c31c85bbe023fbce5ddbb96 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
This commit is contained in:
parent
4524856ae2
commit
8397f640e8
|
@ -54,7 +54,6 @@ struct CompilationUnit;
|
|||
struct Function;
|
||||
}
|
||||
|
||||
struct CallContext;
|
||||
struct CallContext;
|
||||
struct CatchContext;
|
||||
struct WithContext;
|
||||
|
@ -149,6 +148,9 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
|
|||
|
||||
inline CallContext *asCallContext();
|
||||
inline const CallContext *asCallContext() const;
|
||||
inline const CatchContext *asCatchContext() const;
|
||||
|
||||
inline FunctionObject *getFunctionObject() const;
|
||||
|
||||
static void markObjects(Managed *m, ExecutionEngine *e);
|
||||
};
|
||||
|
@ -225,6 +227,24 @@ inline const CallContext *ExecutionContext::asCallContext() const
|
|||
return d()->type >= Type_SimpleCallContext ? static_cast<const CallContext *>(this) : 0;
|
||||
}
|
||||
|
||||
inline const CatchContext *ExecutionContext::asCatchContext() const
|
||||
{
|
||||
return d()->type == Type_CatchContext ? static_cast<const CatchContext *>(this) : 0;
|
||||
}
|
||||
|
||||
inline FunctionObject *ExecutionContext::getFunctionObject() const
|
||||
{
|
||||
for (const ExecutionContext *it = this; it; it = it->d()->parent) {
|
||||
if (const CallContext *callCtx = it->asCallContext())
|
||||
return callCtx->d()->function;
|
||||
else if (it->asCatchContext())
|
||||
continue; // look in the parent context for a FunctionObject
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void ExecutionEngine::pushContext(CallContext *context)
|
||||
{
|
||||
|
|
|
@ -509,7 +509,6 @@ void Debugger::maybeBreakAtInstruction()
|
|||
return;
|
||||
|
||||
QMutexLocker locker(&m_lock);
|
||||
int lineNumber = engine()->currentContext()->d()->lineNumber;
|
||||
|
||||
if (m_gatherSources) {
|
||||
m_gatherSources->run();
|
||||
|
@ -533,8 +532,12 @@ void Debugger::maybeBreakAtInstruction()
|
|||
if (m_pauseRequested) { // Serve debugging requests from the agent
|
||||
m_pauseRequested = false;
|
||||
pauseAndWait(PauseRequest);
|
||||
} else if (m_haveBreakPoints && reallyHitTheBreakPoint(getFunction()->sourceFile(), lineNumber)) {
|
||||
pauseAndWait(BreakPoint);
|
||||
} else if (m_haveBreakPoints) {
|
||||
if (Function *f = getFunction()) {
|
||||
const int lineNumber = engine()->currentContext()->d()->lineNumber;
|
||||
if (reallyHitTheBreakPoint(f->sourceFile(), lineNumber))
|
||||
pauseAndWait(BreakPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -579,12 +582,10 @@ void Debugger::aboutToThrow()
|
|||
Function *Debugger::getFunction() const
|
||||
{
|
||||
ExecutionContext *context = m_engine->currentContext();
|
||||
if (CallContext *callCtx = context->asCallContext())
|
||||
return callCtx->d()->function->function();
|
||||
else {
|
||||
Q_ASSERT(context->d()->type == QV4::ExecutionContext::Type_GlobalContext);
|
||||
if (const FunctionObject *function = context->getFunctionObject())
|
||||
return function->function();
|
||||
else
|
||||
return context->d()->engine->globalCode;
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::pauseAndWait(PauseReason reason)
|
||||
|
|
|
@ -700,19 +700,18 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const
|
|||
|
||||
QV4::ExecutionContext *c = currentContext();
|
||||
while (c && frameLimit) {
|
||||
CallContext *callCtx = c->asCallContext();
|
||||
if (callCtx && callCtx->d()->function) {
|
||||
if (FunctionObject *function = c->getFunctionObject()) {
|
||||
StackFrame frame;
|
||||
if (callCtx->d()->function->function())
|
||||
frame.source = callCtx->d()->function->function()->sourceFile();
|
||||
name = callCtx->d()->function->name();
|
||||
if (const Function *f = function->function())
|
||||
frame.source = f->sourceFile();
|
||||
name = function->name();
|
||||
frame.function = name->toQString();
|
||||
frame.line = -1;
|
||||
frame.column = -1;
|
||||
|
||||
if (callCtx->d()->function->function())
|
||||
if (function->function())
|
||||
// line numbers can be negative for places where you can't set a real breakpoint
|
||||
frame.line = qAbs(callCtx->d()->lineNumber);
|
||||
frame.line = qAbs(c->d()->lineNumber);
|
||||
|
||||
stack.append(frame);
|
||||
--frameLimit;
|
||||
|
@ -727,7 +726,6 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const
|
|||
frame.line = rootContext->d()->lineNumber;
|
||||
frame.column = -1;
|
||||
|
||||
|
||||
stack.append(frame);
|
||||
}
|
||||
return stack;
|
||||
|
|
|
@ -116,7 +116,7 @@ struct Q_QML_EXPORT FunctionObject: Object {
|
|||
|
||||
|
||||
ExecutionContext *scope() { return d()->scope; }
|
||||
Function *function() { return d()->function; }
|
||||
Function *function() const { return d()->function; }
|
||||
|
||||
ReturnedValue name();
|
||||
unsigned int formalParameterCount() { return function() ? function()->compiledFunction->nFormals : 0; }
|
||||
|
|
|
@ -286,6 +286,7 @@ private slots:
|
|||
|
||||
// exceptions:
|
||||
void pauseOnThrow();
|
||||
void breakInCatch();
|
||||
|
||||
void evaluateExpression();
|
||||
|
||||
|
@ -612,6 +613,25 @@ void tst_qv4debugger::pauseOnThrow()
|
|||
QCOMPARE(m_debuggerAgent->m_thrownValue.toString(), QString("hard"));
|
||||
}
|
||||
|
||||
void tst_qv4debugger::breakInCatch()
|
||||
{
|
||||
QString script =
|
||||
"try {\n"
|
||||
" throw 'catch...'\n"
|
||||
"} catch (e) {\n"
|
||||
" console.log(e, 'me');\n"
|
||||
"}\n";
|
||||
|
||||
m_debuggerAgent->addBreakPoint("breakInCatch", 4);
|
||||
evaluateJavaScript(script, "breakInCatch");
|
||||
QVERIFY(m_debuggerAgent->m_wasPaused);
|
||||
QCOMPARE(m_debuggerAgent->m_pauseReason, BreakPoint);
|
||||
QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 1);
|
||||
QV4::Debugging::Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.first();
|
||||
QCOMPARE(state.fileName, QString("breakInCatch"));
|
||||
QCOMPARE(state.lineNumber, 4);
|
||||
}
|
||||
|
||||
void tst_qv4debugger::evaluateExpression()
|
||||
{
|
||||
QString script =
|
||||
|
|
Loading…
Reference in New Issue