aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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