diff options
Diffstat (limited to 'src/plugins/qmltooling/qmldbg_debugger')
4 files changed, 361 insertions, 349 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index 4cca1900de..a86373b627 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -89,9 +89,30 @@ 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_collectedRefs(Q_NULLPTR) + : m_engine(engine) { values.set(engine, engine->newArrayObject()); } @@ -100,10 +121,11 @@ QV4DataCollector::~QV4DataCollector() { } -void QV4DataCollector::collect(const QV4::ScopedValue &value) +QV4DataCollector::Ref QV4DataCollector::collect(const QV4::ScopedValue &value) { - if (m_collectedRefs) - m_collectedRefs->append(addRef(value)); + Ref ref = addRef(value); + collectedRefs.append(ref); + return ref; } const QV4::Object *collectProperty(const QV4::ScopedValue &value, QV4::ExecutionEngine *engine, @@ -191,6 +213,7 @@ QV4DataCollector::Ref QV4DataCollector::addFunctionRef(const QString &functionNa dict.insert(QStringLiteral("type"), QStringLiteral("function")); dict.insert(QStringLiteral("name"), functionName); specialRefs.insert(ref, dict); + collectedRefs.append(ref); return ref; } @@ -204,36 +227,133 @@ QV4DataCollector::Ref QV4DataCollector::addScriptRef(const QString &scriptName) dict.insert(QStringLiteral("type"), QStringLiteral("script")); dict.insert(QStringLiteral("name"), scriptName); specialRefs.insert(ref, dict); + collectedRefs.append(ref); return ref; } -void QV4DataCollector::collectScope(QJsonObject *dict, QV4::Debugging::V4Debugger *debugger, +bool QV4DataCollector::isValidRef(QV4DataCollector::Ref ref) const +{ + QV4::Scope scope(engine()); + QV4::ScopedObject array(scope, values.value()); + return ref < array->getLength(); +} + +bool QV4DataCollector::collectScope(QJsonObject *dict, QV4::Debugging::V4Debugger *debugger, int frameNr, int scopeNr) { QStringList names; - Refs refs; + QV4::Scope scope(engine()); if (debugger->state() == QV4::Debugging::V4Debugger::Paused) { - RefHolder holder(this, &refs); - ArgumentCollectJob argumentsJob(m_engine, this, &names, frameNr, scopeNr); - debugger->runInEngine(&argumentsJob); - LocalCollectJob localsJob(m_engine, this, &names, frameNr, scopeNr); - debugger->runInEngine(&localsJob); + 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() == refs.size()); - for (int i = 0, ei = refs.size(); i != ei; ++i) + Q_ASSERT(names.size() == collectedRefs.size()); + for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) scopeObject->put(engine(), names.at(i), - QV4::Value::fromReturnedValue(getValue(refs.at(i)))); + QV4::Value::fromReturnedValue(getValue(collectedRefs.at(i)))); Ref scopeObjectRef = addRef(scopeObject); dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef)); - if (m_collectedRefs) - m_collectedRefs->append(scopeObjectRef); + 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, + QV4::Debugging::V4Debugger *debugger) +{ + 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; + if (debugger->state() == QV4::Debugging::V4Debugger::Paused) { + 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() +{ + QJsonArray refs; + std::sort(collectedRefs.begin(), collectedRefs.end()); + for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) { + QV4DataCollector::Ref ref = collectedRefs.at(i); + if (i > 0 && ref == collectedRefs.at(i - 1)) + continue; + refs.append(lookupRef(ref)); + } + + collectedRefs.clear(); + return refs; } QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicate) @@ -316,14 +436,117 @@ QJsonObject QV4DataCollector::collectAsJson(const QString &name, const QV4::Scop if (value->isManaged() && !value->isString()) { Ref ref = addRef(value); dict.insert(QStringLiteral("ref"), qint64(ref)); - if (m_collectedRefs) - m_collectedRefs->append(ref); + collectedRefs.append(ref); } collectProperty(value, engine(), dict); return dict; } +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); + QV4::Debugging::V4Debugger *debugger = + qobject_cast<QV4::Debugging::V4Debugger *>(collector->engine()->debugger); + if (debugger) { + for (int i = fromFrame; i < toFrame && i < frames.size(); ++i) + frameArray.push_back(collector->buildFrame(frames[i], i, debugger)); + } + 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 { + QV4::Debugging::V4Debugger *debugger = + qobject_cast<QV4::Debugging::V4Debugger *>(collector->engine()->debugger); + if (debugger) { + result = collector->buildFrame(frames[frameNr], frameNr, debugger); + collectedRefs = collector->flushCollectedRefs(); + success = true; + } else { + success = false; + } + } +} + +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; + QV4::Debugging::V4Debugger *debugger = + qobject_cast<QV4::Debugging::V4Debugger *>(collector->engine()->debugger); + success = (debugger && collector->collectScope(&object, debugger, 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) : + CollectJob(collector), handles(handles) {} + +void ValueLookupJob::run() +{ + foreach (const QJsonValue &handle, handles) { + QV4DataCollector::Ref ref = handle.toInt(); + if (!collector->isValidRef(ref)) { + exception = QString::fromLatin1("Invalid Ref: %1").arg(ref); + break; + } + result[QString::number(ref)] = collector->lookupRef(ref); + } + collectedRefs = collector->flushCollectedRefs(); +} + +const QString &ValueLookupJob::exceptionMessage() const +{ + return exception; +} + ExpressionEvalJob::ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression, QV4DataCollector *collector) @@ -336,7 +559,8 @@ void ExpressionEvalJob::handleResult(QV4::ScopedValue &result) { if (hasExeption()) exception = result->toQStringNoThrow(); - collector->collect(result); + value = collector->lookupRef(collector->collect(result)); + collectedRefs = collector->flushCollectedRefs(); } const QString &ExpressionEvalJob::exceptionMessage() const @@ -344,6 +568,16 @@ const QString &ExpressionEvalJob::exceptionMessage() const return exception; } +const QJsonObject &ExpressionEvalJob::returnValue() const +{ + return value; +} + +const QJsonArray &ExpressionEvalJob::refs() const +{ + return collectedRefs; +} + GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine, int seq) : engine(engine) , seq(seq) @@ -364,111 +598,21 @@ void GatherSourcesJob::run() emit debugger->sourcesCollected(debugger, sources, seq); } -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, bool *foundThis) +ExceptionCollectJob::ExceptionCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector) : engine(engine) , collector(collector) - , frameNr(frameNr) - , foundThis(foundThis) + , exception(-1) {} -void ThisCollectJob::run() -{ - *foundThis = myRun(); -} - -bool ThisCollectJob::myRun() -{ +void ExceptionCollectJob::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 false; - - QV4::ScopedValue o(scope, ctxt->asCallContext()->d()->activation); - collector->collect(o); - return true; + QV4::ScopedValue v(scope, *engine->exceptionValue); + exception = collector->collect(v); } -ExceptionCollectJob::ExceptionCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector) - : engine(engine) - , collector(collector) -{} - -void ExceptionCollectJob::run() +QV4DataCollector::Ref ExceptionCollectJob::exceptionValue() const { - QV4::Scope scope(engine); - QV4::ScopedValue v(scope, *engine->exceptionValue); - collector->collect(v); + return exception; } QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h index d0e4a4ad18..5a2c8ff33b 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h @@ -37,6 +37,9 @@ #include <private/qv4engine_p.h> #include <private/qv4debugging_p.h> +#include <QtCore/QJsonObject> +#include <QtCore/QJsonArray> + QT_BEGIN_NAMESPACE class QV4DataCollector @@ -49,25 +52,27 @@ 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); ~QV4DataCollector(); - void collect(const QV4::ScopedValue &value); - + Ref collect(const QV4::ScopedValue &value); + bool isValidRef(Ref ref) const; QJsonObject lookupRef(Ref ref); Ref addFunctionRef(const QString &functionName); Ref addScriptRef(const QString &scriptName); - void collectScope(QJsonObject *dict, QV4::Debugging::V4Debugger *debugger, int frameNr, + bool collectScope(QJsonObject *dict, QV4::Debugging::V4Debugger *debugger, int frameNr, int scopeNr); + QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr, + QV4::Debugging::V4Debugger *debugger); QV4::ExecutionEngine *engine() const { return m_engine; } + QJsonArray flushCollectedRefs(); private: - friend class RefHolder; - Ref addRef(QV4::Value value, bool deduplicate = true); QV4::ReturnedValue getValue(Ref ref); bool lookupSpecialRef(Ref ref, QJsonObject *dict); @@ -77,102 +82,103 @@ private: void collectArgumentsInContext(); QV4::ExecutionEngine *m_engine; - Refs *m_collectedRefs; + Refs collectedRefs; QV4::PersistentValue values; typedef QHash<Ref, QJsonObject> SpecialRefs; SpecialRefs specialRefs; }; -class RefHolder { +class CollectJob : public QV4::Debugging::V4Debugger::Job +{ +protected: + QV4DataCollector *collector; + QJsonObject result; + QJsonArray collectedRefs; public: - RefHolder(QV4DataCollector *collector, QV4DataCollector::Refs *target) : - m_collector(collector), m_previousRefs(collector->m_collectedRefs) - { - m_collector->m_collectedRefs = target; - } - - ~RefHolder() - { - std::swap(m_collector->m_collectedRefs, m_previousRefs); - } - -private: - QV4DataCollector *m_collector; - QV4DataCollector::Refs *m_previousRefs; + CollectJob(QV4DataCollector *collector) : collector(collector) {} + const QJsonObject &returnValue() const { return result; } + const QJsonArray &refs() const { return collectedRefs; } }; -class ExpressionEvalJob: public QV4::Debugging::V4Debugger::JavaScriptJob +class BacktraceJob: public CollectJob { - QV4DataCollector *collector; - QString exception; - + int fromFrame; + int toFrame; public: - ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression, - QV4DataCollector *collector); - virtual void handleResult(QV4::ScopedValue &result); - const QString &exceptionMessage() const; + BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame); + void run(); }; -class GatherSourcesJob: public QV4::Debugging::V4Debugger::Job +class FrameJob: public CollectJob { - QV4::ExecutionEngine *engine; - const int seq; + int frameNr; + bool success; public: - GatherSourcesJob(QV4::ExecutionEngine *engine, int seq); + FrameJob(QV4DataCollector *collector, int frameNr); void run(); + bool wasSuccessful() const; }; -class ArgumentCollectJob: public QV4::Debugging::V4Debugger::Job +class ScopeJob: public CollectJob { - QV4::ExecutionEngine *engine; - QV4DataCollector *collector; - QStringList *names; int frameNr; int scopeNr; + bool success; public: - ArgumentCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, - QStringList *names, int frameNr, int scopeNr); + ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr); void run(); + bool wasSuccessful() const; }; -class LocalCollectJob: public QV4::Debugging::V4Debugger::Job +class ValueLookupJob: public CollectJob { - QV4::ExecutionEngine *engine; - QV4DataCollector *collector; - QStringList *names; - int frameNr; - int scopeNr; + const QJsonArray handles; + QString exception; public: - LocalCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, QStringList *names, - int frameNr, int scopeNr); + ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector); void run(); + const QString &exceptionMessage() const; }; -class ThisCollectJob: public QV4::Debugging::V4Debugger::Job +class ExpressionEvalJob: public QV4::Debugging::V4Debugger::JavaScriptJob { - QV4::ExecutionEngine *engine; QV4DataCollector *collector; - int frameNr; - bool *foundThis; + QString exception; + QJsonObject value; + QJsonArray collectedRefs; public: - ThisCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, int frameNr, - bool *foundThis); + ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression, + QV4DataCollector *collector); + virtual void handleResult(QV4::ScopedValue &result); + const QString &exceptionMessage() const; + const QJsonObject &returnValue() const; + const QJsonArray &refs() const; +}; + +class GatherSourcesJob: public QV4::Debugging::V4Debugger::Job +{ + QV4::ExecutionEngine *engine; + const int seq; + +public: + GatherSourcesJob(QV4::ExecutionEngine *engine, int seq); void run(); - bool myRun(); }; class ExceptionCollectJob: public QV4::Debugging::V4Debugger::Job { QV4::ExecutionEngine *engine; QV4DataCollector *collector; + QV4DataCollector::Ref exception; public: ExceptionCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector); void run(); + QV4DataCollector::Ref exceptionValue() const; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp index 5233a09992..e9bcd772e5 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp @@ -114,9 +114,9 @@ protected: response.insert(QStringLiteral("running"), debugService->debuggerAgent.isRunning()); } - void addRefs() + void addRefs(const QJsonArray &refs) { - response.insert(QStringLiteral("refs"), debugService->buildRefs()); + response.insert(QStringLiteral("refs"), refs); } void createErrorResponse(const QString &msg) @@ -271,28 +271,16 @@ public: int toFrame = arguments.value(QStringLiteral("toFrame")).toInt(fromFrame + 10); // no idea what the bottom property is for, so we'll ignore it. - QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger(); - - 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(debugService->collector(), fromFrame, toFrame); + debugService->debuggerAgent.firstDebugger()->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(); + addBody(job.returnValue()); + addRefs(job.refs()); } }; @@ -308,23 +296,27 @@ public: const int frameNr = arguments.value(QStringLiteral("number")).toInt( debugService->selectedFrame()); - QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger(); - 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(debugService->collector(), frameNr); + debugService->debuggerAgent.firstDebugger()->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(); + addBody(job.returnValue()); + addRefs(job.refs()); } }; @@ -341,9 +333,7 @@ public: debugService->selectedFrame()); const int scopeNr = arguments.value(QStringLiteral("number")).toInt(0); - QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger(); - 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; } @@ -352,15 +342,20 @@ public: return; } - QJsonObject scope = debugService->buildScope(frameNr, scopeNr, debugger); + ScopeJob job(debugService->collector(), frameNr, scopeNr); + debugService->debuggerAgent.firstDebugger()->runInEngine(&job); + if (!job.wasSuccessful()) { + createErrorResponse(QStringLiteral("scope retrieval failed")); + return; + } // response: addCommand(); addRequestSequence(); addSuccess(true); addRunning(); - addBody(scope); - addRefs(); + addBody(job.returnValue()); + addRefs(job.refs()); } }; @@ -375,17 +370,19 @@ public: QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); QJsonArray handles = arguments.value(QStringLiteral("handles")).toArray(); - QJsonObject body; - foreach (const QJsonValue &handle, handles) - body[QString::number(handle.toInt())] = debugService->lookup(handle.toInt()); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - addBody(body); - addRefs(); + ValueLookupJob job(handles, debugService->collector()); + debugService->debuggerAgent.firstDebugger()->runInEngine(&job); + if (!job.exceptionMessage().isEmpty()) { + createErrorResponse(job.exceptionMessage()); + } else { + // response: + addCommand(); + addRequestSequence(); + addSuccess(true); + addRunning(); + addBody(job.returnValue()); + addRefs(job.refs()); + } } }; @@ -557,7 +554,6 @@ public: const int frame = arguments.value(QStringLiteral("frame")).toInt(0); QV4DataCollector *collector = debugService->collector(); - RefHolder holder(collector, debugService->refs()); ExpressionEvalJob job(debugger->engine(), frame, expression, collector); debugger->runInEngine(&job); if (job.hasExeption()) { @@ -567,8 +563,8 @@ public: addRequestSequence(); addSuccess(true); addRunning(); - addBody(collector->lookupRef(debugService->refs()->last())); - addRefs(); + addBody(job.returnValue()); + addRefs(job.refs()); } } else { createErrorResponse(QStringLiteral("Debugger has to be paused for evaluate to work.")); @@ -789,135 +785,11 @@ void QV4DebugServiceImpl::clearHandles(QV4::ExecutionEngine *engine) theCollector.reset(new QV4DataCollector(engine)); } -QJsonObject QV4DebugServiceImpl::buildFrame(const QV4::StackFrame &stackFrame, int frameNr, - QV4::Debugging::V4Debugger *debugger) -{ - QV4DataCollector::Ref ref; - - QJsonObject frame; - frame[QLatin1String("index")] = frameNr; - frame[QLatin1String("debuggerFrame")] = false; - ref = theCollector->addFunctionRef(stackFrame.function); - collectedRefs.append(ref); - frame[QLatin1String("func")] = toRef(ref); - ref = theCollector->addScriptRef(stackFrame.source); - collectedRefs.append(ref); - frame[QLatin1String("script")] = toRef(ref); - frame[QLatin1String("line")] = stackFrame.line - 1; - if (stackFrame.column >= 0) - frame[QLatin1String("column")] = stackFrame.column; - - QJsonArray scopes; - if (debugger->state() == QV4::Debugging::V4Debugger::Paused) { - RefHolder holder(theCollector.data(), &collectedRefs); - bool foundThis = false; - ThisCollectJob job(debugger->engine(), theCollector.data(), frameNr, &foundThis); - debugger->runInEngine(&job); - if (foundThis) - frame[QLatin1String("receiver")] = toRef(collectedRefs.last()); - - // 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, - QV4::Debugging::V4Debugger *debugger) -{ - QJsonObject scope; - - QJsonObject object; - RefHolder holder(theCollector.data(), &collectedRefs); - theCollector->collectScope(&object, debugger, frameNr, scopeNr); - - if (debugger->state() == QV4::Debugging::V4Debugger::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::lookup(QV4DataCollector::Ref refId) -{ - RefHolder holder(theCollector.data(), &collectedRefs); - return theCollector->lookupRef(refId); -} - -QJsonArray QV4DebugServiceImpl::buildRefs() -{ - QJsonArray refs; - std::sort(collectedRefs.begin(), collectedRefs.end()); - for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) { - QV4DataCollector::Ref ref = collectedRefs.at(i); - if (i > 0 && ref == collectedRefs.at(i - 1)) - continue; - refs.append(lookup(ref)); - } - - collectedRefs.clear(); - return refs; -} - -QJsonValue QV4DebugServiceImpl::toRef(QV4DataCollector::Ref ref) -{ - QJsonObject dict; - dict.insert(QStringLiteral("ref"), qint64(ref)); - return dict; -} - QV4DataCollector *QV4DebugServiceImpl::collector() const { return theCollector.data(); } -QV4DataCollector::Refs *QV4DebugServiceImpl::refs() -{ - return &collectedRefs; -} - 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 273e5ffd62..658b1b3998 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h @@ -78,13 +78,6 @@ public: void signalEmitted(const QString &signal); void send(QJsonObject v8Payload); - QJsonObject buildScope(int frameNr, int scopeNr, QV4::Debugging::V4Debugger *debugger); - QJsonArray buildRefs(); - QJsonValue lookup(QV4DataCollector::Ref refId); - QJsonValue toRef(QV4DataCollector::Ref ref); - - QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr, - QV4::Debugging::V4Debugger *debugger); int selectedFrame() const; void selectFrame(int frameNr); @@ -92,7 +85,6 @@ public: QV4DataCollector *collector() const; QV4DebuggerAgent debuggerAgent; - QV4DataCollector::Refs *refs(); protected: void messageReceived(const QByteArray &); @@ -106,14 +98,12 @@ 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; QMap<int, QV4::Debugging::V4Debugger *> debuggerMap; static int debuggerIndex; static int sequence; const int version; - QV4DataCollector::Refs collectedRefs; QScopedPointer<QV4DataCollector> theCollector; int theSelectedFrame; |