diff options
author | Kent Hansen <[email protected]> | 2012-08-15 11:46:23 +0200 |
---|---|---|
committer | Qt by Nokia <[email protected]> | 2012-08-15 13:34:35 +0200 |
commit | df0ec196031d33850324dc5eeed2d71f61413885 (patch) | |
tree | 9e98812061839c550f2d3b4e86f57a47e6bf2b37 /src/script/api/qscriptengine.cpp | |
parent | 8854338fe988a38514e69fe52a831a1ac3c6f936 (diff) |
Make QScriptEngine::uncaughtExceptionBacktrace() work again
This function has been broken since Qt 4.6 (when the JavaScriptCore-
based back-end was introduced). Fix it by introducing a callback in
JSC that allows us to capture the stack when an uncaught exception
occurs.
Task-number: QTBUG-6139
Change-Id: I4a829323c9fb0c8b2f16a2e5d6f0aeb13cc32561
Reviewed-by: Olivier Goffart <[email protected]>
Diffstat (limited to 'src/script/api/qscriptengine.cpp')
-rw-r--r-- | src/script/api/qscriptengine.cpp | 66 |
1 files changed, 52 insertions, 14 deletions
diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index 5dc4e2d..9965b3a 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -491,6 +491,12 @@ void GlobalClientData::mark(JSC::MarkStack& markStack) engine->mark(markStack); } +void GlobalClientData::uncaughtException(JSC::ExecState* exec, unsigned bytecodeOffset, + JSC::JSValue value) +{ + engine->uncaughtException(exec, bytecodeOffset, value); +} + class TimeoutCheckerProxy : public JSC::TimeoutChecker { public: @@ -964,7 +970,8 @@ QScriptEnginePrivate::QScriptEnginePrivate() qobjectPrototype(0), qmetaobjectPrototype(0), variantPrototype(0), activeAgent(0), agentLineNumber(-1), registeredScriptValues(0), freeScriptValues(0), freeScriptValuesCount(0), - registeredScriptStrings(0), processEventsInterval(-1), inEval(false) + registeredScriptStrings(0), processEventsInterval(-1), inEval(false), + uncaughtExceptionLineNumber(-1) { qMetaTypeId<QScriptValue>(); qMetaTypeId<QList<int> >(); @@ -1408,6 +1415,43 @@ JSC::JSValue QScriptEnginePrivate::evaluateHelper(JSC::ExecState *exec, intptr_t return result; } +// See ExceptionHelpers.cpp createStackOverflowError() +bool QScriptEnginePrivate::isLikelyStackOverflowError(JSC::ExecState *exec, JSC::JSValue value) +{ + if (!isError(value)) + return false; + + JSC::JSValue name = property(exec, value, exec->propertyNames().name); + if (!name || !name.isString() || name.toString(exec) != "RangeError") + return false; + + JSC::JSValue message = property(exec, value, exec->propertyNames().message); + if (!message || !message.isString() || message.toString(exec) != "Maximum call stack size exceeded.") + return false; + + return true; +} + +/*! + \internal + Called by the VM when an uncaught exception is detected. + At the time of this call, the VM stack has not yet been unwound. +*/ +void QScriptEnginePrivate::uncaughtException(JSC::ExecState *exec, unsigned bytecodeOffset, + JSC::JSValue value) +{ + QScript::SaveFrameHelper saveFrame(this, exec); + + uncaughtExceptionLineNumber = exec->codeBlock()->lineNumberForBytecodeOffset(exec, bytecodeOffset); + + if (isLikelyStackOverflowError(exec, value)) { + // Don't save the backtrace, it's likely to take forever to create. + uncaughtExceptionBacktrace.clear(); + } else { + uncaughtExceptionBacktrace = contextForFrame(exec)->backtrace(); + } +} + #ifndef QT_NO_QOBJECT void QScriptEnginePrivate::markQObjectData(JSC::MarkStack& markStack) @@ -2905,32 +2949,26 @@ QScriptValue QScriptEngine::uncaughtException() const */ int QScriptEngine::uncaughtExceptionLineNumber() const { + Q_D(const QScriptEngine); if (!hasUncaughtException()) return -1; + if (d->uncaughtExceptionLineNumber != -1) + return d->uncaughtExceptionLineNumber; + return uncaughtException().property(QLatin1String("lineNumber")).toInt32(); } /*! Returns a human-readable backtrace of the last uncaught exception. - It is in the form \c{<function-name>()@<file-name>:<line-number>}. + It is in the form \c{<function-name>() at <file-name>:<line-number>}. \sa uncaughtException() */ QStringList QScriptEngine::uncaughtExceptionBacktrace() const { - if (!hasUncaughtException()) - return QStringList(); -// ### currently no way to get a full backtrace from JSC without installing a -// debugger that reimplements exception() and store the backtrace there. - QScriptValue value = uncaughtException(); - if (!value.isError()) - return QStringList(); - QStringList result; - result.append(QString::fromLatin1("<anonymous>()@%0:%1") - .arg(value.property(QLatin1String("fileName")).toString()) - .arg(value.property(QLatin1String("lineNumber")).toInt32())); - return result; + Q_D(const QScriptEngine); + return d->uncaughtExceptionBacktrace; } /*! |