aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@theqtcompany.com>2015-10-22 17:11:36 +0200
committerSimon Hausmann <simon.hausmann@theqtcompany.com>2015-10-30 19:05:00 +0000
commite1db5c660734bd8d43675469ce828944347e739b (patch)
tree8d48054be6fbcbe908b0f8dc1902301ef1c30611
parentbe804f641f53305bb294205896a6cfa0cc080d19 (diff)
Move V4 debugger and its test into better places
Now that we have an abstract base class we don't need to carry the V4 debugger in QtQml anymore. The test clearly belongs into the debugger category. Change-Id: I0f71bdb331da8a568e43600363a0468299aa1a87 Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro3
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp7
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h18
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp358
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h183
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp58
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h16
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp38
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h5
-rw-r--r--src/qml/jsruntime/qv4debugging.cpp286
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h158
-rw-r--r--tests/auto/qml/debugger/debugger.pro3
-rw-r--r--tests/auto/qml/debugger/qv4debugger/qv4debugger.pro17
-rw-r--r--tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp (renamed from tests/auto/qml/qv4debugger/tst_qv4debugger.cpp)50
-rw-r--r--tests/auto/qml/qml.pro1
-rw-r--r--tests/auto/qml/qv4debugger/qv4debugger.pro15
16 files changed, 658 insertions, 558 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro
index 8d1a54e9e4..b0678ef2d9 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro
+++ b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro
@@ -12,9 +12,11 @@ SOURCES += \
$$PWD/qqmlnativedebugservice.cpp \
$$PWD/qqmlwatcher.cpp \
$$PWD/qv4debugservice.cpp \
+ $$PWD/qv4debugger.cpp \
$$PWD/qv4debuggeragent.cpp \
$$PWD/qv4datacollector.cpp
+
HEADERS += \
$$PWD/../shared/qqmlconfigurabledebugservice.h \
$$PWD/qdebugmessageservice.h \
@@ -23,6 +25,7 @@ HEADERS += \
$$PWD/qqmlnativedebugservice.h \
$$PWD/qqmlwatcher.h \
$$PWD/qv4debugservice.h \
+ $$PWD/qv4debugger.h \
$$PWD/qv4debuggeragent.h \
$$PWD/qv4datacollector.h
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
index 377f0845d0..e3347be14c 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
@@ -40,6 +40,7 @@
#include <private/qv4runtime_p.h>
#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsonobject.h>
QT_BEGIN_NAMESPACE
@@ -208,13 +209,13 @@ QV4DataCollector::Ref QV4DataCollector::addScriptRef(const QString &scriptName)
return ref;
}
-void QV4DataCollector::collectScope(QJsonObject *dict, QV4::Debugging::V4Debugger *debugger,
- int frameNr, int scopeNr)
+void QV4DataCollector::collectScope(QJsonObject *dict, QV4Debugger *debugger, int frameNr,
+ int scopeNr)
{
QStringList names;
Refs refs;
- if (debugger->state() == QV4::Debugging::V4Debugger::Paused) {
+ if (debugger->state() == QV4Debugger::Paused) {
RefHolder holder(this, &refs);
ArgumentCollectJob argumentsJob(m_engine, this, &names, frameNr, scopeNr);
debugger->runInEngine(&argumentsJob);
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
index 0ea40f896c..bfa3bd2fe1 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
@@ -34,8 +34,9 @@
#ifndef QV4DATACOLLECTOR_H
#define QV4DATACOLLECTOR_H
+#include "qv4debugger.h"
#include <private/qv4engine_p.h>
-#include <private/qv4debugging_p.h>
+#include <private/qv4persistent_p.h>
QT_BEGIN_NAMESPACE
@@ -60,8 +61,7 @@ public:
Ref addFunctionRef(const QString &functionName);
Ref addScriptRef(const QString &scriptName);
- void collectScope(QJsonObject *dict, QV4::Debugging::V4Debugger *debugger, int frameNr,
- int scopeNr);
+ void collectScope(QJsonObject *dict, QV4Debugger *debugger, int frameNr, int scopeNr);
QV4::ExecutionEngine *engine() const { return m_engine; }
@@ -101,7 +101,7 @@ private:
QV4DataCollector::Refs *m_previousRefs;
};
-class ExpressionEvalJob: public QV4::Debugging::V4Debugger::JavaScriptJob
+class ExpressionEvalJob: public QV4Debugger::JavaScriptJob
{
QV4DataCollector *collector;
QString exception;
@@ -113,7 +113,7 @@ public:
const QString &exceptionMessage() const;
};
-class GatherSourcesJob: public QV4::Debugging::V4Debugger::Job
+class GatherSourcesJob: public QV4Debugger::Job
{
QV4::ExecutionEngine *engine;
QStringList sources;
@@ -124,7 +124,7 @@ public:
const QStringList &result() const;
};
-class ArgumentCollectJob: public QV4::Debugging::V4Debugger::Job
+class ArgumentCollectJob: public QV4Debugger::Job
{
QV4::ExecutionEngine *engine;
QV4DataCollector *collector;
@@ -138,7 +138,7 @@ public:
void run();
};
-class LocalCollectJob: public QV4::Debugging::V4Debugger::Job
+class LocalCollectJob: public QV4Debugger::Job
{
QV4::ExecutionEngine *engine;
QV4DataCollector *collector;
@@ -152,7 +152,7 @@ public:
void run();
};
-class ThisCollectJob: public QV4::Debugging::V4Debugger::Job
+class ThisCollectJob: public QV4Debugger::Job
{
QV4::ExecutionEngine *engine;
QV4DataCollector *collector;
@@ -166,7 +166,7 @@ public:
bool myRun();
};
-class ExceptionCollectJob: public QV4::Debugging::V4Debugger::Job
+class ExceptionCollectJob: public QV4Debugger::Job
{
QV4::ExecutionEngine *engine;
QV4DataCollector *collector;
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp
new file mode 100644
index 0000000000..6198e2c039
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp
@@ -0,0 +1,358 @@
+/****************************************************************************
+**
+** 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 "qv4debugger.h"
+
+#include <private/qv4scopedvalue_p.h>
+#include <private/qv4script_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QV4Debugger::BreakPoint::BreakPoint(const QString &fileName, int line)
+ : fileName(fileName), lineNumber(line)
+{}
+
+inline uint qHash(const QV4Debugger::BreakPoint &b, uint seed = 0) Q_DECL_NOTHROW
+{
+ return qHash(b.fileName, seed) ^ b.lineNumber;
+}
+
+inline bool operator==(const QV4Debugger::BreakPoint &a,
+ const QV4Debugger::BreakPoint &b)
+{
+ 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;
+ 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)
+ , m_stepping(NotStepping)
+ , m_pauseRequested(false)
+ , m_haveBreakPoints(false)
+ , m_breakOnThrow(false)
+ , m_returnedValue(engine, QV4::Primitive::undefinedValue())
+ , m_gatherSources(0)
+ , m_runningJob(0)
+{
+ static int debuggerId = qRegisterMetaType<QV4Debugger*>();
+ static int pauseReasonId = qRegisterMetaType<QV4Debugger::PauseReason>();
+ Q_UNUSED(debuggerId);
+ Q_UNUSED(pauseReasonId);
+}
+
+QV4::ExecutionEngine *QV4Debugger::engine() const
+{
+ return m_engine;
+}
+
+void QV4Debugger::pause()
+{
+ QMutexLocker locker(&m_lock);
+ if (m_state == Paused)
+ return;
+ m_pauseRequested = true;
+}
+
+void QV4Debugger::resume(Speed speed)
+{
+ QMutexLocker locker(&m_lock);
+ if (m_state != Paused)
+ return;
+
+ if (!m_returnedValue.isUndefined())
+ m_returnedValue.set(m_engine, QV4::Encode::undefined());
+
+ m_currentContext.set(m_engine, *m_engine->currentContext);
+ m_stepping = speed;
+ m_runningCondition.wakeAll();
+}
+
+QV4Debugger::State QV4Debugger::state() const
+{
+ return m_state;
+}
+
+void QV4Debugger::addBreakPoint(const QString &fileName, int lineNumber, const QString &condition)
+{
+ QMutexLocker locker(&m_lock);
+ m_breakPoints.insert(BreakPoint(fileName.mid(fileName.lastIndexOf('/') + 1),
+ lineNumber), condition);
+ m_haveBreakPoints = true;
+}
+
+void QV4Debugger::removeBreakPoint(const QString &fileName, int lineNumber)
+{
+ QMutexLocker locker(&m_lock);
+ m_breakPoints.remove(BreakPoint(fileName.mid(fileName.lastIndexOf('/') + 1),
+ lineNumber));
+ m_haveBreakPoints = !m_breakPoints.isEmpty();
+}
+
+void QV4Debugger::setBreakOnThrow(bool onoff)
+{
+ QMutexLocker locker(&m_lock);
+
+ m_breakOnThrow = onoff;
+}
+
+QV4Debugger::ExecutionState QV4Debugger::currentExecutionState() const
+{
+ ExecutionState state;
+ state.fileName = getFunction()->sourceFile();
+ state.lineNumber = engine()->current->lineNumber;
+
+ return state;
+}
+
+bool QV4Debugger::pauseAtNextOpportunity() const {
+ return m_pauseRequested || m_haveBreakPoints || m_gatherSources || m_stepping >= StepOver;
+}
+
+QVector<QV4::StackFrame> QV4Debugger::stackTrace(int frameLimit) const
+{
+ return m_engine->stackTrace(frameLimit);
+}
+
+void QV4Debugger::maybeBreakAtInstruction()
+{
+ if (m_runningJob) // do not re-enter when we're doing a job for the debugger.
+ return;
+
+ QMutexLocker locker(&m_lock);
+
+ if (m_gatherSources) {
+ m_gatherSources->run();
+ delete m_gatherSources;
+ m_gatherSources = 0;
+ }
+
+ switch (m_stepping) {
+ case StepOver:
+ if (m_currentContext.asManaged()->d() != m_engine->current)
+ break;
+ // fall through
+ case StepIn:
+ pauseAndWait(Step);
+ return;
+ case StepOut:
+ case NotStepping:
+ break;
+ }
+
+ if (m_pauseRequested) { // Serve debugging requests from the agent
+ m_pauseRequested = false;
+ pauseAndWait(PauseRequest);
+ } else if (m_haveBreakPoints) {
+ if (QV4::Function *f = getFunction()) {
+ const int lineNumber = engine()->current->lineNumber;
+ if (reallyHitTheBreakPoint(f->sourceFile(), lineNumber))
+ pauseAndWait(BreakPointHit);
+ }
+ }
+}
+
+void QV4Debugger::enteringFunction()
+{
+ if (m_runningJob)
+ return;
+ QMutexLocker locker(&m_lock);
+
+ if (m_stepping == StepIn) {
+ m_currentContext.set(m_engine, *m_engine->currentContext);
+ }
+}
+
+void QV4Debugger::leavingFunction(const QV4::ReturnedValue &retVal)
+{
+ if (m_runningJob)
+ return;
+ Q_UNUSED(retVal); // TODO
+
+ QMutexLocker locker(&m_lock);
+
+ if (m_stepping != NotStepping && m_currentContext.asManaged()->d() == m_engine->current) {
+ m_currentContext.set(m_engine, *m_engine->parentContext(m_engine->currentContext));
+ m_stepping = StepOver;
+ m_returnedValue.set(m_engine, retVal);
+ }
+}
+
+void QV4Debugger::aboutToThrow()
+{
+ if (!m_breakOnThrow)
+ return;
+
+ if (m_runningJob) // do not re-enter when we're doing a job for the debugger.
+ return;
+
+ QMutexLocker locker(&m_lock);
+ pauseAndWait(Throwing);
+}
+
+QV4::Function *QV4Debugger::getFunction() const
+{
+ QV4::Scope scope(m_engine);
+ QV4::ExecutionContext *context = m_engine->currentContext;
+ QV4::ScopedFunctionObject function(scope, context->getFunctionObject());
+ if (function)
+ return function->function();
+ else
+ return context->d()->engine->globalCode;
+}
+
+void QV4Debugger::pauseAndWait(PauseReason reason)
+{
+ if (m_runningJob)
+ return;
+
+ m_state = Paused;
+ emit debuggerPaused(this, reason);
+
+ while (true) {
+ m_runningCondition.wait(&m_lock);
+ if (m_runningJob) {
+ m_runningJob->run();
+ m_jobIsRunning.wakeAll();
+ } else {
+ break;
+ }
+ }
+
+ m_state = Running;
+}
+
+bool QV4Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr)
+{
+ QHash<BreakPoint, QString>::iterator it = m_breakPoints.find(
+ BreakPoint(filename.mid(filename.lastIndexOf('/') + 1), linenr));
+ if (it == m_breakPoints.end())
+ return false;
+ QString condition = it.value();
+ if (condition.isEmpty())
+ return true;
+
+ Q_ASSERT(m_runningJob == 0);
+ EvalJob evilJob(m_engine, condition);
+ m_runningJob = &evilJob;
+ m_runningJob->run();
+ m_runningJob = 0;
+
+ return evilJob.resultAsBoolean();
+}
+
+void QV4Debugger::runInEngine(QV4Debugger::Job *job)
+{
+ QMutexLocker locker(&m_lock);
+ runInEngine_havingLock(job);
+}
+
+void QV4Debugger::runInEngine_havingLock(QV4Debugger::Job *job)
+{
+ Q_ASSERT(job);
+ Q_ASSERT(m_runningJob == 0);
+
+ m_runningJob = job;
+ m_runningCondition.wakeAll();
+ m_jobIsRunning.wait(&m_lock);
+ 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
new file mode 100644
index 0000000000..adc58141d0
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** 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 QV4DEBUGGER_H
+#define QV4DEBUGGER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qv4debugging_p.h>
+#include <private/qv4function_p.h>
+#include <private/qv4context_p.h>
+#include <private/qv4persistent_p.h>
+
+#include <QtCore/qmutex.h>
+#include <QtCore/qwaitcondition.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV4Debugger : public QV4::Debugging::Debugger
+{
+ Q_OBJECT
+public:
+ struct BreakPoint {
+ BreakPoint(const QString &fileName, int line);
+ QString fileName;
+ 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
+ };
+
+ enum Speed {
+ FullThrottle = 0,
+ StepOut,
+ StepOver,
+ StepIn,
+
+ NotStepping = FullThrottle
+ };
+
+ enum PauseReason {
+ PauseRequest,
+ BreakPointHit,
+ Throwing,
+ Step
+ };
+
+ QV4Debugger(QV4::ExecutionEngine *engine);
+
+ QV4::ExecutionEngine *engine() const;
+
+ void pause();
+ void resume(Speed speed);
+
+ State state() const;
+
+ void addBreakPoint(const QString &fileName, int lineNumber,
+ const QString &condition = QString());
+ void removeBreakPoint(const QString &fileName, int lineNumber);
+
+ void setBreakOnThrow(bool onoff);
+
+ // used for testing
+ struct ExecutionState
+ {
+ QString fileName;
+ int lineNumber;
+ };
+ ExecutionState currentExecutionState() const;
+
+ QVector<QV4::StackFrame> stackTrace(int frameLimit = -1) const;
+ QVector<QV4::Heap::ExecutionContext::ContextType> getScopeTypes(int frame = 0) const;
+
+ QV4::Function *getFunction() const;
+ void runInEngine(Job *job);
+
+ // compile-time interface
+ void maybeBreakAtInstruction() Q_DECL_OVERRIDE;
+
+ // execution hooks
+ void enteringFunction() Q_DECL_OVERRIDE;
+ void leavingFunction(const QV4::ReturnedValue &retVal) Q_DECL_OVERRIDE;
+ void aboutToThrow() Q_DECL_OVERRIDE;
+
+ bool pauseAtNextOpportunity() const Q_DECL_OVERRIDE;
+
+signals:
+ void debuggerPaused(QV4Debugger *self, QV4Debugger::PauseReason reason);
+
+private:
+ // requires lock to be held
+ void pauseAndWait(PauseReason reason);
+ bool reallyHitTheBreakPoint(const QString &filename, int linenr);
+ void runInEngine_havingLock(QV4Debugger::Job *job);
+
+ QV4::ExecutionEngine *m_engine;
+ QV4::PersistentValue m_currentContext;
+ QMutex m_lock;
+ QWaitCondition m_runningCondition;
+ State m_state;
+ Speed m_stepping;
+ bool m_pauseRequested;
+ bool m_haveBreakPoints;
+ bool m_breakOnThrow;
+
+ QHash<BreakPoint, QString> m_breakPoints;
+ QV4::PersistentValue m_returnedValue;
+
+ Job *m_gatherSources;
+ Job *m_runningJob;
+ QWaitCondition m_jobIsRunning;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QV4Debugger::PauseReason)
+Q_DECLARE_METATYPE(QV4Debugger*)
+
+#endif // QV4DEBUGGER_H
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp
index dcb40dd548..da43257b24 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp
@@ -44,7 +44,7 @@ QV4DebuggerAgent::QV4DebuggerAgent(QV4DebugServiceImpl *debugService)
: m_breakOnThrow(false), m_debugService(debugService)
{}
-QV4::Debugging::V4Debugger *QV4DebuggerAgent::firstDebugger() const
+QV4Debugger *QV4DebuggerAgent::firstDebugger() const
{
// Currently only 1 single engine is supported, so:
if (m_debuggers.isEmpty())
@@ -56,14 +56,13 @@ QV4::Debugging::V4Debugger *QV4DebuggerAgent::firstDebugger() const
bool QV4DebuggerAgent::isRunning() const
{
// Currently only 1 single engine is supported, so:
- if (QV4::Debugging::V4Debugger *debugger = firstDebugger())
- return debugger->state() == QV4::Debugging::V4Debugger::Running;
+ if (QV4Debugger *debugger = firstDebugger())
+ return debugger->state() == QV4Debugger::Running;
else
return false;
}
-void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::V4Debugger *debugger,
- QV4::Debugging::PauseReason reason)
+void QV4DebuggerAgent::debuggerPaused(QV4Debugger *debugger, QV4Debugger::PauseReason reason)
{
Q_UNUSED(reason);
@@ -73,9 +72,9 @@ void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::V4Debugger *debugger,
event.insert(QStringLiteral("type"), QStringLiteral("event"));
switch (reason) {
- case QV4::Debugging::Step:
- case QV4::Debugging::PauseRequest:
- case QV4::Debugging::BreakPoint: {
+ case QV4Debugger::Step:
+ case QV4Debugger::PauseRequest:
+ case QV4Debugger::BreakPointHit: {
event.insert(QStringLiteral("event"), QStringLiteral("break"));
QVector<QV4::StackFrame> frames = debugger->stackTrace(1);
if (frames.isEmpty())
@@ -92,7 +91,7 @@ void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::V4Debugger *debugger,
body.insert(QStringLiteral("breakpoints"), breakPoints);
script.insert(QStringLiteral("name"), topFrame.source);
} break;
- case QV4::Debugging::Throwing:
+ case QV4Debugger::Throwing:
// TODO: complete this!
event.insert(QStringLiteral("event"), QStringLiteral("exception"));
break;
@@ -105,7 +104,7 @@ void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::V4Debugger *debugger,
m_debugService->send(event);
}
-void QV4DebuggerAgent::addDebugger(QV4::Debugging::V4Debugger *debugger)
+void QV4DebuggerAgent::addDebugger(QV4Debugger *debugger)
{
Q_ASSERT(!m_debuggers.contains(debugger));
m_debuggers << debugger;
@@ -116,57 +115,50 @@ void QV4DebuggerAgent::addDebugger(QV4::Debugging::V4Debugger *debugger)
if (breakPoint.enabled)
debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition);
- connect(debugger, SIGNAL(destroyed(QObject*)),
- this, SLOT(handleDebuggerDeleted(QObject*)));
- connect(debugger,
- SIGNAL(debuggerPaused(QV4::Debugging::V4Debugger*,QV4::Debugging::PauseReason)),
- this, SLOT(debuggerPaused(QV4::Debugging::V4Debugger*,QV4::Debugging::PauseReason)),
+ connect(debugger, &QObject::destroyed, this, &QV4DebuggerAgent::handleDebuggerDeleted);
+ connect(debugger, &QV4Debugger::debuggerPaused, this, &QV4DebuggerAgent::debuggerPaused,
Qt::QueuedConnection);
}
-void QV4DebuggerAgent::removeDebugger(QV4::Debugging::V4Debugger *debugger)
+void QV4DebuggerAgent::removeDebugger(QV4Debugger *debugger)
{
m_debuggers.removeAll(debugger);
- disconnect(debugger, SIGNAL(destroyed(QObject*)),
- this, SLOT(handleDebuggerDeleted(QObject*)));
- disconnect(debugger,
- SIGNAL(debuggerPaused(QV4::Debugging::V4Debugger*,QV4::Debugging::PauseReason)),
- this,
- SLOT(debuggerPaused(QV4::Debugging::V4Debugger*,QV4::Debugging::PauseReason)));
+ disconnect(debugger, &QObject::destroyed, this, &QV4DebuggerAgent::handleDebuggerDeleted);
+ disconnect(debugger, &QV4Debugger::debuggerPaused, this, &QV4DebuggerAgent::debuggerPaused);
}
-const QList<QV4::Debugging::V4Debugger *> &QV4DebuggerAgent::debuggers()
+const QList<QV4Debugger *> &QV4DebuggerAgent::debuggers()
{
return m_debuggers;
}
void QV4DebuggerAgent::handleDebuggerDeleted(QObject *debugger)
{
- m_debuggers.removeAll(static_cast<QV4::Debugging::V4Debugger *>(debugger));
+ m_debuggers.removeAll(static_cast<QV4Debugger *>(debugger));
}
-void QV4DebuggerAgent::pause(QV4::Debugging::V4Debugger *debugger) const
+void QV4DebuggerAgent::pause(QV4Debugger *debugger) const
{
debugger->pause();
}
void QV4DebuggerAgent::pauseAll() const
{
- foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers)
+ foreach (QV4Debugger *debugger, m_debuggers)
pause(debugger);
}
void QV4DebuggerAgent::resumeAll() const
{
- foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers)
- if (debugger->state() == QV4::Debugging::V4Debugger::Paused)
- debugger->resume(QV4::Debugging::V4Debugger::FullThrottle);
+ foreach (QV4Debugger *debugger, m_debuggers)
+ if (debugger->state() == QV4Debugger::Paused)
+ debugger->resume(QV4Debugger::FullThrottle);
}
int QV4DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber, bool enabled, const QString &condition)
{
if (enabled)
- foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers)
+ foreach (QV4Debugger *debugger, m_debuggers)
debugger->addBreakPoint(fileName, lineNumber, condition);
int id = m_breakPoints.size();
@@ -183,7 +175,7 @@ void QV4DebuggerAgent::removeBreakPoint(int id)
m_breakPoints.remove(id);
if (breakPoint.enabled)
- foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers)
+ foreach (QV4Debugger *debugger, m_debuggers)
debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr);
}
@@ -201,7 +193,7 @@ void QV4DebuggerAgent::enableBreakPoint(int id, bool onoff)
return;
breakPoint.enabled = onoff;
- foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers) {
+ foreach (QV4Debugger *debugger, m_debuggers) {
if (onoff)
debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition);
else
@@ -224,7 +216,7 @@ void QV4DebuggerAgent::setBreakOnThrow(bool onoff)
{
if (onoff != m_breakOnThrow) {
m_breakOnThrow = onoff;
- foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers)
+ foreach (QV4Debugger *debugger, m_debuggers)
debugger->setBreakOnThrow(onoff);
}
}
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h
index 9f77a17b45..d133c6954b 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h
@@ -34,7 +34,7 @@
#ifndef QV4DEBUGGERAGENT_H
#define QV4DEBUGGERAGENT_H
-#include <private/qv4debugging_p.h>
+#include "qv4debugger.h"
QT_BEGIN_NAMESPACE
@@ -46,14 +46,14 @@ class QV4DebuggerAgent : public QObject
public:
QV4DebuggerAgent(QV4DebugServiceImpl *m_debugService);
- QV4::Debugging::V4Debugger *firstDebugger() const;
+ QV4Debugger *firstDebugger() const;
bool isRunning() const;
- void addDebugger(QV4::Debugging::V4Debugger *debugger);
- void removeDebugger(QV4::Debugging::V4Debugger *debugger);
- const QList<QV4::Debugging::V4Debugger *> &debuggers();
+ void addDebugger(QV4Debugger *debugger);
+ void removeDebugger(QV4Debugger *debugger);
+ const QList<QV4Debugger *> &debuggers();
- void pause(QV4::Debugging::V4Debugger *debugger) const;
+ void pause(QV4Debugger *debugger) const;
void pauseAll() const;
void resumeAll() const;
int addBreakPoint(const QString &fileName, int lineNumber, bool enabled = true, const QString &condition = QString());
@@ -66,11 +66,11 @@ public:
void setBreakOnThrow(bool onoff);
public slots:
- void debuggerPaused(QV4::Debugging::V4Debugger *debugger, QV4::Debugging::PauseReason reason);
+ void debuggerPaused(QV4Debugger *debugger, QV4Debugger::PauseReason reason);
void handleDebuggerDeleted(QObject *debugger);
private:
- QList<QV4::Debugging::V4Debugger *> m_debuggers;
+ QList<QV4Debugger *> m_debuggers;
struct BreakPoint {
QString fileName;
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
index f742502e2a..3a080be125 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
@@ -270,7 +270,7 @@ public:
int toFrame = arguments.value(QStringLiteral("toFrame")).toInt(fromFrame + 10);
// no idea what the bottom property is for, so we'll ignore it.
- QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
+ QV4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
QJsonArray frameArray;
QVector<QV4::StackFrame> frames = debugger->stackTrace(toFrame);
@@ -307,7 +307,7 @@ public:
const int frameNr = arguments.value(QStringLiteral("number")).toInt(
debugService->selectedFrame());
- QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
+ QV4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1);
if (frameNr < 0 || frameNr >= frames.size()) {
createErrorResponse(QStringLiteral("frame command has invalid frame number"));
@@ -340,7 +340,7 @@ public:
debugService->selectedFrame());
const int scopeNr = arguments.value(QStringLiteral("number")).toInt(0);
- QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
+ QV4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1);
if (frameNr < 0 || frameNr >= frames.size()) {
createErrorResponse(QStringLiteral("scope command has invalid frame number"));
@@ -398,10 +398,10 @@ public:
// decypher the payload:
QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
+ QV4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
if (arguments.empty()) {
- debugger->resume(QV4::Debugging::V4Debugger::FullThrottle);
+ debugger->resume(QV4Debugger::FullThrottle);
} else {
QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
QString stepAction = arguments.value(QStringLiteral("stepaction")).toString();
@@ -410,11 +410,11 @@ public:
qWarning() << "Step count other than 1 is not supported.";
if (stepAction == QStringLiteral("in")) {
- debugger->resume(QV4::Debugging::V4Debugger::StepIn);
+ debugger->resume(QV4Debugger::StepIn);
} else if (stepAction == QStringLiteral("out")) {
- debugger->resume(QV4::Debugging::V4Debugger::StepOut);
+ debugger->resume(QV4Debugger::StepOut);
} else if (stepAction == QStringLiteral("next")) {
- debugger->resume(QV4::Debugging::V4Debugger::StepOver);
+ debugger->resume(QV4Debugger::StepOver);
} else {
createErrorResponse(QStringLiteral("continue command has invalid stepaction"));
return;
@@ -506,7 +506,7 @@ public:
}
// do it:
- QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
+ QV4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
GatherSourcesJob job(debugger->engine());
debugger->runInEngine(&job);
@@ -561,8 +561,8 @@ public:
virtual void handleRequest()
{
- QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
- if (debugger->state() == QV4::Debugging::V4Debugger::Paused) {
+ QV4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
+ if (debugger->state() == QV4Debugger::Paused) {
QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
QString expression = arguments.value(QStringLiteral("expression")).toString();
const int frame = arguments.value(QStringLiteral("frame")).toInt(0);
@@ -634,7 +634,7 @@ void QV4DebugServiceImpl::engineAboutToBeAdded(QQmlEngine *engine)
if (QQmlDebugConnector *server = QQmlDebugConnector::instance()) {
if (ee) {
ee->iselFactory.reset(new QV4::Moth::ISelFactory);
- QV4::Debugging::V4Debugger *debugger = new QV4::Debugging::V4Debugger(ee);
+ QV4Debugger *debugger = new QV4Debugger(ee);
if (state() == Enabled)
ee->setDebugger(debugger);
debuggerAgent.addDebugger(debugger);
@@ -651,8 +651,7 @@ void QV4DebugServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine)
if (engine){
const QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle());
if (ee) {
- QV4::Debugging::V4Debugger *debugger
- = qobject_cast<QV4::Debugging::V4Debugger *>(ee->debugger);
+ QV4Debugger *debugger = qobject_cast<QV4Debugger *>(ee->debugger);
if (debugger)
debuggerAgent.removeDebugger(debugger);
}
@@ -664,7 +663,7 @@ void QV4DebugServiceImpl::stateAboutToBeChanged(State state)
{
QMutexLocker lock(&m_configMutex);
if (state == Enabled) {
- foreach (QV4::Debugging::V4Debugger *debugger, debuggerAgent.debuggers()) {
+ foreach (QV4Debugger *debugger, debuggerAgent.debuggers()) {
QV4::ExecutionEngine *ee = debugger->engine();
if (!ee->debugger)
ee->setDebugger(debugger);
@@ -787,7 +786,7 @@ void QV4DebugServiceImpl::clearHandles(QV4::ExecutionEngine *engine)
}
QJsonObject QV4DebugServiceImpl::buildFrame(const QV4::StackFrame &stackFrame, int frameNr,
- QV4::Debugging::V4Debugger *debugger)
+ QV4Debugger *debugger)
{
QV4DataCollector::Ref ref;
@@ -805,7 +804,7 @@ QJsonObject QV4DebugServiceImpl::buildFrame(const QV4::StackFrame &stackFrame, i
frame[QLatin1String("column")] = stackFrame.column;
QJsonArray scopes;
- if (debugger->state() == QV4::Debugging::V4Debugger::Paused) {
+ if (debugger->state() == QV4Debugger::Paused) {
RefHolder holder(theCollector.data(), &collectedRefs);
bool foundThis = false;
ThisCollectJob job(debugger->engine(), theCollector.data(), frameNr, &foundThis);
@@ -854,8 +853,7 @@ int QV4DebugServiceImpl::encodeScopeType(QV4::Heap::ExecutionContext::ContextTyp
}
}
-QJsonObject QV4DebugServiceImpl::buildScope(int frameNr, int scopeNr,
- QV4::Debugging::V4Debugger *debugger)
+QJsonObject QV4DebugServiceImpl::buildScope(int frameNr, int scopeNr, QV4Debugger *debugger)
{
QJsonObject scope;
@@ -863,7 +861,7 @@ QJsonObject QV4DebugServiceImpl::buildScope(int frameNr, int scopeNr,
RefHolder holder(theCollector.data(), &collectedRefs);
theCollector->collectScope(&object, debugger, frameNr, scopeNr);
- if (debugger->state() == QV4::Debugging::V4Debugger::Paused) {
+ if (debugger->state() == QV4Debugger::Paused) {
QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes =
QV4DataCollector::getScopeTypes(debugger->engine(), frameNr);
scope[QLatin1String("type")] = encodeScopeType(scopeTypes[scopeNr]);
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
index ea4a695fed..37b9f6f976 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
@@ -78,13 +78,12 @@ public:
void signalEmitted(const QString &signal);
void send(QJsonObject v8Payload);
- QJsonObject buildScope(int frameNr, int scopeNr, QV4::Debugging::V4Debugger *debugger);
+ QJsonObject buildScope(int frameNr, int scopeNr, QV4Debugger *debugger);
QJsonArray buildRefs();
QJsonValue lookup(QV4DataCollector::Ref refId);
QJsonValue toRef(QV4DataCollector::Ref ref);
- QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr,
- QV4::Debugging::V4Debugger *debugger);
+ QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr, QV4Debugger *debugger);
int selectedFrame() const;
void selectFrame(int frameNr);
diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp
index 7706a40da6..b04bcd33e7 100644
--- a/src/qml/jsruntime/qv4debugging.cpp
+++ b/src/qml/jsruntime/qv4debugging.cpp
@@ -51,290 +51,4 @@
QT_BEGIN_NAMESPACE
-using namespace QV4;
-using namespace QV4::Debugging;
-
-V4Debugger::JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr,
- const QString &script)
- : engine(engine)
- , frameNr(frameNr)
- , script(script)
- , resultIsException(false)
-{}
-
-void V4Debugger::JavaScriptJob::run()
-{
- Scope scope(engine);
-
- ExecutionContextSaver saver(scope);
-
- ExecutionContext *ctx = engine->currentContext;
- 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 V4Debugger::JavaScriptJob::hasExeption() const
-{
- return resultIsException;
-}
-
-class EvalJob: public V4Debugger::JavaScriptJob
-{
- bool result;
-
-public:
- EvalJob(QV4::ExecutionEngine *engine, const QString &script)
- : V4Debugger::JavaScriptJob(engine, /*frameNr*/-1, script)
- , result(false)
- {}
-
- virtual void handleResult(QV4::ScopedValue &result)
- {
- this->result = result->toBoolean();
- }
-
- bool resultAsBoolean() const
- {
- return result;
- }
-};
-
-V4Debugger::V4Debugger(QV4::ExecutionEngine *engine)
- : m_engine(engine)
- , m_state(Running)
- , m_stepping(NotStepping)
- , m_pauseRequested(false)
- , m_haveBreakPoints(false)
- , m_breakOnThrow(false)
- , m_returnedValue(engine, Primitive::undefinedValue())
- , m_gatherSources(0)
- , m_runningJob(0)
-{
- qMetaTypeId<V4Debugger*>();
- qMetaTypeId<PauseReason>();
-}
-
-void V4Debugger::pause()
-{
- QMutexLocker locker(&m_lock);
- if (m_state == Paused)
- return;
- m_pauseRequested = true;
-}
-
-void V4Debugger::resume(Speed speed)
-{
- QMutexLocker locker(&m_lock);
- if (m_state != Paused)
- return;
-
- if (!m_returnedValue.isUndefined())
- m_returnedValue.set(m_engine, Encode::undefined());
-
- m_currentContext.set(m_engine, *m_engine->currentContext);
- m_stepping = speed;
- m_runningCondition.wakeAll();
-}
-
-void V4Debugger::addBreakPoint(const QString &fileName, int lineNumber, const QString &condition)
-{
- QMutexLocker locker(&m_lock);
- m_breakPoints.insert(DebuggerBreakPoint(fileName.mid(fileName.lastIndexOf('/') + 1), lineNumber), condition);
- m_haveBreakPoints = true;
-}
-
-void V4Debugger::removeBreakPoint(const QString &fileName, int lineNumber)
-{
- QMutexLocker locker(&m_lock);
- m_breakPoints.remove(DebuggerBreakPoint(fileName.mid(fileName.lastIndexOf('/') + 1), lineNumber));
- m_haveBreakPoints = !m_breakPoints.isEmpty();
-}
-
-void V4Debugger::setBreakOnThrow(bool onoff)
-{
- QMutexLocker locker(&m_lock);
-
- m_breakOnThrow = onoff;
-}
-
-V4Debugger::ExecutionState V4Debugger::currentExecutionState() const
-{
- ExecutionState state;
- state.fileName = getFunction()->sourceFile();
- state.lineNumber = engine()->current->lineNumber;
-
- return state;
-}
-
-QVector<StackFrame> V4Debugger::stackTrace(int frameLimit) const
-{
- return m_engine->stackTrace(frameLimit);
-}
-
-void V4Debugger::maybeBreakAtInstruction()
-{
- if (m_runningJob) // do not re-enter when we're doing a job for the debugger.
- return;
-
- QMutexLocker locker(&m_lock);
-
- if (m_gatherSources) {
- m_gatherSources->run();
- delete m_gatherSources;
- m_gatherSources = 0;
- }
-
- switch (m_stepping) {
- case StepOver:
- if (m_currentContext.asManaged()->d() != m_engine->current)
- break;
- // fall through
- case StepIn:
- pauseAndWait(Step);
- return;
- case StepOut:
- case NotStepping:
- break;
- }
-
- if (m_pauseRequested) { // Serve debugging requests from the agent
- m_pauseRequested = false;
- pauseAndWait(PauseRequest);
- } else if (m_haveBreakPoints) {
- if (Function *f = getFunction()) {
- const int lineNumber = engine()->current->lineNumber;
- if (reallyHitTheBreakPoint(f->sourceFile(), lineNumber))
- pauseAndWait(BreakPoint);
- }
- }
-}
-
-void V4Debugger::enteringFunction()
-{
- if (m_runningJob)
- return;
- QMutexLocker locker(&m_lock);
-
- if (m_stepping == StepIn) {
- m_currentContext.set(m_engine, *m_engine->currentContext);
- }
-}
-
-void V4Debugger::leavingFunction(const ReturnedValue &retVal)
-{
- if (m_runningJob)
- return;
- Q_UNUSED(retVal); // TODO
-
- QMutexLocker locker(&m_lock);
-
- if (m_stepping != NotStepping && m_currentContext.asManaged()->d() == m_engine->current) {
- m_currentContext.set(m_engine, *m_engine->parentContext(m_engine->currentContext));
- m_stepping = StepOver;
- m_returnedValue.set(m_engine, retVal);
- }
-}
-
-void V4Debugger::aboutToThrow()
-{
- if (!m_breakOnThrow)
- return;
-
- if (m_runningJob) // do not re-enter when we're doing a job for the debugger.
- return;
-
- QMutexLocker locker(&m_lock);
- pauseAndWait(Throwing);
-}
-
-Function *V4Debugger::getFunction() const
-{
- Scope scope(m_engine);
- ExecutionContext *context = m_engine->currentContext;
- ScopedFunctionObject function(scope, context->getFunctionObject());
- if (function)
- return function->function();
- else
- return context->d()->engine->globalCode;
-}
-
-void V4Debugger::pauseAndWait(PauseReason reason)
-{
- if (m_runningJob)
- return;
-
- m_state = Paused;
- emit debuggerPaused(this, reason);
-
- while (true) {
- m_runningCondition.wait(&m_lock);
- if (m_runningJob) {
- m_runningJob->run();
- m_jobIsRunning.wakeAll();
- } else {
- break;
- }
- }
-
- m_state = Running;
-}
-
-bool V4Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr)
-{
- BreakPoints::iterator it = m_breakPoints.find(DebuggerBreakPoint(filename.mid(filename.lastIndexOf('/') + 1), linenr));
- if (it == m_breakPoints.end())
- return false;
- QString condition = it.value();
- if (condition.isEmpty())
- return true;
-
- Q_ASSERT(m_runningJob == 0);
- EvalJob evilJob(m_engine, condition);
- m_runningJob = &evilJob;
- m_runningJob->run();
- m_runningJob = 0;
-
- return evilJob.resultAsBoolean();
-}
-
-void V4Debugger::runInEngine(V4Debugger::Job *job)
-{
- QMutexLocker locker(&m_lock);
- runInEngine_havingLock(job);
-}
-
-void V4Debugger::runInEngine_havingLock(V4Debugger::Job *job)
-{
- Q_ASSERT(job);
- Q_ASSERT(m_runningJob == 0);
-
- m_runningJob = job;
- m_runningCondition.wakeAll();
- m_jobIsRunning.wait(&m_lock);
- m_runningJob = 0;
-}
-
-V4Debugger::Job::~Job()
-{
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h
index 683036882e..3a3ecef918 100644
--- a/src/qml/jsruntime/qv4debugging_p.h
+++ b/src/qml/jsruntime/qv4debugging_p.h
@@ -31,8 +31,8 @@
**
****************************************************************************/
-#ifndef DEBUGGING_H
-#define DEBUGGING_H
+#ifndef QV4DEBUGGING_H
+#define QV4DEBUGGING_H
//
// W A R N I N G
@@ -46,50 +46,13 @@
//
#include "qv4global_p.h"
-#include "qv4engine_p.h"
-#include "qv4context_p.h"
-#include "qv4scopedvalue_p.h"
-
-#include <QHash>
-#include <QThread>
-#include <QMutex>
-#include <QWaitCondition>
-
-#include <QtCore/QJsonObject>
+#include <QtCore/qobject.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-
-struct Function;
-
namespace Debugging {
-enum PauseReason {
- PauseRequest,
- BreakPoint,
- Throwing,
- Step
-};
-
-struct DebuggerBreakPoint {
- DebuggerBreakPoint(const QString &fileName, int line)
- : fileName(fileName), lineNumber(line)
- {}
- QString fileName;
- int lineNumber;
-};
-inline uint qHash(const DebuggerBreakPoint &b, uint seed = 0) Q_DECL_NOTHROW
-{
- return qHash(b.fileName, seed) ^ b.lineNumber;
-}
-inline bool operator==(const DebuggerBreakPoint &a, const DebuggerBreakPoint &b)
-{
- return a.lineNumber == b.lineNumber && a.fileName == b.fileName;
-}
-
-typedef QHash<DebuggerBreakPoint, QString> BreakPoints;
-
class Q_QML_EXPORT Debugger : public QObject
{
Q_OBJECT
@@ -103,122 +66,9 @@ public:
virtual void aboutToThrow() = 0;
};
-class Q_QML_EXPORT V4Debugger : public Debugger
-{
- Q_OBJECT
-public:
- class Q_QML_EXPORT Job
- {
- public:
- virtual ~Job() = 0;
- virtual void run() = 0;
- };
-
- class Q_QML_EXPORT 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
- };
-
- enum Speed {
- FullThrottle = 0,
- StepOut,
- StepOver,
- StepIn,
-
- NotStepping = FullThrottle
- };
-
- V4Debugger(ExecutionEngine *engine);
-
- ExecutionEngine *engine() const
- { return m_engine; }
-
- void pause();
- void resume(Speed speed);
-
- State state() const { return m_state; }
-
- void addBreakPoint(const QString &fileName, int lineNumber, const QString &condition = QString());
- void removeBreakPoint(const QString &fileName, int lineNumber);
-
- void setBreakOnThrow(bool onoff);
-
- // used for testing
- struct ExecutionState
- {
- QString fileName;
- int lineNumber;
- };
- ExecutionState currentExecutionState() const;
-
- bool pauseAtNextOpportunity() const {
- return m_pauseRequested || m_haveBreakPoints || m_gatherSources || m_stepping >= StepOver;
- }
-
- QVector<StackFrame> stackTrace(int frameLimit = -1) const;
- QVector<Heap::ExecutionContext::ContextType> getScopeTypes(int frame = 0) const;
-
- Function *getFunction() const;
- void runInEngine(Job *job);
-
-public: // compile-time interface
- void maybeBreakAtInstruction();
-
-public: // execution hooks
- void enteringFunction();
- void leavingFunction(const ReturnedValue &retVal);
- void aboutToThrow();
-
-signals:
- void debuggerPaused(QV4::Debugging::V4Debugger *self, QV4::Debugging::PauseReason reason);
-
-private:
- // requires lock to be held
- void pauseAndWait(PauseReason reason);
- bool reallyHitTheBreakPoint(const QString &filename, int linenr);
- void runInEngine_havingLock(V4Debugger::Job *job);
-
-private:
- QV4::ExecutionEngine *m_engine;
- QV4::PersistentValue m_currentContext;
- QMutex m_lock;
- QWaitCondition m_runningCondition;
- State m_state;
- Speed m_stepping;
- bool m_pauseRequested;
- bool m_haveBreakPoints;
- bool m_breakOnThrow;
-
- BreakPoints m_breakPoints;
- QV4::PersistentValue m_returnedValue;
-
- Job *m_gatherSources;
- Job *m_runningJob;
- QWaitCondition m_jobIsRunning;
-};
-
} // namespace Debugging
} // namespace QV4
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QV4::Debugging::Debugger*)
-Q_DECLARE_METATYPE(QV4::Debugging::PauseReason)
-
-#endif // DEBUGGING_H
+#endif // QV4DEBUGGING_H
diff --git a/tests/auto/qml/debugger/debugger.pro b/tests/auto/qml/debugger/debugger.pro
index 420510679f..ccb2d71c53 100644
--- a/tests/auto/qml/debugger/debugger.pro
+++ b/tests/auto/qml/debugger/debugger.pro
@@ -15,7 +15,8 @@ PUBLICTESTS += \
PRIVATETESTS += \
qqmldebugclient \
qqmldebuglocal \
- qqmldebugservice
+ qqmldebugservice \
+ qv4debugger
SUBDIRS += $$PUBLICTESTS
diff --git a/tests/auto/qml/debugger/qv4debugger/qv4debugger.pro b/tests/auto/qml/debugger/qv4debugger/qv4debugger.pro
new file mode 100644
index 0000000000..d11de56e43
--- /dev/null
+++ b/tests/auto/qml/debugger/qv4debugger/qv4debugger.pro
@@ -0,0 +1,17 @@
+CONFIG += testcase
+TARGET = tst_qv4debugger
+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
+
+HEADERS += \
+ $$PWD/../../../../../src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h \
+ $$PWD/../../../../../src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h
+
+INCLUDEPATH += \
+ $$PWD/../../../../../src/plugins/qmltooling/qmldbg_debugger
+
+QT += core-private gui-private qml-private network testlib
diff --git a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
index 39a1fbc173..c5fa6be7a0 100644
--- a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp
+++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
@@ -33,6 +33,7 @@
#include <QtTest/QtTest>
#include "qv4datacollector.h"
+#include "qv4debugger.h"
#include <QJSEngine>
#include <QQmlEngine>
@@ -159,7 +160,7 @@ public:
}
public slots:
- void debuggerPaused(V4Debugger *debugger, QV4::Debugging::PauseReason reason)
+ void debuggerPaused(QV4Debugger *debugger, QV4Debugger::PauseReason reason)
{
Q_ASSERT(debugger == m_debugger);
Q_ASSERT(debugger->engine() == collector.engine());
@@ -167,7 +168,7 @@ public slots:
m_pauseReason = reason;
m_statesWhenPaused << debugger->currentExecutionState();
- if (debugger->state() == V4Debugger::Paused &&
+ if (debugger->state() == QV4Debugger::Paused &&
debugger->engine()->hasException) {
Refs refs;
RefHolder holder(&collector, &refs);
@@ -184,7 +185,7 @@ public slots:
m_stackTrace = debugger->stackTrace();
while (!m_expressionRequests.isEmpty()) {
- Q_ASSERT(debugger->state() == V4Debugger::Paused);
+ Q_ASSERT(debugger->state() == QV4Debugger::Paused);
ExpressionRequest request = m_expressionRequests.takeFirst();
m_expressionResults << Refs();
RefHolder holder(&collector, &m_expressionResults.last());
@@ -196,7 +197,7 @@ public slots:
if (m_captureContextInfo)
captureContextInfo(debugger);
- debugger->resume(V4Debugger::FullThrottle);
+ debugger->resume(QV4Debugger::FullThrottle);
}
public:
@@ -209,7 +210,7 @@ public:
int lineNumber;
};
- void captureContextInfo(V4Debugger *debugger)
+ void captureContextInfo(QV4Debugger *debugger)
{
for (int i = 0, ei = m_stackTrace.size(); i != ei; ++i) {
m_capturedArguments.append(NamedRefs(&collector));
@@ -226,18 +227,17 @@ public:
}
}
- void addDebugger(V4Debugger *debugger)
+ void addDebugger(QV4Debugger *debugger)
{
Q_ASSERT(!m_debugger);
m_debugger = debugger;
- connect(m_debugger, &V4Debugger::debuggerPaused,
- this, &TestAgent::debuggerPaused);
+ connect(m_debugger, &QV4Debugger::debuggerPaused, this, &TestAgent::debuggerPaused);
}
bool m_wasPaused;
- PauseReason m_pauseReason;
+ QV4Debugger::PauseReason m_pauseReason;
bool m_captureContextInfo;
- QList<V4Debugger::ExecutionState> m_statesWhenPaused;
+ QList<QV4Debugger::ExecutionState> m_statesWhenPaused;
QList<TestBreakPoint> m_breakPointsToAddWhenPaused;
QVector<QV4::StackFrame> m_stackTrace;
QVector<NamedRefs> m_capturedArguments;
@@ -251,7 +251,7 @@ public:
};
QVector<ExpressionRequest> m_expressionRequests;
QVector<Refs> m_expressionResults;
- V4Debugger *m_debugger;
+ QV4Debugger *m_debugger;
// Utility methods:
void dumpStackTrace() const
@@ -295,9 +295,9 @@ private slots:
void evaluateExpression();
private:
- V4Debugger *debugger() const
+ QV4Debugger *debugger() const
{
- return static_cast<V4Debugger *>(m_v4->debugger);
+ return static_cast<QV4Debugger *>(m_v4->debugger);
}
void evaluateJavaScript(const QString &script, const QString &fileName, int lineNumber = 1)
{
@@ -319,7 +319,7 @@ void tst_qv4debugger::init()
m_engine = new TestEngine;
m_v4 = m_engine->v4Engine();
m_v4->iselFactory.reset(new QV4::Moth::ISelFactory);
- m_v4->setDebugger(new V4Debugger(m_v4));
+ m_v4->setDebugger(new QV4Debugger(m_v4));
m_engine->moveToThread(m_javaScriptThread);
m_javaScriptThread->start();
m_debuggerAgent = new TestAgent(m_v4);
@@ -359,7 +359,7 @@ void tst_qv4debugger::pendingBreakpoint()
evaluateJavaScript(script, "testfile");
QVERIFY(m_debuggerAgent->m_wasPaused);
QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 1);
- V4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.first();
+ QV4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.first();
QCOMPARE(state.fileName, QString("testfile"));
QCOMPARE(state.lineNumber, 2);
}
@@ -375,7 +375,7 @@ void tst_qv4debugger::liveBreakPoint()
evaluateJavaScript(script, "liveBreakPoint");
QVERIFY(m_debuggerAgent->m_wasPaused);
QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 2);
- V4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.at(1);
+ QV4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.at(1);
QCOMPARE(state.fileName, QString("liveBreakPoint"));
QCOMPARE(state.lineNumber, 3);
}
@@ -404,7 +404,7 @@ void tst_qv4debugger::addBreakPointWhilePaused()
QVERIFY(m_debuggerAgent->m_wasPaused);
QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 2);
- V4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.at(0);
+ QV4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.at(0);
QCOMPARE(state.fileName, QString("addBreakPointWhilePaused"));
QCOMPARE(state.lineNumber, 1);
@@ -415,7 +415,7 @@ void tst_qv4debugger::addBreakPointWhilePaused()
static QV4::ReturnedValue someCall(QV4::CallContext *ctx)
{
- static_cast<V4Debugger *>(ctx->d()->engine->debugger)
+ static_cast<QV4Debugger *>(ctx->d()->engine->debugger)
->removeBreakPoint("removeBreakPointForNextInstruction", 2);
return QV4::Encode::undefined();
}
@@ -450,7 +450,7 @@ void tst_qv4debugger::conditionalBreakPoint()
evaluateJavaScript(script, "conditionalBreakPoint");
QVERIFY(m_debuggerAgent->m_wasPaused);
QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 4);
- V4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.first();
+ QV4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.first();
QCOMPARE(state.fileName, QString("conditionalBreakPoint"));
QCOMPARE(state.lineNumber, 3);
@@ -465,7 +465,7 @@ void tst_qv4debugger::conditionalBreakPointInQml()
{
QQmlEngine engine;
QV4::ExecutionEngine *v4 = QV8Engine::getV4(&engine);
- V4Debugger *v4Debugger = new V4Debugger(v4);
+ QV4Debugger *v4Debugger = new QV4Debugger(v4);
v4->iselFactory.reset(new QV4::Moth::ISelFactory);
v4->setDebugger(v4Debugger);
@@ -644,7 +644,7 @@ void tst_qv4debugger::pauseOnThrow()
debugger()->setBreakOnThrow(true);
evaluateJavaScript(script, "pauseOnThrow");
QVERIFY(m_debuggerAgent->m_wasPaused);
- QCOMPARE(m_debuggerAgent->m_pauseReason, Throwing);
+ QCOMPARE(m_debuggerAgent->m_pauseReason, QV4Debugger::Throwing);
QCOMPARE(m_debuggerAgent->m_stackTrace.size(), 2);
QVERIFY(m_debuggerAgent->m_thrownValue >= qint64(0));
QJsonObject exception = m_debuggerAgent->collector.lookupRef(m_debuggerAgent->m_thrownValue);
@@ -665,9 +665,9 @@ void tst_qv4debugger::breakInCatch()
debugger()->addBreakPoint("breakInCatch", 4);
evaluateJavaScript(script, "breakInCatch");
QVERIFY(m_debuggerAgent->m_wasPaused);
- QCOMPARE(m_debuggerAgent->m_pauseReason, BreakPoint);
+ QCOMPARE(m_debuggerAgent->m_pauseReason, QV4Debugger::BreakPointHit);
QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 1);
- V4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.first();
+ QV4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.first();
QCOMPARE(state.fileName, QString("breakInCatch"));
QCOMPARE(state.lineNumber, 4);
}
@@ -682,9 +682,9 @@ void tst_qv4debugger::breakInWith()
debugger()->addBreakPoint("breakInWith", 2);
evaluateJavaScript(script, "breakInWith");
QVERIFY(m_debuggerAgent->m_wasPaused);
- QCOMPARE(m_debuggerAgent->m_pauseReason, BreakPoint);
+ QCOMPARE(m_debuggerAgent->m_pauseReason, QV4Debugger::BreakPointHit);
QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 1);
- V4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.first();
+ QV4Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.first();
QCOMPARE(state.fileName, QString("breakInWith"));
QCOMPARE(state.lineNumber, 2);
}
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index b61eca730f..3a97bf655d 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -57,7 +57,6 @@ PRIVATETESTS += \
qrcqml \
qqmltimer \
qqmlinstantiator \
- qv4debugger \
qqmlenginecleanup \
v4misc \
qqmltranslation \
diff --git a/tests/auto/qml/qv4debugger/qv4debugger.pro b/tests/auto/qml/qv4debugger/qv4debugger.pro
deleted file mode 100644
index 540cab70e6..0000000000
--- a/tests/auto/qml/qv4debugger/qv4debugger.pro
+++ /dev/null
@@ -1,15 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qv4debugger
-macx:CONFIG -= app_bundle
-
-SOURCES += \
- $$PWD/tst_qv4debugger.cpp \
- $$PWD/../../../../src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
-
-HEADERS += \
- $$PWD/../../../../src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
-
-INCLUDEPATH += \
- $$PWD/../../../../src/plugins/qmltooling/qmldbg_debugger
-
-QT += core-private gui-private qml-private network testlib