diff options
author | Erik Verbruggen <erik.verbruggen@qt.io> | 2019-01-14 14:21:21 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2019-01-15 17:35:46 +0000 |
commit | 8fd3cfe7d0f39a731c585334299f5160ad952df9 (patch) | |
tree | ff57f39464d88c610103f6fd4aa1b4e1ec53be01 | |
parent | 8396dc86f28e89a920d85f59518fac79da8480eb (diff) |
Annotate stack traces when frames are elided through tail calls
Task-number: QTBUG-72407
Change-Id: I98b96852309fc783a945797185f666196513d24b
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4stackframe_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qml/qjsengine/tst_qjsengine.cpp | 16 |
4 files changed, 24 insertions, 0 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 57a364b205..f00578aa70 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1011,6 +1011,11 @@ StackTrace ExecutionEngine::stackTrace(int frameLimit) const frame.line = qAbs(f->lineNumber()); frame.column = -1; stack.append(frame); + if (f->isTailCalling) { + QV4::StackFrame frame; + frame.function = QStringLiteral("[elided tail calls]"); + stack.append(frame); + } --frameLimit; f = f->parent; } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index dfe9d35194..41a21ba379 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -518,6 +518,7 @@ ReturnedValue ArrowFunction::virtualCall(const FunctionObject *fo, const Value * do { frame.pendingTailCall = false; result = Moth::VME::exec(&frame, engine); + frame.isTailCalling = true; } while (frame.pendingTailCall); frame.pop(); diff --git a/src/qml/jsruntime/qv4stackframe_p.h b/src/qml/jsruntime/qv4stackframe_p.h index a97ae0e7c9..44cfef9173 100644 --- a/src/qml/jsruntime/qv4stackframe_p.h +++ b/src/qml/jsruntime/qv4stackframe_p.h @@ -125,6 +125,7 @@ struct Q_QML_EXPORT CppStackFrame { bool yieldIsIterator; bool callerCanHandleTailCall; bool pendingTailCall; + bool isTailCalling; void init(EngineBase *engine, Function *v4Function, const Value *argv, int argc, bool callerCanHandleTailCall = false) { this->engine = engine; @@ -140,6 +141,7 @@ struct Q_QML_EXPORT CppStackFrame { yieldIsIterator = false; this->callerCanHandleTailCall = callerCanHandleTailCall; pendingTailCall = false; + isTailCalling = false; } void push() { diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 00c631141b..cf7b9c7224 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -1759,6 +1759,22 @@ void tst_QJSEngine::stacktrace() QJSValue result2 = eng.evaluate(script2, fileName); QVERIFY(!result2.isError()); QVERIFY(result2.isString()); + + { + QString script3 = QString::fromLatin1( + "'use strict'\n" + "function throwUp() { throw new Error('up') }\n" + "function indirectlyThrow() { return throwUp() }\n" + "indirectlyThrow()\n" + ); + QJSValue result3 = eng.evaluate(script3); + QVERIFY(result3.isError()); + QJSValue stack = result3.property("stack"); + QVERIFY(stack.isString()); + QString stackTrace = stack.toString(); + QVERIFY(!stackTrace.contains(QStringLiteral("indirectlyThrow"))); + QVERIFY(stackTrace.contains(QStringLiteral("elide"))); + } } void tst_QJSEngine::numberParsing_data() |