diff options
10 files changed, 544 insertions, 439 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro index 9db38d2dfe..3703d0fe0b 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro +++ b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro @@ -14,8 +14,8 @@ SOURCES += \ $$PWD/qv4debugservice.cpp \ $$PWD/qv4debugger.cpp \ $$PWD/qv4debuggeragent.cpp \ - $$PWD/qv4datacollector.cpp - + $$PWD/qv4datacollector.cpp \ + $$PWD/qv4debugjob.cpp HEADERS += \ $$PWD/../shared/qqmlconfigurabledebugservice.h \ @@ -28,7 +28,8 @@ HEADERS += \ $$PWD/qv4debugservice.h \ $$PWD/qv4debugger.h \ $$PWD/qv4debuggeragent.h \ - $$PWD/qv4datacollector.h + $$PWD/qv4datacollector.h \ + $$PWD/qv4debugjob.h INCLUDEPATH += $$PWD \ $$PWD/../shared diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index 78cb2be8d3..2d8a39e126 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -32,6 +32,8 @@ ****************************************************************************/ #include "qv4datacollector.h" +#include "qv4debugger.h" +#include "qv4debugjob.h" #include <private/qv4script_p.h> #include <private/qv4string_p.h> @@ -353,206 +355,4 @@ QJsonObject QV4DataCollector::collectAsJson(const QString &name, const QV4::Scop return dict; } -void ValueLookupJob::run() -{ - // Open a QML context if we don't have one, yet. We might run into QML objects when looking up - // refs and that will crash without a valid QML context. Mind that engine->qmlContext() is only - // set if the engine is currently executing QML code. - QScopedPointer<QObject> scopeObject; - QV4::ExecutionEngine *engine = collector->engine(); - if (engine->qmlEngine() && !engine->qmlContext()) { - scopeObject.reset(new QObject); - engine->pushContext(engine->currentContext->newQmlContext( - QQmlContextData::get(engine->qmlEngine()->rootContext()), - scopeObject.data())); - } - 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(); - if (scopeObject) - engine->popContext(); -} - -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) -{ -} - -void ExpressionEvalJob::handleResult(QV4::ScopedValue &value) -{ - if (hasExeption()) - exception = value->toQStringNoThrow(); - result = collector->lookupRef(collector->collect(value)); - collectedRefs = collector->flushCollectedRefs(); -} - -const QString &ExpressionEvalJob::exceptionMessage() const -{ - return exception; -} - -const QJsonObject &ExpressionEvalJob::returnValue() const -{ - return result; -} - -const QJsonArray &ExpressionEvalJob::refs() const -{ - return collectedRefs; -} - -GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine) - : engine(engine) -{} - -void GatherSourcesJob::run() -{ - foreach (QV4::CompiledData::CompilationUnit *unit, engine->compilationUnits) { - QString fileName = unit->fileName(); - if (!fileName.isEmpty()) - sources.append(fileName); - } -} - -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) - , exception(QV4DataCollector::s_invalidRef) -{} - -void ExceptionCollectJob::run() -{ - QV4::Scope scope(engine); - QV4::ScopedValue v(scope, *engine->exceptionValue); - exception = collector->collect(v); -} - -QV4DataCollector::Ref ExceptionCollectJob::exceptionValue() const -{ - return exception; -} - QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h index d1ff98f9b0..e57747fbc1 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h @@ -34,7 +34,6 @@ #ifndef QV4DATACOLLECTOR_H #define QV4DATACOLLECTOR_H -#include "qv4debugger.h" #include <private/qv4engine_p.h> #include <private/qv4persistent_p.h> @@ -43,6 +42,7 @@ QT_BEGIN_NAMESPACE +class QV4Debugger; class QV4DataCollector { public: @@ -86,103 +86,6 @@ private: SpecialRefs m_specialRefs; }; -class ValueLookupJob: public QV4Debugger::Job -{ - QV4DataCollector *collector; - const QJsonArray handles; - QJsonObject result; - QJsonArray collectedRefs; - QString exception; - -public: - ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector) : - collector(collector), handles(handles) {} - void run(); - const QString &exceptionMessage() const; - const QJsonObject &returnValue() const; - const QJsonArray &refs() const; -}; - -class ExpressionEvalJob: public QV4Debugger::JavaScriptJob -{ - QV4DataCollector *collector; - QString exception; - QJsonObject result; - QJsonArray collectedRefs; - -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; -}; - -class GatherSourcesJob: public QV4Debugger::Job -{ - QV4::ExecutionEngine *engine; - QStringList sources; - -public: - GatherSourcesJob(QV4::ExecutionEngine *engine); - void run(); - const QStringList &result() const; -}; - -class ArgumentCollectJob: public QV4Debugger::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 QV4Debugger::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 QV4Debugger::Job -{ - QV4::ExecutionEngine *engine; - QV4DataCollector *collector; - int frameNr; - QV4DataCollector::Ref thisRef; - -public: - ThisCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, int frameNr); - void run(); - QV4DataCollector::Ref foundRef() const; -}; - -class ExceptionCollectJob: public QV4Debugger::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 #endif // QV4DATACOLLECTOR_H diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp index b7c310edd8..6ff3b81b4b 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp @@ -32,6 +32,7 @@ ****************************************************************************/ #include "qv4debugger.h" +#include "qv4debugjob.h" #include "qv4datacollector.h" #include <private/qv4scopedvalue_p.h> @@ -56,97 +57,6 @@ inline bool operator==(const QV4Debugger::BreakPoint &a, return a.lineNumber == b.lineNumber && a.fileName == b.fileName; } -QV4Debugger::JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, - const QString &script) - : engine(engine) - , frameNr(frameNr) - , script(script) - , resultIsException(false) -{} - -void QV4Debugger::JavaScriptJob::run() -{ - QV4::Scope scope(engine); - - QV4::ExecutionContextSaver saver(scope); - - QV4::ExecutionContext *ctx = engine->currentContext; - QObject scopeObject; - if (frameNr < 0) { // Use QML context if available - QQmlEngine *qmlEngine = engine->qmlEngine(); - if (qmlEngine) { - QQmlContext *qmlRootContext = qmlEngine->rootContext(); - QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(qmlRootContext); - - QV4::ScopedObject withContext(scope, engine->newObject()); - for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) { - QObject *object = ctxtPriv->instances.at(ii); - if (QQmlContext *context = qmlContext(object)) { - if (QQmlContextData *cdata = QQmlContextData::get(context)) { - QV4::ScopedValue v(scope, QV4::QObjectWrapper::wrap(engine, object)); - withContext->put(engine, cdata->findObjectId(object), v); - } - } - } - if (!engine->qmlContext()) { - engine->pushContext(ctx->newQmlContext(QQmlContextData::get(qmlRootContext), - &scopeObject)); - ctx = engine->currentContext; - } - engine->pushContext(ctx->newWithContext(withContext->toObject(engine))); - ctx = engine->currentContext; - } - } else { - if (frameNr > 0) { - for (int i = 0; i < frameNr; ++i) { - ctx = engine->parentContext(ctx); - } - engine->pushContext(ctx); - } - } - - QV4::Script script(ctx, this->script); - script.strictMode = ctx->d()->strictMode; - // In order for property lookups in QML to work, we need to disable fast v4 lookups. That - // is a side-effect of inheritContext. - script.inheritContext = true; - script.parse(); - QV4::ScopedValue result(scope); - if (!scope.engine->hasException) - result = script.run(); - if (scope.engine->hasException) { - result = scope.engine->catchException(); - resultIsException = true; - } - handleResult(result); -} - -bool QV4Debugger::JavaScriptJob::hasExeption() const -{ - return resultIsException; -} - -class EvalJob: public QV4Debugger::JavaScriptJob -{ - bool result; - -public: - EvalJob(QV4::ExecutionEngine *engine, const QString &script) - : QV4Debugger::JavaScriptJob(engine, /*frameNr*/-1, script) - , result(false) - {} - - virtual void handleResult(QV4::ScopedValue &result) - { - this->result = result->toBoolean(); - } - - bool resultAsBoolean() const - { - return result; - } -}; - QV4Debugger::QV4Debugger(QV4::ExecutionEngine *engine) : m_engine(engine) , m_state(Running) @@ -157,7 +67,7 @@ QV4Debugger::QV4Debugger(QV4::ExecutionEngine *engine) , m_returnedValue(engine, QV4::Primitive::undefinedValue()) , m_gatherSources(0) , m_runningJob(0) - , m_collector(new QV4DataCollector(engine)) + , m_collector(engine) { static int debuggerId = qRegisterMetaType<QV4Debugger*>(); static int pauseReasonId = qRegisterMetaType<QV4Debugger::PauseReason>(); @@ -165,19 +75,19 @@ QV4Debugger::QV4Debugger(QV4::ExecutionEngine *engine) Q_UNUSED(pauseReasonId); } -QV4Debugger::~QV4Debugger() +QV4::ExecutionEngine *QV4Debugger::engine() const { - delete m_collector; + return m_engine; } -QV4::ExecutionEngine *QV4Debugger::engine() const +const QV4DataCollector *QV4Debugger::collector() const { - return m_engine; + return &m_collector; } -QV4DataCollector *QV4Debugger::collector() const +QV4DataCollector *QV4Debugger::collector() { - return m_collector; + return &m_collector; } void QV4Debugger::pause() @@ -389,13 +299,13 @@ bool QV4Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr) return evilJob.resultAsBoolean(); } -void QV4Debugger::runInEngine(QV4Debugger::Job *job) +void QV4Debugger::runInEngine(QV4DebugJob *job) { QMutexLocker locker(&m_lock); runInEngine_havingLock(job); } -void QV4Debugger::runInEngine_havingLock(QV4Debugger::Job *job) +void QV4Debugger::runInEngine_havingLock(QV4DebugJob *job) { Q_ASSERT(job); Q_ASSERT(m_runningJob == 0); @@ -409,8 +319,4 @@ void QV4Debugger::runInEngine_havingLock(QV4Debugger::Job *job) m_runningJob = 0; } -QV4Debugger::Job::~Job() -{ -} - QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h index abb43f82f3..98224d5075 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h @@ -45,6 +45,7 @@ // We mean it. // +#include "qv4datacollector.h" #include <private/qv4debugging_p.h> #include <private/qv4function_p.h> #include <private/qv4context_p.h> @@ -55,6 +56,7 @@ QT_BEGIN_NAMESPACE +class QV4DebugJob; class QV4DataCollector; class QV4Debugger : public QV4::Debugging::Debugger { @@ -66,29 +68,6 @@ public: int lineNumber; }; - class Job - { - public: - virtual ~Job(); - virtual void run() = 0; - }; - - class JavaScriptJob: public Job - { - QV4::ExecutionEngine *engine; - int frameNr; - const QString &script; - bool resultIsException; - - public: - JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, const QString &script); - void run(); - bool hasExeption() const; - - protected: - virtual void handleResult(QV4::ScopedValue &result) = 0; - }; - enum State { Running, Paused @@ -111,10 +90,10 @@ public: }; QV4Debugger(QV4::ExecutionEngine *engine); - ~QV4Debugger(); QV4::ExecutionEngine *engine() const; - QV4DataCollector *collector() const; + const QV4DataCollector *collector() const; + QV4DataCollector *collector(); void pause(); void resume(Speed speed); @@ -141,7 +120,7 @@ public: QVector<QV4::Heap::ExecutionContext::ContextType> getScopeTypes(int frame = 0) const; QV4::Function *getFunction() const; - void runInEngine(Job *job); + void runInEngine(QV4DebugJob *job); // compile-time interface void maybeBreakAtInstruction() Q_DECL_OVERRIDE; @@ -163,7 +142,7 @@ private: // requires lock to be held void pauseAndWait(PauseReason reason); bool reallyHitTheBreakPoint(const QString &filename, int linenr); - void runInEngine_havingLock(QV4Debugger::Job *job); + void runInEngine_havingLock(QV4DebugJob *job); QV4::ExecutionEngine *m_engine; QV4::PersistentValue m_currentContext; @@ -178,9 +157,9 @@ private: QHash<BreakPoint, QString> m_breakPoints; QV4::PersistentValue m_returnedValue; - Job *m_gatherSources; - Job *m_runningJob; - QV4DataCollector *m_collector; + QV4DebugJob *m_gatherSources; + QV4DebugJob *m_runningJob; + QV4DataCollector m_collector; QWaitCondition m_jobIsRunning; }; diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp new file mode 100644 index 0000000000..572ea805a5 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp @@ -0,0 +1,332 @@ +/**************************************************************************** +** +** 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 "qv4debugjob.h" + +#include <private/qv4script_p.h> +#include <private/qqmlcontext_p.h> +#include <private/qv4qobjectwrapper_p.h> + +#include <QtQml/qqmlengine.h> + +QT_BEGIN_NAMESPACE + +QV4DebugJob::~QV4DebugJob() +{ +} + +JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, + const QString &script) : + engine(engine), frameNr(frameNr), script(script), resultIsException(false) +{} + +void JavaScriptJob::run() +{ + QV4::Scope scope(engine); + + QV4::ExecutionContextSaver saver(scope); + + QV4::ExecutionContext *ctx = engine->currentContext; + QObject scopeObject; + if (frameNr < 0) { // Use QML context if available + QQmlEngine *qmlEngine = engine->qmlEngine(); + if (qmlEngine) { + QQmlContext *qmlRootContext = qmlEngine->rootContext(); + QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(qmlRootContext); + + QV4::ScopedObject withContext(scope, engine->newObject()); + for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) { + QObject *object = ctxtPriv->instances.at(ii); + if (QQmlContext *context = qmlContext(object)) { + if (QQmlContextData *cdata = QQmlContextData::get(context)) { + QV4::ScopedValue v(scope, QV4::QObjectWrapper::wrap(engine, object)); + withContext->put(engine, cdata->findObjectId(object), v); + } + } + } + if (!engine->qmlContext()) { + engine->pushContext(ctx->newQmlContext(QQmlContextData::get(qmlRootContext), + &scopeObject)); + ctx = engine->currentContext; + } + engine->pushContext(ctx->newWithContext(withContext->toObject(engine))); + ctx = engine->currentContext; + } + } else { + if (frameNr > 0) { + for (int i = 0; i < frameNr; ++i) { + ctx = engine->parentContext(ctx); + } + engine->pushContext(ctx); + } + } + + QV4::Script script(ctx, this->script); + script.strictMode = ctx->d()->strictMode; + // In order for property lookups in QML to work, we need to disable fast v4 lookups. That + // is a side-effect of inheritContext. + script.inheritContext = true; + script.parse(); + QV4::ScopedValue result(scope); + if (!scope.engine->hasException) + result = script.run(); + if (scope.engine->hasException) { + result = scope.engine->catchException(); + resultIsException = true; + } + handleResult(result); +} + +bool JavaScriptJob::hasExeption() const +{ + return resultIsException; +} + +ValueLookupJob::ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector) : + collector(collector), handles(handles) {} + +void ValueLookupJob::run() +{ + // Open a QML context if we don't have one, yet. We might run into QML objects when looking up + // refs and that will crash without a valid QML context. Mind that engine->qmlContext() is only + // set if the engine is currently executing QML code. + QScopedPointer<QObject> scopeObject; + QV4::ExecutionEngine *engine = collector->engine(); + if (engine->qmlEngine() && !engine->qmlContext()) { + scopeObject.reset(new QObject); + engine->pushContext(engine->currentContext->newQmlContext( + QQmlContextData::get(engine->qmlEngine()->rootContext()), + scopeObject.data())); + } + 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(); + if (scopeObject) + engine->popContext(); +} + +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) +{ +} + +void ExpressionEvalJob::handleResult(QV4::ScopedValue &value) +{ + if (hasExeption()) + exception = value->toQStringNoThrow(); + result = collector->lookupRef(collector->collect(value)); + collectedRefs = collector->flushCollectedRefs(); +} + +const QString &ExpressionEvalJob::exceptionMessage() const +{ + return exception; +} + +const QJsonObject &ExpressionEvalJob::returnValue() const +{ + return result; +} + +const QJsonArray &ExpressionEvalJob::refs() const +{ + return collectedRefs; +} + +GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine) + : engine(engine) +{} + +void GatherSourcesJob::run() +{ + foreach (QV4::CompiledData::CompilationUnit *unit, engine->compilationUnits) { + QString fileName = unit->fileName(); + if (!fileName.isEmpty()) + sources.append(fileName); + } +} + +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) + , exception(QV4DataCollector::s_invalidRef) +{} + +void ExceptionCollectJob::run() +{ + QV4::Scope scope(engine); + QV4::ScopedValue v(scope, *engine->exceptionValue); + exception = collector->collect(v); +} + +QV4DataCollector::Ref ExceptionCollectJob::exceptionValue() const +{ + return exception; +} + +EvalJob::EvalJob(QV4::ExecutionEngine *engine, const QString &script) : + JavaScriptJob(engine, /*frameNr*/-1, script), result(false) +{} + +void EvalJob::handleResult(QV4::ScopedValue &result) +{ + this->result = result->toBoolean(); +} + +bool EvalJob::resultAsBoolean() const +{ + return result; +} + +QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h new file mode 100644 index 0000000000..b758868ace --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** 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 QV4DEBUGJOB_H +#define QV4DEBUGJOB_H + +#include "qv4datacollector.h" +#include <private/qv4engine_p.h> + +#include <QtCore/qjsonarray.h> +#include <QtCore/qjsonobject.h> + +QT_BEGIN_NAMESPACE + +class QV4DataCollector; +class QV4DebugJob +{ +public: + virtual ~QV4DebugJob(); + virtual void run() = 0; +}; + +class JavaScriptJob : public QV4DebugJob +{ + QV4::ExecutionEngine *engine; + int frameNr; + const QString &script; + bool resultIsException; + +public: + JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, const QString &script); + void run(); + bool hasExeption() const; + +protected: + virtual void handleResult(QV4::ScopedValue &result) = 0; +}; + +class ValueLookupJob: public QV4DebugJob +{ + QV4DataCollector *collector; + const QJsonArray handles; + QJsonObject result; + QJsonArray collectedRefs; + QString exception; + +public: + ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector); + void run(); + const QString &exceptionMessage() const; + const QJsonObject &returnValue() const; + const QJsonArray &refs() const; +}; + +class ExpressionEvalJob: public JavaScriptJob +{ + QV4DataCollector *collector; + QString exception; + QJsonObject result; + QJsonArray collectedRefs; + +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; +}; + +class GatherSourcesJob: public QV4DebugJob +{ + QV4::ExecutionEngine *engine; + QStringList sources; + +public: + GatherSourcesJob(QV4::ExecutionEngine *engine); + void run(); + const QStringList &result() const; +}; + +class ArgumentCollectJob: public QV4DebugJob +{ + 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 QV4DebugJob +{ + 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 QV4DebugJob +{ + QV4::ExecutionEngine *engine; + QV4DataCollector *collector; + int frameNr; + QV4DataCollector::Ref thisRef; + +public: + ThisCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, int frameNr); + void run(); + QV4DataCollector::Ref foundRef() const; +}; + +class ExceptionCollectJob: public QV4DebugJob +{ + QV4::ExecutionEngine *engine; + QV4DataCollector *collector; + QV4DataCollector::Ref exception; + +public: + ExceptionCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector); + void run(); + QV4DataCollector::Ref exceptionValue() const; +}; + +class EvalJob: public JavaScriptJob +{ + bool result; + +public: + EvalJob(QV4::ExecutionEngine *engine, const QString &script); + + virtual void handleResult(QV4::ScopedValue &result); + bool resultAsBoolean() const +; +}; + +QT_END_NAMESPACE + +#endif // QV4DEBUGJOB_H + diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp index dcf1fe8335..1c1e9e48df 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp @@ -32,6 +32,7 @@ ****************************************************************************/ #include "qv4debugservice.h" +#include "qv4debugjob.h" #include "qqmlengine.h" #include "qqmldebugpacket.h" diff --git a/tests/auto/qml/debugger/qv4debugger/qv4debugger.pro b/tests/auto/qml/debugger/qv4debugger/qv4debugger.pro index d11de56e43..e25b4260e5 100644 --- a/tests/auto/qml/debugger/qv4debugger/qv4debugger.pro +++ b/tests/auto/qml/debugger/qv4debugger/qv4debugger.pro @@ -5,11 +5,13 @@ osx:CONFIG -= app_bundle SOURCES += \ $$PWD/tst_qv4debugger.cpp \ $$PWD/../../../../../src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp \ - $$PWD/../../../../../src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp + $$PWD/../../../../../src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp \ + $$PWD/../../../../../src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp HEADERS += \ $$PWD/../../../../../src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h \ - $$PWD/../../../../../src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h + $$PWD/../../../../../src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h \ + $$PWD/../../../../../src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h INCLUDEPATH += \ $$PWD/../../../../../src/plugins/qmltooling/qmldbg_debugger diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp index 70883047c8..c676e5422a 100644 --- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp @@ -34,6 +34,7 @@ #include "qv4datacollector.h" #include "qv4debugger.h" +#include "qv4debugjob.h" #include <QJSEngine> #include <QQmlEngine> |