diff options
author | Ulf Hermann <ulf.hermann@theqtcompany.com> | 2015-07-22 18:50:34 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@theqtcompany.com> | 2015-08-10 10:05:14 +0000 |
commit | a2ccdd33888cb0eb4516089d3418dd01c8cca25c (patch) | |
tree | 400d8d1de2223812f9b8c0106e69c6ef9656c0a3 /src/plugins | |
parent | bf5db2bbc1da83a9930832e628e65ec64cd4b831 (diff) | |
download | qtdeclarative-a2ccdd33888cb0eb4516089d3418dd01c8cca25c.tar.gz qtdeclarative-a2ccdd33888cb0eb4516089d3418dd01c8cca25c.tar.bz2 qtdeclarative-a2ccdd33888cb0eb4516089d3418dd01c8cca25c.zip |
Move DataCollector into debugger plugin
The data collector and all the jobs it uses to interact with the engine
are only used from the debugger plugin. We can as well move them there.
Change-Id: Ia48251f08b48c7e1e607b8ae2a3d1de29f80f742
Reviewed-by: Erik Verbruggen <erik.verbruggen@theqtcompany.com>
Diffstat (limited to 'src/plugins')
6 files changed, 686 insertions, 38 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro index dd0c9a174..d860328dc 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro +++ b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro @@ -11,7 +11,8 @@ SOURCES += \ $$PWD/qqmlenginedebugservice.cpp \ $$PWD/qqmlwatcher.cpp \ $$PWD/qv4debugservice.cpp \ - $$PWD/qv4debuggeragent.cpp + $$PWD/qv4debuggeragent.cpp \ + $$PWD/qv4datacollector.cpp HEADERS += \ $$PWD/../shared/qqmlconfigurabledebugservice.h \ @@ -20,7 +21,8 @@ HEADERS += \ $$PWD/qqmlenginedebugservice.h \ $$PWD/qqmlwatcher.h \ $$PWD/qv4debugservice.h \ - $$PWD/qv4debuggeragent.h + $$PWD/qv4debuggeragent.h \ + $$PWD/qv4datacollector.h INCLUDEPATH += $$PWD \ $$PWD/../shared diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp new file mode 100644 index 000000000..64ee5c3b9 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -0,0 +1,452 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qv4datacollector.h" + +#include <private/qv4script_p.h> +#include <private/qv4string_p.h> +#include <private/qv4objectiterator_p.h> +#include <private/qv4identifier_p.h> + +#include <QtCore/qjsonarray.h> + +QT_BEGIN_NAMESPACE + +QV4::Heap::CallContext *QV4DataCollector::findContext(QV4::Heap::ExecutionContext *ctxt, int frame) +{ + if (!ctxt) + return 0; + + QV4::Scope scope(ctxt->engine); + QV4::ScopedContext ctx(scope, ctxt); + while (ctx) { + QV4::CallContext *cCtxt = ctx->asCallContext(); + if (cCtxt && cCtxt->d()->function) { + if (frame < 1) + return cCtxt->d(); + --frame; + } + ctx = ctx->d()->parent; + } + + return 0; +} + +QV4::Heap::CallContext *QV4DataCollector::findScope(QV4::Heap::ExecutionContext *ctxt, int scope) +{ + if (!ctxt) + return 0; + + QV4::Scope s(ctxt->engine); + QV4::ScopedContext ctx(s, ctxt); + for (; scope > 0 && ctx; --scope) + ctx = ctx->d()->outer; + + return (ctx && ctx->d()) ? ctx->asCallContext()->d() : 0; +} + +QVector<QV4::Heap::ExecutionContext::ContextType> QV4DataCollector::getScopeTypes( + QV4::ExecutionEngine *engine, int frame) +{ + QVector<QV4::Heap::ExecutionContext::ContextType> types; + + QV4::Scope scope(engine); + QV4::Scoped<QV4::CallContext> sctxt(scope, findContext(engine->currentContext(), frame)); + if (!sctxt || sctxt->d()->type < QV4::Heap::ExecutionContext::Type_QmlContext) + return types; + + QV4::ScopedContext it(scope, sctxt->d()); + for (; it; it = it->d()->outer) + types.append(it->d()->type); + + return types; +} + + +QV4DataCollector::QV4DataCollector(QV4::ExecutionEngine *engine) + : m_engine(engine), m_collectedRefs(Q_NULLPTR) +{ + values.set(engine, engine->newArrayObject()); +} + +QV4DataCollector::~QV4DataCollector() +{ +} + +void QV4DataCollector::collect(const QV4::ScopedValue &value) +{ + if (m_collectedRefs) + m_collectedRefs->append(addRef(value)); +} + +QJsonObject QV4DataCollector::lookupRef(Ref ref) +{ + QJsonObject dict; + if (lookupSpecialRef(ref, &dict)) + return dict; + + dict.insert(QStringLiteral("handle"), qint64(ref)); + + QV4::Scope scope(engine()); + QV4::ScopedValue value(scope, getValue(ref)); + switch (value->type()) { + case QV4::Value::Empty_Type: + Q_ASSERT(!"empty Value encountered"); + break; + case QV4::Value::Undefined_Type: + dict.insert(QStringLiteral("type"), QStringLiteral("undefined")); + break; + case QV4::Value::Null_Type: + dict.insert(QStringLiteral("type"), QStringLiteral("null")); + break; + case QV4::Value::Boolean_Type: + dict.insert(QStringLiteral("type"), QStringLiteral("boolean")); + dict.insert(QStringLiteral("value"), value->booleanValue() ? QStringLiteral("true") + : QStringLiteral("false")); + break; + case QV4::Value::Managed_Type: + if (QV4::String *s = value->as<QV4::String>()) { + dict.insert(QStringLiteral("type"), QStringLiteral("string")); + dict.insert(QStringLiteral("value"), s->toQString()); + } else if (QV4::Object *o = value->as<QV4::Object>()) { + dict.insert(QStringLiteral("type"), QStringLiteral("object")); + dict.insert(QStringLiteral("properties"), collectProperties(o)); + } else { + Q_UNREACHABLE(); + } + break; + case QV4::Value::Integer_Type: + dict.insert(QStringLiteral("type"), QStringLiteral("number")); + dict.insert(QStringLiteral("value"), value->integerValue()); + break; + default: // double + dict.insert(QStringLiteral("type"), QStringLiteral("number")); + dict.insert(QStringLiteral("value"), value->doubleValue()); + break; + } + + return dict; +} + +QV4DataCollector::Ref QV4DataCollector::addFunctionRef(const QString &functionName) +{ + Ref ref = addRef(QV4::Primitive::emptyValue(), false); + + QJsonObject dict; + dict.insert(QStringLiteral("handle"), qint64(ref)); + dict.insert(QStringLiteral("type"), QStringLiteral("function")); + dict.insert(QStringLiteral("className"), QStringLiteral("Function")); + dict.insert(QStringLiteral("name"), functionName); + specialRefs.insert(ref, dict); + + return ref; +} + +QV4DataCollector::Ref QV4DataCollector::addScriptRef(const QString &scriptName) +{ + Ref ref = addRef(QV4::Primitive::emptyValue(), false); + + QJsonObject dict; + dict.insert(QStringLiteral("handle"), qint64(ref)); + dict.insert(QStringLiteral("type"), QStringLiteral("script")); + dict.insert(QStringLiteral("name"), scriptName); + specialRefs.insert(ref, dict); + + return ref; +} + +void QV4DataCollector::collectScope(QJsonObject *dict, QV4::Debugging::Debugger *debugger, + int frameNr, int scopeNr) +{ + QStringList names; + + Refs refs; + if (debugger->state() == QV4::Debugging::Debugger::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::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) + scopeObject->put(engine(), names.at(i), + QV4::Value::fromReturnedValue(getValue(refs.at(i)))); + + Ref scopeObjectRef = addRef(scopeObject); + dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef)); + if (m_collectedRefs) + m_collectedRefs->append(scopeObjectRef); +} + +QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicate) +{ + class ExceptionStateSaver + { + quint32 *hasExceptionLoc; + quint32 hadException; + + public: + ExceptionStateSaver(QV4::ExecutionEngine *engine) + : hasExceptionLoc(&engine->hasException) + , hadException(false) + { std::swap(*hasExceptionLoc, hadException); } + + ~ExceptionStateSaver() + { std::swap(*hasExceptionLoc, hadException); } + }; + + // if we wouldn't do this, the putIndexed won't work. + ExceptionStateSaver resetExceptionState(engine()); + QV4::Scope scope(engine()); + QV4::ScopedObject array(scope, values.value()); + if (deduplicate) { + for (Ref i = 0; i < array->getLength(); ++i) { + if (array->getIndexed(i) == value.rawValue()) + return i; + } + } + Ref ref = array->getLength(); + array->putIndexed(ref, value); + Q_ASSERT(array->getLength() - 1 == ref); + return ref; +} + +QV4::ReturnedValue QV4DataCollector::getValue(Ref ref) +{ + QV4::Scope scope(engine()); + QV4::ScopedObject array(scope, values.value()); + Q_ASSERT(ref < array->getLength()); + return array->getIndexed(ref, Q_NULLPTR); +} + +bool QV4DataCollector::lookupSpecialRef(Ref ref, QJsonObject *dict) +{ + SpecialRefs::const_iterator it = specialRefs.find(ref); + if (it == specialRefs.end()) + return false; + + *dict = it.value(); + return true; +} + +QJsonArray QV4DataCollector::collectProperties(QV4::Object *object) +{ + QJsonArray res; + + QV4::Scope scope(engine()); + QV4::ObjectIterator it(scope, object, QV4::ObjectIterator::EnumerableOnly); + QV4::ScopedValue name(scope); + QV4::ScopedValue value(scope); + while (true) { + QV4::Value v; + name = it.nextPropertyNameAsString(&v); + if (name->isNull()) + break; + QString key = name->toQStringNoThrow(); + value = v; + res.append(collectAsJson(key, value)); + } + + return res; +} + +QJsonObject QV4DataCollector::collectAsJson(const QString &name, const QV4::ScopedValue &value) +{ + QJsonObject dict; + if (!name.isNull()) + dict.insert(QStringLiteral("name"), name); + Ref ref = addRef(value); + dict.insert(QStringLiteral("ref"), qint64(ref)); + if (m_collectedRefs) + m_collectedRefs->append(ref); + + // TODO: enable this when creator can handle it. + if (false) { + if (value->isManaged() && !value->isString()) { + QV4::Scope scope(engine()); + QV4::ScopedObject obj(scope, value->as<QV4::Object>()); + dict.insert(QStringLiteral("propertycount"), qint64(obj->getLength())); + } + } + + return dict; +} + +ExpressionEvalJob::ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, + const QString &expression, + QV4DataCollector *collector) + : JavaScriptJob(engine, frameNr, expression) + , collector(collector) +{ +} + +void ExpressionEvalJob::handleResult(QV4::ScopedValue &result) +{ + collector->collect(result); +} + +GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine, int seq) + : engine(engine) + , seq(seq) +{} + +void GatherSourcesJob::run() +{ + QStringList sources; + + foreach (QV4::CompiledData::CompilationUnit *unit, engine->compilationUnits) { + QString fileName = unit->fileName(); + if (!fileName.isEmpty()) + sources.append(fileName); + } + + QV4::Debugging::Debugger *debugger = engine->debugger; + 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->currentContext(), 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->currentContext(), 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) + : engine(engine) + , collector(collector) + , frameNr(frameNr) + , foundThis(foundThis) +{} + +void ThisCollectJob::run() +{ + *foundThis = myRun(); +} + +bool ThisCollectJob::myRun() +{ + QV4::Scope scope(engine); + QV4::ScopedContext ctxt(scope, QV4DataCollector::findContext(engine->currentContext(), + 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; +} + +ExceptionCollectJob::ExceptionCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector) + : engine(engine) + , collector(collector) +{} + +void ExceptionCollectJob::run() +{ + QV4::Scope scope(engine); + QV4::ScopedValue v(scope, *engine->exceptionValue); + collector->collect(v); +} + +QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h new file mode 100644 index 000000000..c91b77cb9 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QV4DATACOLLECTOR_H +#define QV4DATACOLLECTOR_H + +#include <private/qv4engine_p.h> +#include <private/qv4debugging_p.h> + +QT_BEGIN_NAMESPACE + +class QV4DataCollector +{ +public: + typedef uint Ref; + typedef QVector<uint> Refs; + + static QV4::Heap::CallContext *findContext(QV4::Heap::ExecutionContext *ctxt, int frame); + static QV4::Heap::CallContext *findScope(QV4::Heap::ExecutionContext *ctxt, int scope); + static QVector<QV4::Heap::ExecutionContext::ContextType> getScopeTypes( + QV4::ExecutionEngine *engine, int frame); + + QV4DataCollector(QV4::ExecutionEngine *engine); + ~QV4DataCollector(); + + void collect(const QV4::ScopedValue &value); + + QJsonObject lookupRef(Ref ref); + + Ref addFunctionRef(const QString &functionName); + Ref addScriptRef(const QString &scriptName); + + void collectScope(QJsonObject *dict, QV4::Debugging::Debugger *debugger, int frameNr, + int scopeNr); + + QV4::ExecutionEngine *engine() const { return m_engine; } + +private: + friend class RefHolder; + + Ref addRef(QV4::Value value, bool deduplicate = true); + QV4::ReturnedValue getValue(Ref ref); + bool lookupSpecialRef(Ref ref, QJsonObject *dict); + + QJsonArray collectProperties(QV4::Object *object); + QJsonObject collectAsJson(const QString &name, const QV4::ScopedValue &value); + void collectArgumentsInContext(); + + QV4::ExecutionEngine *m_engine; + Refs *m_collectedRefs; + QV4::PersistentValue values; + typedef QHash<Ref, QJsonObject> SpecialRefs; + SpecialRefs specialRefs; +}; + +class RefHolder { +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; +}; + +class ExpressionEvalJob: public QV4::Debugging::Debugger::JavaScriptJob +{ + QV4DataCollector *collector; + +public: + ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression, + QV4DataCollector *collector); + virtual void handleResult(QV4::ScopedValue &result); +}; + +class GatherSourcesJob: public QV4::Debugging::Debugger::Job +{ + QV4::ExecutionEngine *engine; + const int seq; + +public: + GatherSourcesJob(QV4::ExecutionEngine *engine, int seq); + void run(); +}; + +class ArgumentCollectJob: public QV4::Debugging::Debugger::Job +{ + QV4::ExecutionEngine *engine; + QV4DataCollector *collector; + QStringList *names; + int frameNr; + int scopeNr; + +public: + ArgumentCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, + QStringList *names, int frameNr, int scopeNr); + void run(); +}; + +class LocalCollectJob: public QV4::Debugging::Debugger::Job +{ + QV4::ExecutionEngine *engine; + QV4DataCollector *collector; + QStringList *names; + int frameNr; + int scopeNr; + +public: + LocalCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, QStringList *names, + int frameNr, int scopeNr); + void run(); +}; + +class ThisCollectJob: public QV4::Debugging::Debugger::Job +{ + QV4::ExecutionEngine *engine; + QV4DataCollector *collector; + int frameNr; + bool *foundThis; + +public: + ThisCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, int frameNr, + bool *foundThis); + void run(); + bool myRun(); +}; + +class ExceptionCollectJob: public QV4::Debugging::Debugger::Job +{ + QV4::ExecutionEngine *engine; + QV4DataCollector *collector; + +public: + ExceptionCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector); + void run(); +}; + +QT_END_NAMESPACE + +#endif // QV4DATACOLLECTOR_H diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp index 15421f4f5..7f22b16e4 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp @@ -33,6 +33,7 @@ #include "qv4debuggeragent.h" #include "qv4debugservice.h" +#include "qv4datacollector.h" #include <QtCore/qjsonobject.h> #include <QtCore/qjsonarray.h> diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp index 21bfe9780..6b68f9518 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp @@ -506,7 +506,9 @@ public: } // do it: - debugService->debuggerAgent.firstDebugger()->gatherSources(requestSequenceNr()); + QV4::Debugging::Debugger *debugger = debugService->debuggerAgent.firstDebugger(); + GatherSourcesJob job(debugger->engine(), requestSequenceNr()); + debugger->runInEngine(&job); // response will be send by } @@ -555,10 +557,13 @@ public: QV4::Debugging::Debugger *debugger = debugService->debuggerAgent.firstDebugger(); Q_ASSERT(debugger->state() == QV4::Debugging::Debugger::Paused); - QV4::Debugging::DataCollector *collector = debugService->collector(); - QV4::Debugging::DataCollector::Refs refs; - QV4::Debugging::RefHolder holder(collector, &refs); - debugger->evaluateExpression(frame, expression, collector); + QV4DataCollector *collector = debugService->collector(); + QV4DataCollector::Refs refs; + RefHolder holder(collector, &refs); + Q_ASSERT(debugger->state() == QV4::Debugging::Debugger::Paused); + + ExpressionEvalJob job(debugger->engine(), frame, expression, collector); + debugger->runInEngine(&job); Q_ASSERT(refs.size() == 1); @@ -762,13 +767,13 @@ void QV4DebugServiceImpl::send(QJsonObject v8Payload) void QV4DebugServiceImpl::clearHandles(QV4::ExecutionEngine *engine) { - theCollector.reset(new QV4::Debugging::DataCollector(engine)); + theCollector.reset(new QV4DataCollector(engine)); } QJsonObject QV4DebugServiceImpl::buildFrame(const QV4::StackFrame &stackFrame, int frameNr, QV4::Debugging::Debugger *debugger) { - QV4::Debugging::DataCollector::Ref ref; + QV4DataCollector::Ref ref; QJsonObject frame; frame[QLatin1String("index")] = frameNr; @@ -783,24 +788,28 @@ QJsonObject QV4DebugServiceImpl::buildFrame(const QV4::StackFrame &stackFrame, i if (stackFrame.column >= 0) frame[QLatin1String("column")] = stackFrame.column; - { - QV4::Debugging::RefHolder holder(theCollector.data(), &collectedRefs); - if (debugger->collectThisInContext(theCollector.data(), frameNr)) - frame[QLatin1String("receiver")] = toRef(collectedRefs.last()); - } - QJsonArray scopes; - // Only type and index are used by Qt Creator, so we keep it easy: - QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = debugger->getScopeTypes(frameNr); - for (int i = 0, ei = scopeTypes.count(); i != ei; ++i) { - int type = encodeScopeType(scopeTypes[i]); - if (type == -1) - continue; + if (debugger->state() == QV4::Debugging::Debugger::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()); - QJsonObject scope; - scope[QLatin1String("index")] = i; - scope[QLatin1String("type")] = type; - scopes.push_back(scope); + // 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; @@ -835,11 +844,16 @@ QJsonObject QV4DebugServiceImpl::buildScope(int frameNr, int scopeNr, QJsonObject scope; QJsonObject object; - QV4::Debugging::RefHolder holder(theCollector.data(), &collectedRefs); + RefHolder holder(theCollector.data(), &collectedRefs); theCollector->collectScope(&object, debugger, frameNr, scopeNr); - QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = debugger->getScopeTypes(frameNr); - scope[QLatin1String("type")] = encodeScopeType(scopeTypes[scopeNr]); + if (debugger->state() == QV4::Debugging::Debugger::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; @@ -847,9 +861,9 @@ QJsonObject QV4DebugServiceImpl::buildScope(int frameNr, int scopeNr, return scope; } -QJsonValue QV4DebugServiceImpl::lookup(QV4::Debugging::DataCollector::Ref refId) +QJsonValue QV4DebugServiceImpl::lookup(QV4DataCollector::Ref refId) { - QV4::Debugging::RefHolder holder(theCollector.data(), &collectedRefs); + RefHolder holder(theCollector.data(), &collectedRefs); return theCollector->lookupRef(refId); } @@ -858,7 +872,7 @@ QJsonArray QV4DebugServiceImpl::buildRefs() QJsonArray refs; std::sort(collectedRefs.begin(), collectedRefs.end()); for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) { - QV4::Debugging::DataCollector::Ref ref = collectedRefs.at(i); + QV4DataCollector::Ref ref = collectedRefs.at(i); if (i > 0 && ref == collectedRefs.at(i - 1)) continue; refs.append(lookup(ref)); @@ -868,14 +882,14 @@ QJsonArray QV4DebugServiceImpl::buildRefs() return refs; } -QJsonValue QV4DebugServiceImpl::toRef(QV4::Debugging::DataCollector::Ref ref) +QJsonValue QV4DebugServiceImpl::toRef(QV4DataCollector::Ref ref) { QJsonObject dict; dict.insert(QStringLiteral("ref"), qint64(ref)); return dict; } -QV4::Debugging::DataCollector *QV4DebugServiceImpl::collector() const +QV4DataCollector *QV4DebugServiceImpl::collector() const { return theCollector.data(); } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h index 6e5113600..c80ad78cc 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h @@ -47,6 +47,7 @@ #include "qqmlconfigurabledebugservice.h" #include "qv4debuggeragent.h" +#include "qv4datacollector.h" #include <private/qqmldebugserviceinterfaces_p.h> #include <private/qv4debugging_p.h> @@ -77,8 +78,8 @@ public: QJsonObject buildScope(int frameNr, int scopeNr, QV4::Debugging::Debugger *debugger); QJsonArray buildRefs(); - QJsonValue lookup(QV4::Debugging::DataCollector::Ref refId); - QJsonValue toRef(QV4::Debugging::DataCollector::Ref ref); + QJsonValue lookup(QV4DataCollector::Ref refId); + QJsonValue toRef(QV4DataCollector::Ref ref); QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr, QV4::Debugging::Debugger *debugger); @@ -87,7 +88,7 @@ public: void clearHandles(QV4::ExecutionEngine *engine); - QV4::Debugging::DataCollector *collector() const; + QV4DataCollector *collector() const; QV4DebuggerAgent debuggerAgent; protected: @@ -109,9 +110,9 @@ private: static int debuggerIndex; static int sequence; const int version; - QV4::Debugging::DataCollector::Refs collectedRefs; + QV4DataCollector::Refs collectedRefs; - QScopedPointer<QV4::Debugging::DataCollector> theCollector; + QScopedPointer<QV4DataCollector> theCollector; int theSelectedFrame; void addHandler(V8CommandHandler* handler); |