aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@theqtcompany.com>2015-12-15 13:38:46 +0100
committerUlf Hermann <ulf.hermann@theqtcompany.com>2016-01-11 09:46:41 +0000
commitdd37ea85809db58abd3b45d3f55020b240baca28 (patch)
tree44904021f37320ac7eb92a30d0b98a23e55aa325 /src/plugins
parentb6ca444408e351d1ddcaddc66071c27aa011ea6b (diff)
V4 Debugger: Move all the jobs into one place
This makes the code more readable and allows us to keep the data collector as value, rather than pointer, in QV4Debugger. Change-Id: I2939c2b2f551111139f1dc34704a6029e87a66bf Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro7
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp204
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h99
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp114
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h39
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp332
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h180
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp1
8 files changed, 539 insertions, 437 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"