diff options
7 files changed, 305 insertions, 329 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index b1d928db52..a3f59870a2 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -104,6 +104,28 @@ QVector<QV4::Heap::ExecutionContext::ContextType> QV4DataCollector::getScopeType return types; } +int QV4DataCollector::encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType) +{ + switch (scopeType) { + case QV4::Heap::ExecutionContext::Type_GlobalContext: + return 0; + break; + case QV4::Heap::ExecutionContext::Type_CatchContext: + return 4; + break; + case QV4::Heap::ExecutionContext::Type_WithContext: + return 2; + break; + case QV4::Heap::ExecutionContext::Type_SimpleCallContext: + case QV4::Heap::ExecutionContext::Type_CallContext: + return 1; + break; + case QV4::Heap::ExecutionContext::Type_QmlContext: + default: + return -1; + } +} + QV4DataCollector::QV4DataCollector(QV4::ExecutionEngine *engine) : m_engine(engine) { m_values.set(engine, engine->newArrayObject()); @@ -227,19 +249,35 @@ bool QV4DataCollector::isValidRef(QV4DataCollector::Ref ref) const return ref < array->getLength(); } -void QV4DataCollector::collectScope(QJsonObject *dict, QV4Debugger *debugger, int frameNr, - int scopeNr) +bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr) { QStringList names; - if (debugger->state() == QV4Debugger::Paused) { - ArgumentCollectJob argumentsJob(m_engine, this, &names, frameNr, scopeNr); - debugger->runInEngine(&argumentsJob); - LocalCollectJob localsJob(m_engine, this, &names, frameNr, scopeNr); - debugger->runInEngine(&localsJob); + QV4::Scope scope(engine()); + QV4::Scoped<QV4::CallContext> ctxt(scope, findScope(findContext(engine(), frameNr), scopeNr)); + if (!ctxt) + return false; + + QV4::ScopedValue v(scope); + int nFormals = ctxt->formalCount(); + for (unsigned i = 0, ei = nFormals; i != ei; ++i) { + QString qName; + if (QV4::Identifier *name = ctxt->formals()[nFormals - i - 1]) + qName = name->string; + names.append(qName); + v = ctxt->argument(i); + collect(v); + } + + for (unsigned i = 0, ei = ctxt->variableCount(); i != ei; ++i) { + QString qName; + if (QV4::Identifier *name = ctxt->variables()[i]) + qName = name->string; + names.append(qName); + v = ctxt->d()->locals[i]; + collect(v); } - QV4::Scope scope(engine()); QV4::ScopedObject scopeObject(scope, engine()->newObject()); Q_ASSERT(names.size() == m_collectedRefs.size()); @@ -250,6 +288,62 @@ void QV4DataCollector::collectScope(QJsonObject *dict, QV4Debugger *debugger, in Ref scopeObjectRef = addRef(scopeObject); dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef)); m_collectedRefs.append(scopeObjectRef); + return true; +} + +QJsonObject toRef(QV4DataCollector::Ref ref) { + QJsonObject dict; + dict.insert(QStringLiteral("ref"), qint64(ref)); + return dict; +} + +QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int frameNr) +{ + QV4DataCollector::Ref ref; + + QJsonObject frame; + frame[QLatin1String("index")] = frameNr; + frame[QLatin1String("debuggerFrame")] = false; + ref = addFunctionRef(stackFrame.function); + frame[QLatin1String("func")] = toRef(ref); + ref = addScriptRef(stackFrame.source); + frame[QLatin1String("script")] = toRef(ref); + frame[QLatin1String("line")] = stackFrame.line - 1; + if (stackFrame.column >= 0) + frame[QLatin1String("column")] = stackFrame.column; + + QJsonArray scopes; + QV4::Scope scope(engine()); + QV4::ScopedContext ctxt(scope, findContext(engine(), frameNr)); + while (ctxt) { + if (QV4::CallContext *cCtxt = ctxt->asCallContext()) { + if (cCtxt->d()->activation) + break; + } + ctxt = ctxt->d()->outer; + } + + if (ctxt) { + QV4::ScopedValue o(scope, ctxt->asCallContext()->d()->activation); + frame[QLatin1String("receiver")] = toRef(collect(o)); + } + + // Only type and index are used by Qt Creator, so we keep it easy: + QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = getScopeTypes(engine(), frameNr); + for (int i = 0, ei = scopeTypes.count(); i != ei; ++i) { + int type = encodeScopeType(scopeTypes[i]); + if (type == -1) + continue; + + QJsonObject scope; + scope[QLatin1String("index")] = i; + scope[QLatin1String("type")] = type; + scopes.push_back(scope); + } + + frame[QLatin1String("scopes")] = scopes; + + return frame; } QJsonArray QV4DataCollector::flushCollectedRefs() diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h index 1679c2eab7..1c3a05960c 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h @@ -60,6 +60,7 @@ public: static QV4::Heap::CallContext *findScope(QV4::ExecutionContext *ctxt, int scope); static QVector<QV4::Heap::ExecutionContext::ContextType> getScopeTypes( QV4::ExecutionEngine *engine, int frame); + static int encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType); QV4DataCollector(QV4::ExecutionEngine *engine); @@ -70,7 +71,8 @@ public: bool isValidRef(Ref ref) const; QJsonObject lookupRef(Ref ref); - void collectScope(QJsonObject *dict, QV4Debugger *debugger, int frameNr, int scopeNr); + bool collectScope(QJsonObject *dict, int frameNr, int scopeNr); + QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr); QV4::ExecutionEngine *engine() const { return m_engine; } QJsonArray flushCollectedRefs(); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp index 020be688f3..d60db6cf82 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp @@ -118,8 +118,79 @@ bool JavaScriptJob::hasExeption() const return resultIsException; } +BacktraceJob::BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame) : + CollectJob(collector), fromFrame(fromFrame), toFrame(toFrame) +{ +} + +void BacktraceJob::run() +{ + QJsonArray frameArray; + QVector<QV4::StackFrame> frames = collector->engine()->stackTrace(toFrame); + for (int i = fromFrame; i < toFrame && i < frames.size(); ++i) + frameArray.push_back(collector->buildFrame(frames[i], i)); + if (frameArray.isEmpty()) { + result.insert(QStringLiteral("totalFrames"), 0); + } else { + result.insert(QStringLiteral("fromFrame"), fromFrame); + result.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size()); + result.insert(QStringLiteral("frames"), frameArray); + } + collectedRefs = collector->flushCollectedRefs(); +} + +FrameJob::FrameJob(QV4DataCollector *collector, int frameNr) : + CollectJob(collector), frameNr(frameNr), success(false) +{ +} + +void FrameJob::run() +{ + QVector<QV4::StackFrame> frames = collector->engine()->stackTrace(frameNr + 1); + if (frameNr >= frames.length()) { + success = false; + } else { + result = collector->buildFrame(frames[frameNr], frameNr); + collectedRefs = collector->flushCollectedRefs(); + success = true; + } +} + +bool FrameJob::wasSuccessful() const +{ + return success; +} + +ScopeJob::ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr) : + CollectJob(collector), frameNr(frameNr), scopeNr(scopeNr), success(false) +{ +} + +void ScopeJob::run() +{ + QJsonObject object; + success = collector->collectScope(&object, frameNr, scopeNr); + + if (success) { + QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = + QV4DataCollector::getScopeTypes(collector->engine(), frameNr); + result[QLatin1String("type")] = QV4DataCollector::encodeScopeType(scopeTypes[scopeNr]); + } else { + result[QLatin1String("type")] = -1; + } + result[QLatin1String("index")] = scopeNr; + result[QLatin1String("frameIndex")] = frameNr; + result[QLatin1String("object")] = object; + collectedRefs = collector->flushCollectedRefs(); +} + +bool ScopeJob::wasSuccessful() const +{ + return success; +} + ValueLookupJob::ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector) : - collector(collector), handles(handles) {} + CollectJob(collector), handles(handles) {} void ValueLookupJob::run() { @@ -152,16 +223,6 @@ const QString &ValueLookupJob::exceptionMessage() const return exception; } -const QJsonObject &ValueLookupJob::returnValue() const -{ - return result; -} - -const QJsonArray &ValueLookupJob::refs() const -{ - return collectedRefs; -} - ExpressionEvalJob::ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression, QV4DataCollector *collector) : JavaScriptJob(engine, frameNr, expression), collector(collector) @@ -209,100 +270,6 @@ const QStringList &GatherSourcesJob::result() const return sources; } -ArgumentCollectJob::ArgumentCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, - QStringList *names, int frameNr, int scopeNr) - : engine(engine) - , collector(collector) - , names(names) - , frameNr(frameNr) - , scopeNr(scopeNr) -{} - -void ArgumentCollectJob::run() -{ - if (frameNr < 0) - return; - - QV4::Scope scope(engine); - QV4::Scoped<QV4::CallContext> ctxt( - scope, QV4DataCollector::findScope(QV4DataCollector::findContext(engine, frameNr), scopeNr)); - if (!ctxt) - return; - - QV4::ScopedValue v(scope); - int nFormals = ctxt->formalCount(); - for (unsigned i = 0, ei = nFormals; i != ei; ++i) { - QString qName; - if (QV4::Identifier *name = ctxt->formals()[nFormals - i - 1]) - qName = name->string; - names->append(qName); - v = ctxt->argument(i); - collector->collect(v); - } -} - -LocalCollectJob::LocalCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, - QStringList *names, int frameNr, int scopeNr) - : engine(engine) - , collector(collector) - , names(names) - , frameNr(frameNr) - , scopeNr(scopeNr) -{} - -void LocalCollectJob::run() -{ - if (frameNr < 0) - return; - - QV4::Scope scope(engine); - QV4::Scoped<QV4::CallContext> ctxt( - scope, QV4DataCollector::findScope(QV4DataCollector::findContext(engine, frameNr), scopeNr)); - if (!ctxt) - return; - - QV4::ScopedValue v(scope); - for (unsigned i = 0, ei = ctxt->variableCount(); i != ei; ++i) { - QString qName; - if (QV4::Identifier *name = ctxt->variables()[i]) - qName = name->string; - names->append(qName); - v = ctxt->d()->locals[i]; - collector->collect(v); - } -} - -ThisCollectJob::ThisCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, - int frameNr) - : engine(engine) - , collector(collector) - , frameNr(frameNr) - , thisRef(QV4DataCollector::s_invalidRef) -{} - -void ThisCollectJob::run() -{ - QV4::Scope scope(engine); - QV4::ScopedContext ctxt(scope, QV4DataCollector::findContext(engine, frameNr)); - while (ctxt) { - if (QV4::CallContext *cCtxt = ctxt->asCallContext()) - if (cCtxt->d()->activation) - break; - ctxt = ctxt->d()->outer; - } - - if (!ctxt) - return; - - QV4::ScopedValue o(scope, ctxt->asCallContext()->d()->activation); - thisRef = collector->collect(o); -} - -QV4DataCollector::Ref ThisCollectJob::foundRef() const -{ - return thisRef; -} - ExceptionCollectJob::ExceptionCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector) : engine(engine) , collector(collector) diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h index e48b5b1e5e..a1adbeff40 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h @@ -72,88 +72,86 @@ protected: virtual void handleResult(QV4::ScopedValue &result) = 0; }; -class ValueLookupJob: public QV4DebugJob +class CollectJob : public QV4DebugJob { +protected: QV4DataCollector *collector; - const QJsonArray handles; QJsonObject result; QJsonArray collectedRefs; - QString exception; +public: + CollectJob(QV4DataCollector *collector) : collector(collector) {} + const QJsonObject &returnValue() const { return result; } + const QJsonArray &refs() const { return collectedRefs; } +}; +class BacktraceJob: public CollectJob +{ + int fromFrame; + int toFrame; public: - ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector); + BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame); void run(); - const QString &exceptionMessage() const; - const QJsonObject &returnValue() const; - const QJsonArray &refs() const; }; -class ExpressionEvalJob: public JavaScriptJob +class FrameJob: public CollectJob { - QV4DataCollector *collector; - QString exception; - QJsonObject result; - QJsonArray collectedRefs; + int frameNr; + bool success; public: - ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression, - QV4DataCollector *collector); - virtual void handleResult(QV4::ScopedValue &value); - const QString &exceptionMessage() const; - const QJsonObject &returnValue() const; - const QJsonArray &refs() const; + FrameJob(QV4DataCollector *collector, int frameNr); + void run(); + bool wasSuccessful() const; }; -class GatherSourcesJob: public QV4DebugJob +class ScopeJob: public CollectJob { - QV4::ExecutionEngine *engine; - QStringList sources; + int frameNr; + int scopeNr; + bool success; public: - GatherSourcesJob(QV4::ExecutionEngine *engine); + ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr); void run(); - const QStringList &result() const; + bool wasSuccessful() const; }; -class ArgumentCollectJob: public QV4DebugJob +class ValueLookupJob: public CollectJob { - QV4::ExecutionEngine *engine; - QV4DataCollector *collector; - QStringList *names; - int frameNr; - int scopeNr; + const QJsonArray handles; + QString exception; public: - ArgumentCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, - QStringList *names, int frameNr, int scopeNr); + ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector); void run(); + const QString &exceptionMessage() const; }; -class LocalCollectJob: public QV4DebugJob +class ExpressionEvalJob: public JavaScriptJob { - QV4::ExecutionEngine *engine; QV4DataCollector *collector; - QStringList *names; - int frameNr; - int scopeNr; + QString exception; + QJsonObject result; + QJsonArray collectedRefs; public: - LocalCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, QStringList *names, - int frameNr, int scopeNr); - void run(); + ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression, + QV4DataCollector *collector); + virtual void handleResult(QV4::ScopedValue &value); + const QString &exceptionMessage() const; + const QJsonObject &returnValue() const; + const QJsonArray &refs() const; }; -class ThisCollectJob: public QV4DebugJob +class GatherSourcesJob: public QV4DebugJob { QV4::ExecutionEngine *engine; - QV4DataCollector *collector; - int frameNr; - QV4DataCollector::Ref thisRef; + QStringList sources; public: - ThisCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, int frameNr); + GatherSourcesJob(QV4::ExecutionEngine *engine); void run(); - QV4DataCollector::Ref foundRef() const; + const QStringList &result() const; }; class ExceptionCollectJob: public QV4DebugJob @@ -176,8 +174,7 @@ public: EvalJob(QV4::ExecutionEngine *engine, const QString &script); virtual void handleResult(QV4::ScopedValue &result); - bool resultAsBoolean() const -; + bool resultAsBoolean() const; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp index ba953eb21d..5ee9e5e9e9 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp @@ -285,26 +285,16 @@ public: return; } - QJsonArray frameArray; - QVector<QV4::StackFrame> frames = debugger->stackTrace(toFrame); - for (int i = fromFrame; i < toFrame && i < frames.size(); ++i) - frameArray.push_back(debugService->buildFrame(frames[i], i, debugger)); + BacktraceJob job(debugger->collector(), fromFrame, toFrame); + debugger->runInEngine(&job); // response: addCommand(); addRequestSequence(); addSuccess(true); addRunning(); - QJsonObject body; - if (frameArray.isEmpty()) { - body.insert(QStringLiteral("totalFrames"), 0); - } else { - body.insert(QStringLiteral("fromFrame"), fromFrame); - body.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size()); - body.insert(QStringLiteral("frames"), frameArray); - } - addBody(body); - addRefs(debugger->collector()->flushCollectedRefs()); + addBody(job.returnValue()); + addRefs(job.refs()); } }; @@ -326,22 +316,27 @@ public: return; } - QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1); - if (frameNr < 0 || frameNr >= frames.size()) { + if (frameNr < 0) { createErrorResponse(QStringLiteral("frame command has invalid frame number")); return; } + FrameJob job(debugger->collector(), frameNr); + debugger->runInEngine(&job); + if (!job.wasSuccessful()) { + createErrorResponse(QStringLiteral("frame retrieval failed")); + return; + } + debugService->selectFrame(frameNr); - QJsonObject frame = debugService->buildFrame(frames[frameNr], frameNr, debugger); // response: addCommand(); addRequestSequence(); addSuccess(true); addRunning(); - addBody(frame); - addRefs(debugger->collector()->flushCollectedRefs()); + addBody(job.returnValue()); + addRefs(job.refs()); } }; @@ -364,8 +359,7 @@ public: return; } - QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1); - if (frameNr < 0 || frameNr >= frames.size()) { + if (frameNr < 0) { createErrorResponse(QStringLiteral("scope command has invalid frame number")); return; } @@ -374,15 +368,20 @@ public: return; } - QJsonObject scope = debugService->buildScope(frameNr, scopeNr, debugger); + ScopeJob job(debugger->collector(), frameNr, scopeNr); + debugger->runInEngine(&job); + if (!job.wasSuccessful()) { + createErrorResponse(QStringLiteral("scope retrieval failed")); + return; + } // response: addCommand(); addRequestSequence(); addSuccess(true); addRunning(); - addBody(scope); - addRefs(debugger->collector()->flushCollectedRefs()); + addBody(job.returnValue()); + addRefs(job.refs()); } }; @@ -836,98 +835,6 @@ void QV4DebugServiceImpl::send(QJsonObject v8Payload) emit messageToClient(name(), packMessage("v8message", responseData)); } -QJsonObject QV4DebugServiceImpl::buildFrame(const QV4::StackFrame &stackFrame, int frameNr, - QV4Debugger *debugger) -{ - QV4DataCollector::Ref ref; - - QJsonObject frame; - frame[QLatin1String("index")] = frameNr; - frame[QLatin1String("debuggerFrame")] = false; - ref = debugger->collector()->addFunctionRef(stackFrame.function); - frame[QLatin1String("func")] = toRef(ref); - ref = debugger->collector()->addScriptRef(stackFrame.source); - frame[QLatin1String("script")] = toRef(ref); - frame[QLatin1String("line")] = stackFrame.line - 1; - if (stackFrame.column >= 0) - frame[QLatin1String("column")] = stackFrame.column; - - QJsonArray scopes; - Q_ASSERT (debugger->state() == QV4Debugger::Paused); - - ThisCollectJob job(debugger->engine(), debugger->collector(), frameNr); - debugger->runInEngine(&job); - if (job.foundRef() != QV4DataCollector::s_invalidRef) - frame[QLatin1String("receiver")] = toRef(job.foundRef()); - - // Only type and index are used by Qt Creator, so we keep it easy: - QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = - QV4DataCollector::getScopeTypes(debugger->engine(), frameNr); - for (int i = 0, ei = scopeTypes.count(); i != ei; ++i) { - int type = encodeScopeType(scopeTypes[i]); - if (type == -1) - continue; - - QJsonObject scope; - scope[QLatin1String("index")] = i; - scope[QLatin1String("type")] = type; - scopes.push_back(scope); - } - frame[QLatin1String("scopes")] = scopes; - - return frame; -} - -int QV4DebugServiceImpl::encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType) -{ - switch (scopeType) { - case QV4::Heap::ExecutionContext::Type_GlobalContext: - return 0; - break; - case QV4::Heap::ExecutionContext::Type_CatchContext: - return 4; - break; - case QV4::Heap::ExecutionContext::Type_WithContext: - return 2; - break; - case QV4::Heap::ExecutionContext::Type_SimpleCallContext: - case QV4::Heap::ExecutionContext::Type_CallContext: - return 1; - break; - case QV4::Heap::ExecutionContext::Type_QmlContext: - default: - return -1; - } -} - -QJsonObject QV4DebugServiceImpl::buildScope(int frameNr, int scopeNr, QV4Debugger *debugger) -{ - QJsonObject scope; - - QJsonObject object; - debugger->collector()->collectScope(&object, debugger, frameNr, scopeNr); - - if (debugger->state() == QV4Debugger::Paused) { - QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = - QV4DataCollector::getScopeTypes(debugger->engine(), frameNr); - scope[QLatin1String("type")] = encodeScopeType(scopeTypes[scopeNr]); - } else { - scope[QLatin1String("type")] = -1; - } - scope[QLatin1String("index")] = scopeNr; - scope[QLatin1String("frameIndex")] = frameNr; - scope[QLatin1String("object")] = object; - - return scope; -} - -QJsonValue QV4DebugServiceImpl::toRef(QV4DataCollector::Ref ref) -{ - QJsonObject dict; - dict.insert(QStringLiteral("ref"), qint64(ref)); - return dict; -} - void QV4DebugServiceImpl::selectFrame(int frameNr) { theSelectedFrame = frameNr; diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h index df9da2c07f..69e32189b8 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h @@ -83,10 +83,6 @@ public: void signalEmitted(const QString &signal) Q_DECL_OVERRIDE; void send(QJsonObject v8Payload); - QJsonObject buildScope(int frameNr, int scopeNr, QV4Debugger *debugger); - QJsonValue toRef(QV4DataCollector::Ref ref); - - QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr, QV4Debugger *debugger); int selectedFrame() const; void selectFrame(int frameNr); @@ -104,11 +100,9 @@ private: const QByteArray &message = QByteArray()); void processCommand(const QByteArray &command, const QByteArray &data); V8CommandHandler *v8CommandHandler(const QString &command) const; - int encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType); QStringList breakOnSignals; static int sequence; - int theSelectedFrame; void addHandler(V8CommandHandler* handler); diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp index fd504c50d3..7398e97326 100644 --- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp @@ -100,16 +100,24 @@ public: typedef QV4DataCollector::Refs Refs; typedef QV4DataCollector::Ref Ref; struct NamedRefs { - QStringList names; QJsonArray refs; + QJsonObject scope; int size() const { - Q_ASSERT(names.size() == refs.size()); - return names.size(); + return scope.size(); } bool contains(const QString &name) const { - return names.contains(name); + return scope.contains(name); + } + + QJsonObject resolveRef(int ref) const { + foreach (const QJsonValue &val, refs) { + QJsonObject obj = val.toObject(); + if (obj.value(QLatin1String("handle")).toInt() == ref) + return obj; + } + return QJsonObject(); } #define DUMP_JSON(x) {\ @@ -119,7 +127,7 @@ public: QJsonObject rawValue(const QString &name) const { Q_ASSERT(contains(name)); - return refs.at(names.indexOf(name)).toObject(); + return scope[name].toObject(); } QJsonValue value(const QString &name) const { @@ -136,7 +144,7 @@ public: return; } - QJsonObject o = refs.at(names.indexOf(name)).toObject(); + QJsonObject o = scope[name].toObject(); QJsonDocument d; d.setObject(o); qDebug() << name << "=" << d.toJson(QJsonDocument::Indented); @@ -202,17 +210,30 @@ public: void captureContextInfo(QV4Debugger *debugger) { for (int i = 0, ei = m_stackTrace.size(); i != ei; ++i) { - m_capturedArguments.append(NamedRefs()); - ArgumentCollectJob argumentsJob(debugger->engine(), &collector, - &m_capturedArguments.last().names, i, 0); - debugger->runInEngine(&argumentsJob); - m_capturedArguments.last().refs = collector.flushCollectedRefs(); - - m_capturedLocals.append(NamedRefs()); - LocalCollectJob localsJob(debugger->engine(), &collector, - &m_capturedLocals.last().names, i, 0); - debugger->runInEngine(&localsJob); - m_capturedLocals.last().refs = collector.flushCollectedRefs(); + m_capturedScope.append(NamedRefs()); + ScopeJob job(&collector, i, 0); + debugger->runInEngine(&job); + NamedRefs &refs = m_capturedScope.last(); + refs.refs = job.refs(); + QJsonObject object = job.returnValue(); + object = object.value(QLatin1String("object")).toObject(); + int ref = object.value(QLatin1String("ref")).toInt(); + object = refs.resolveRef(ref); + foreach (const QJsonValue &value, object.value(QLatin1String("properties")).toArray()) { + QJsonObject property = value.toObject(); + QString name = property.value(QLatin1String("name")).toString(); + property.remove(QLatin1String("name")); + if (property.contains(QLatin1String("ref"))) { + int childRef = property.value(QLatin1String("ref")).toInt(); + if (childRef >= 0 && refs.refs.size() > childRef) { + property.remove(QLatin1String("ref")); + property.insert(QLatin1String("properties"), + refs.resolveRef(childRef).value( + QLatin1String("properties")).toArray()); + } + } + refs.scope.insert(name, property); + } } } @@ -229,8 +250,7 @@ public: QList<QV4Debugger::ExecutionState> m_statesWhenPaused; QList<TestBreakPoint> m_breakPointsToAddWhenPaused; QVector<QV4::StackFrame> m_stackTrace; - QVector<NamedRefs> m_capturedArguments; - QVector<NamedRefs> m_capturedLocals; + QVector<NamedRefs> m_capturedScope; qint64 m_thrownValue; QV4DataCollector collector; @@ -444,8 +464,8 @@ void tst_qv4debugger::conditionalBreakPoint() QCOMPARE(state.fileName, QString("conditionalBreakPoint")); QCOMPARE(state.lineNumber, 3); - QVERIFY(m_debuggerAgent->m_capturedLocals.size() > 1); - const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedLocals.at(0); + QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1); + const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0); QCOMPARE(frame0.size(), 2); QVERIFY(frame0.contains("i")); QCOMPARE(frame0.value("i").toInt(), 11); @@ -501,13 +521,13 @@ void tst_qv4debugger::readArguments() debugger()->addBreakPoint("readArguments", 2); evaluateJavaScript(script, "readArguments"); QVERIFY(m_debuggerAgent->m_wasPaused); - QVERIFY(m_debuggerAgent->m_capturedArguments.size() > 1); - const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedArguments.at(0); + QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1); + const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0); QCOMPARE(frame0.size(), 4); QVERIFY(frame0.contains(QStringLiteral("a"))); QCOMPARE(frame0.type(QStringLiteral("a")), QStringLiteral("number")); QCOMPARE(frame0.value(QStringLiteral("a")).toDouble(), 1.0); - QVERIFY(frame0.names.contains("b")); + QVERIFY(frame0.scope.contains("b")); QCOMPARE(frame0.type(QStringLiteral("b")), QStringLiteral("string")); QCOMPARE(frame0.value(QStringLiteral("b")).toString(), QStringLiteral("two")); } @@ -525,9 +545,9 @@ void tst_qv4debugger::readLocals() debugger()->addBreakPoint("readLocals", 3); evaluateJavaScript(script, "readLocals"); QVERIFY(m_debuggerAgent->m_wasPaused); - QVERIFY(m_debuggerAgent->m_capturedLocals.size() > 1); - const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedLocals.at(0); - QCOMPARE(frame0.size(), 2); + QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1); + const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0); + QCOMPARE(frame0.size(), 4); // locals and parameters QVERIFY(frame0.contains("c")); QCOMPARE(frame0.type("c"), QStringLiteral("number")); QCOMPARE(frame0.value("c").toDouble(), 3.0); @@ -547,9 +567,9 @@ void tst_qv4debugger::readObject() debugger()->addBreakPoint("readObject", 3); evaluateJavaScript(script, "readObject"); QVERIFY(m_debuggerAgent->m_wasPaused); - QVERIFY(m_debuggerAgent->m_capturedLocals.size() > 1); - const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedLocals.at(0); - QCOMPARE(frame0.size(), 1); + QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1); + const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0); + QCOMPARE(frame0.size(), 2); QVERIFY(frame0.contains("b")); QCOMPARE(frame0.type("b"), QStringLiteral("object")); QJsonObject b = frame0.rawValue("b"); @@ -600,28 +620,23 @@ void tst_qv4debugger::readContextInAllFrames() evaluateJavaScript(script, "readFormalsInAllFrames"); QVERIFY(m_debuggerAgent->m_wasPaused); QCOMPARE(m_debuggerAgent->m_stackTrace.size(), 13); - QCOMPARE(m_debuggerAgent->m_capturedArguments.size(), 13); - QCOMPARE(m_debuggerAgent->m_capturedLocals.size(), 13); + QCOMPARE(m_debuggerAgent->m_capturedScope.size(), 13); for (int i = 0; i < 12; ++i) { - const TestAgent::NamedRefs &args = m_debuggerAgent->m_capturedArguments.at(i); - QCOMPARE(args.size(), 1); - QVERIFY(args.contains("n")); - QCOMPARE(args.type("n"), QStringLiteral("number")); - QCOMPARE(args.value("n").toDouble(), i + 1.0); - - const TestAgent::NamedRefs &locals = m_debuggerAgent->m_capturedLocals.at(i); - QCOMPARE(locals.size(), 1); - QVERIFY(locals.contains("n_1")); + const TestAgent::NamedRefs &scope = m_debuggerAgent->m_capturedScope.at(i); + QCOMPARE(scope.size(), 2); + QVERIFY(scope.contains("n")); + QCOMPARE(scope.type("n"), QStringLiteral("number")); + QCOMPARE(scope.value("n").toDouble(), i + 1.0); + QVERIFY(scope.contains("n_1")); if (i == 0) { - QCOMPARE(locals.type("n_1"), QStringLiteral("undefined")); + QCOMPARE(scope.type("n_1"), QStringLiteral("undefined")); } else { - QCOMPARE(locals.type("n_1"), QStringLiteral("number")); - QCOMPARE(locals.value("n_1").toInt(), i); + QCOMPARE(scope.type("n_1"), QStringLiteral("number")); + QCOMPARE(scope.value("n_1").toInt(), i); } } - QCOMPARE(m_debuggerAgent->m_capturedArguments[12].size(), 0); - QCOMPARE(m_debuggerAgent->m_capturedLocals[12].size(), 0); + QCOMPARE(m_debuggerAgent->m_capturedScope[12].size(), 0); } void tst_qv4debugger::pauseOnThrow() |