aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro6
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp251
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h97
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp84
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h19
-rw-r--r--src/qml/jsruntime/qv4debugging.cpp144
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h63
-rw-r--r--tests/auto/qml/qv4debugger/tst_qv4debugger.cpp64
8 files changed, 395 insertions, 333 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro
index 6c29411981..dd0c9a174f 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro
+++ b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro
@@ -10,7 +10,8 @@ SOURCES += \
$$PWD/qqmldebuggerservicefactory.cpp \
$$PWD/qqmlenginedebugservice.cpp \
$$PWD/qqmlwatcher.cpp \
- $$PWD/qv4debugservice.cpp
+ $$PWD/qv4debugservice.cpp \
+ $$PWD/qv4debuggeragent.cpp
HEADERS += \
$$PWD/../shared/qqmlconfigurabledebugservice.h \
@@ -18,7 +19,8 @@ HEADERS += \
$$PWD/qqmldebuggerservicefactory.h \
$$PWD/qqmlenginedebugservice.h \
$$PWD/qqmlwatcher.h \
- $$PWD/qv4debugservice.h
+ $$PWD/qv4debugservice.h \
+ $$PWD/qv4debuggeragent.h
INCLUDEPATH += $$PWD \
$$PWD/../shared
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp
new file mode 100644
index 0000000000..15421f4f5d
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp
@@ -0,0 +1,251 @@
+/****************************************************************************
+**
+** 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 "qv4debuggeragent.h"
+#include "qv4debugservice.h"
+
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonarray.h>
+
+QT_BEGIN_NAMESPACE
+
+QV4DebuggerAgent::QV4DebuggerAgent(QV4DebugServiceImpl *debugService)
+ : m_breakOnThrow(false), m_debugService(debugService)
+{}
+
+QV4::Debugging::Debugger *QV4DebuggerAgent::firstDebugger() const
+{
+ // Currently only 1 single engine is supported, so:
+ if (m_debuggers.isEmpty())
+ return 0;
+ else
+ return m_debuggers.first();
+}
+
+bool QV4DebuggerAgent::isRunning() const
+{
+ // Currently only 1 single engine is supported, so:
+ if (QV4::Debugging::Debugger *debugger = firstDebugger())
+ return debugger->state() == QV4::Debugging::Debugger::Running;
+ else
+ return false;
+}
+
+void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::Debugger *debugger,
+ QV4::Debugging::PauseReason reason)
+{
+ Q_UNUSED(reason);
+
+ m_debugService->clearHandles(debugger->engine());
+
+ QJsonObject event, body, script;
+ event.insert(QStringLiteral("type"), QStringLiteral("event"));
+
+ switch (reason) {
+ case QV4::Debugging::Step:
+ case QV4::Debugging::PauseRequest:
+ case QV4::Debugging::BreakPoint: {
+ event.insert(QStringLiteral("event"), QStringLiteral("break"));
+ QVector<QV4::StackFrame> frames = debugger->stackTrace(1);
+ if (frames.isEmpty())
+ break;
+
+ const QV4::StackFrame &topFrame = frames.first();
+ body.insert(QStringLiteral("invocationText"), topFrame.function);
+ body.insert(QStringLiteral("sourceLine"), topFrame.line - 1);
+ if (topFrame.column > 0)
+ body.insert(QStringLiteral("sourceColumn"), topFrame.column);
+ QJsonArray breakPoints;
+ foreach (int breakPointId, breakPointIds(topFrame.source, topFrame.line))
+ breakPoints.push_back(breakPointId);
+ body.insert(QStringLiteral("breakpoints"), breakPoints);
+ script.insert(QStringLiteral("name"), topFrame.source);
+ } break;
+ case QV4::Debugging::Throwing:
+ // TODO: complete this!
+ event.insert(QStringLiteral("event"), QStringLiteral("exception"));
+ break;
+ }
+
+ if (!script.isEmpty())
+ body.insert(QStringLiteral("script"), script);
+ if (!body.isEmpty())
+ event.insert(QStringLiteral("body"), body);
+ m_debugService->send(event);
+}
+
+void QV4DebuggerAgent::sourcesCollected(QV4::Debugging::Debugger *debugger,
+ const QStringList &sources, int requestSequenceNr)
+{
+ QJsonArray body;
+ foreach (const QString &source, sources) {
+ QJsonObject src;
+ src[QLatin1String("name")] = source;
+ src[QLatin1String("scriptType")] = 4;
+ body.append(src);
+ }
+
+ QJsonObject response;
+ response[QLatin1String("success")] = true;
+ response[QLatin1String("running")] = debugger->state() == QV4::Debugging::Debugger::Running;
+ response[QLatin1String("body")] = body;
+ response[QLatin1String("command")] = QStringLiteral("scripts");
+ response[QLatin1String("request_seq")] = requestSequenceNr;
+ response[QLatin1String("type")] = QStringLiteral("response");
+ m_debugService->send(response);
+}
+
+void QV4DebuggerAgent::addDebugger(QV4::Debugging::Debugger *debugger)
+{
+ Q_ASSERT(!m_debuggers.contains(debugger));
+ m_debuggers << debugger;
+
+ debugger->setBreakOnThrow(m_breakOnThrow);
+
+ foreach (const BreakPoint &breakPoint, m_breakPoints.values())
+ if (breakPoint.enabled)
+ debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition);
+
+ connect(debugger, SIGNAL(destroyed(QObject*)),
+ this, SLOT(handleDebuggerDeleted(QObject*)));
+ connect(debugger, SIGNAL(sourcesCollected(QV4::Debugging::Debugger*,QStringList,int)),
+ this, SLOT(sourcesCollected(QV4::Debugging::Debugger*,QStringList,int)),
+ Qt::QueuedConnection);
+ connect(debugger, SIGNAL(debuggerPaused(QV4::Debugging::Debugger*,QV4::Debugging::PauseReason)),
+ this, SLOT(debuggerPaused(QV4::Debugging::Debugger*,QV4::Debugging::PauseReason)),
+ Qt::QueuedConnection);
+}
+
+void QV4DebuggerAgent::removeDebugger(QV4::Debugging::Debugger *debugger)
+{
+ m_debuggers.removeAll(debugger);
+ disconnect(debugger, SIGNAL(destroyed(QObject*)),
+ this, SLOT(handleDebuggerDeleted(QObject*)));
+ disconnect(debugger, SIGNAL(sourcesCollected(QV4::Debugging::Debugger*,QStringList,int)),
+ this, SLOT(sourcesCollected(QV4::Debugging::Debugger*,QStringList,int)));
+ disconnect(debugger,
+ SIGNAL(debuggerPaused(QV4::Debugging::Debugger*,QV4::Debugging::PauseReason)),
+ this,
+ SLOT(debuggerPaused(QV4::Debugging::Debugger*,QV4::Debugging::PauseReason)));
+}
+
+void QV4DebuggerAgent::handleDebuggerDeleted(QObject *debugger)
+{
+ m_debuggers.removeAll(static_cast<QV4::Debugging::Debugger *>(debugger));
+}
+
+void QV4DebuggerAgent::pause(QV4::Debugging::Debugger *debugger) const
+{
+ debugger->pause();
+}
+
+void QV4DebuggerAgent::pauseAll() const
+{
+ foreach (QV4::Debugging::Debugger *debugger, m_debuggers)
+ pause(debugger);
+}
+
+void QV4DebuggerAgent::resumeAll() const
+{
+ foreach (QV4::Debugging::Debugger *debugger, m_debuggers)
+ if (debugger->state() == QV4::Debugging::Debugger::Paused)
+ debugger->resume(QV4::Debugging::Debugger::FullThrottle);
+}
+
+int QV4DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber, bool enabled, const QString &condition)
+{
+ if (enabled)
+ foreach (QV4::Debugging::Debugger *debugger, m_debuggers)
+ debugger->addBreakPoint(fileName, lineNumber, condition);
+
+ int id = m_breakPoints.size();
+ m_breakPoints.insert(id, BreakPoint(fileName, lineNumber, enabled, condition));
+ return id;
+}
+
+void QV4DebuggerAgent::removeBreakPoint(int id)
+{
+ BreakPoint breakPoint = m_breakPoints.value(id);
+ if (!breakPoint.isValid())
+ return;
+
+ m_breakPoints.remove(id);
+
+ if (breakPoint.enabled)
+ foreach (QV4::Debugging::Debugger *debugger, m_debuggers)
+ debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr);
+}
+
+void QV4DebuggerAgent::removeAllBreakPoints()
+{
+ QList<int> ids = m_breakPoints.keys();
+ foreach (int id, ids)
+ removeBreakPoint(id);
+}
+
+void QV4DebuggerAgent::enableBreakPoint(int id, bool onoff)
+{
+ BreakPoint &breakPoint = m_breakPoints[id];
+ if (!breakPoint.isValid() || breakPoint.enabled == onoff)
+ return;
+ breakPoint.enabled = onoff;
+
+ foreach (QV4::Debugging::Debugger *debugger, m_debuggers) {
+ if (onoff)
+ debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition);
+ else
+ debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr);
+ }
+}
+
+QList<int> QV4DebuggerAgent::breakPointIds(const QString &fileName, int lineNumber) const
+{
+ QList<int> ids;
+
+ for (QHash<int, BreakPoint>::const_iterator i = m_breakPoints.begin(), ei = m_breakPoints.end(); i != ei; ++i)
+ if (i->lineNr == lineNumber && fileName.endsWith(i->fileName))
+ ids.push_back(i.key());
+
+ return ids;
+}
+
+void QV4DebuggerAgent::setBreakOnThrow(bool onoff)
+{
+ if (onoff != m_breakOnThrow) {
+ m_breakOnThrow = onoff;
+ foreach (QV4::Debugging::Debugger *debugger, m_debuggers)
+ debugger->setBreakOnThrow(onoff);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h
new file mode 100644
index 0000000000..6126eea772
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** 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 QV4DEBUGGERAGENT_H
+#define QV4DEBUGGERAGENT_H
+
+#include <private/qv4debugging_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV4DebugServiceImpl;
+
+class QV4DebuggerAgent : public QObject
+{
+ Q_OBJECT
+public:
+ QV4DebuggerAgent(QV4DebugServiceImpl *m_debugService);
+
+ QV4::Debugging::Debugger *firstDebugger() const;
+ bool isRunning() const;
+
+ void addDebugger(QV4::Debugging::Debugger *debugger);
+ void removeDebugger(QV4::Debugging::Debugger *debugger);
+
+ void pause(QV4::Debugging::Debugger *debugger) const;
+ void pauseAll() const;
+ void resumeAll() const;
+ int addBreakPoint(const QString &fileName, int lineNumber, bool enabled = true, const QString &condition = QString());
+ void removeBreakPoint(int id);
+ void removeAllBreakPoints();
+ void enableBreakPoint(int id, bool onoff);
+ QList<int> breakPointIds(const QString &fileName, int lineNumber) const;
+
+ bool breakOnThrow() const { return m_breakOnThrow; }
+ void setBreakOnThrow(bool onoff);
+
+public slots:
+ void debuggerPaused(QV4::Debugging::Debugger *debugger, QV4::Debugging::PauseReason reason);
+ void sourcesCollected(QV4::Debugging::Debugger *debugger, const QStringList &sources,
+ int requestSequenceNr);
+ void handleDebuggerDeleted(QObject *debugger);
+
+private:
+ QList<QV4::Debugging::Debugger *> m_debuggers;
+
+ struct BreakPoint {
+ QString fileName;
+ int lineNr;
+ bool enabled;
+ QString condition;
+
+ BreakPoint(): lineNr(-1), enabled(false) {}
+ BreakPoint(const QString &fileName, int lineNr, bool enabled, const QString &condition)
+ : fileName(fileName), lineNr(lineNr), enabled(enabled), condition(condition)
+ {}
+
+ bool isValid() const { return lineNr >= 0 && !fileName.isEmpty(); }
+ };
+
+ QHash<int, BreakPoint> m_breakPoints;
+ bool m_breakOnThrow;
+ QV4DebugServiceImpl *m_debugService;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV4DEBUGGERAGENT_H
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
index 62436f18c9..21bfe97808 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
@@ -720,90 +720,6 @@ void QV4DebugServiceImpl::sendSomethingToSomebody(const char *type, int magicNum
emit messageToClient(name(), packMessage(type, response));
}
-QV4DebuggerAgent::QV4DebuggerAgent(QV4DebugServiceImpl *debugService)
- : debugService(debugService)
-{}
-
-QV4::Debugging::Debugger *QV4DebuggerAgent::firstDebugger() const
-{
- // Currently only 1 single engine is supported, so:
- if (m_debuggers.isEmpty())
- return 0;
- else
- return m_debuggers.first();
-}
-
-bool QV4DebuggerAgent::isRunning() const
-{
- // Currently only 1 single engine is supported, so:
- if (QV4::Debugging::Debugger *debugger = firstDebugger())
- return debugger->state() == QV4::Debugging::Debugger::Running;
- else
- return false;
-}
-
-void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::Debugger *debugger, QV4::Debugging::PauseReason reason)
-{
- Q_UNUSED(reason);
-
- debugService->clearHandles(debugger->engine());
-
- QJsonObject event, body, script;
- event.insert(QStringLiteral("type"), QStringLiteral("event"));
-
- switch (reason) {
- case QV4::Debugging::Step:
- case QV4::Debugging::PauseRequest:
- case QV4::Debugging::BreakPoint: {
- event.insert(QStringLiteral("event"), QStringLiteral("break"));
- QVector<QV4::StackFrame> frames = debugger->stackTrace(1);
- if (frames.isEmpty())
- break;
-
- const QV4::StackFrame &topFrame = frames.first();
- body.insert(QStringLiteral("invocationText"), topFrame.function);
- body.insert(QStringLiteral("sourceLine"), topFrame.line - 1);
- if (topFrame.column > 0)
- body.insert(QStringLiteral("sourceColumn"), topFrame.column);
- QJsonArray breakPoints;
- foreach (int breakPointId, breakPointIds(topFrame.source, topFrame.line))
- breakPoints.push_back(breakPointId);
- body.insert(QStringLiteral("breakpoints"), breakPoints);
- script.insert(QStringLiteral("name"), topFrame.source);
- } break;
- case QV4::Debugging::Throwing:
- // TODO: complete this!
- event.insert(QStringLiteral("event"), QStringLiteral("exception"));
- break;
- }
-
- if (!script.isEmpty())
- body.insert(QStringLiteral("script"), script);
- if (!body.isEmpty())
- event.insert(QStringLiteral("body"), body);
- debugService->send(event);
-}
-
-void QV4DebuggerAgent::sourcesCollected(QV4::Debugging::Debugger *debugger, QStringList sources, int requestSequenceNr)
-{
- QJsonArray body;
- foreach (const QString &source, sources) {
- QJsonObject src;
- src[QLatin1String("name")] = source;
- src[QLatin1String("scriptType")] = 4;
- body.append(src);
- }
-
- QJsonObject response;
- response[QLatin1String("success")] = true;
- response[QLatin1String("running")] = debugger->state() == QV4::Debugging::Debugger::Running;
- response[QLatin1String("body")] = body;
- response[QLatin1String("command")] = QStringLiteral("scripts");
- response[QLatin1String("request_seq")] = requestSequenceNr;
- response[QLatin1String("type")] = QStringLiteral("response");
- debugService->send(response);
-}
-
void QV4DebugServiceImpl::handleV8Request(const QByteArray &payload)
{
TRACE_PROTOCOL(qDebug() << "v8request, payload:" << payload.constData());
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
index 23bffa368a..6e5113600d 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
@@ -46,6 +46,7 @@
//
#include "qqmlconfigurabledebugservice.h"
+#include "qv4debuggeragent.h"
#include <private/qqmldebugserviceinterfaces_p.h>
#include <private/qv4debugging_p.h>
@@ -61,24 +62,6 @@ class V8CommandHandler;
class UnknownV8CommandHandler;
class QV4DebugServiceImpl;
-class QV4DebuggerAgent : public QV4::Debugging::DebuggerAgent
-{
- Q_OBJECT
-public:
- QV4DebuggerAgent(QV4DebugServiceImpl *debugService);
- QV4::Debugging::Debugger *firstDebugger() const;
- bool isRunning() const;
-
-public slots:
- virtual void debuggerPaused(QV4::Debugging::Debugger *debugger,
- QV4::Debugging::PauseReason reason);
- virtual void sourcesCollected(QV4::Debugging::Debugger *debugger, QStringList sources,
- int requestSequenceNr);
-
-private:
- QV4DebugServiceImpl *debugService;
-};
-
class QV4DebugServiceImpl : public QQmlConfigurableDebugService<QV4DebugService>
{
Q_OBJECT
diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp
index c48bb03844..6f3e48352e 100644
--- a/src/qml/jsruntime/qv4debugging.cpp
+++ b/src/qml/jsruntime/qv4debugging.cpp
@@ -164,10 +164,7 @@ public:
}
Debugger *debugger = engine->debugger;
- QMetaObject::invokeMethod(debugger->agent(), "sourcesCollected", Qt::QueuedConnection,
- Q_ARG(QV4::Debugging::Debugger*, debugger),
- Q_ARG(QStringList, sources),
- Q_ARG(int, seq));
+ emit debugger->sourcesCollected(debugger, sources, seq);
}
};
}
@@ -386,7 +383,6 @@ QJsonObject DataCollector::collectAsJson(const QString &name, const ScopedValue
Debugger::Debugger(QV4::ExecutionEngine *engine)
: m_engine(engine)
- , m_agent(0)
, m_state(Running)
, m_stepping(NotStepping)
, m_pauseRequested(false)
@@ -400,29 +396,6 @@ Debugger::Debugger(QV4::ExecutionEngine *engine)
qMetaTypeId<PauseReason>();
}
-Debugger::~Debugger()
-{
- detachFromAgent();
-}
-
-void Debugger::attachToAgent(DebuggerAgent *agent)
-{
- Q_ASSERT(!m_agent);
- m_agent = agent;
-}
-
-void Debugger::detachFromAgent()
-{
- DebuggerAgent *agent = 0;
- {
- QMutexLocker locker(&m_lock);
- agent = m_agent;
- m_agent = 0;
- }
- if (agent)
- agent->removeDebugger(this);
-}
-
void Debugger::gatherSources(int requestSequenceNr)
{
QMutexLocker locker(&m_lock);
@@ -835,9 +808,7 @@ void Debugger::pauseAndWait(PauseReason reason)
return;
m_state = Paused;
- QMetaObject::invokeMethod(m_agent, "debuggerPaused", Qt::QueuedConnection,
- Q_ARG(QV4::Debugging::Debugger*, this),
- Q_ARG(QV4::Debugging::PauseReason, reason));
+ emit debuggerPaused(this, reason);
while (true) {
m_runningCondition.wait(&m_lock);
@@ -887,117 +858,6 @@ void Debugger::runInEngine_havingLock(Debugger::Job *job)
m_runningJob = 0;
}
-void DebuggerAgent::addDebugger(Debugger *debugger)
-{
- Q_ASSERT(!m_debuggers.contains(debugger));
- m_debuggers << debugger;
- debugger->attachToAgent(this);
-
- debugger->setBreakOnThrow(m_breakOnThrow);
-
- foreach (const BreakPoint &breakPoint, m_breakPoints.values())
- if (breakPoint.enabled)
- debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition);
-}
-
-void DebuggerAgent::removeDebugger(Debugger *debugger)
-{
- m_debuggers.removeAll(debugger);
- debugger->detachFromAgent();
-}
-
-void DebuggerAgent::pause(Debugger *debugger) const
-{
- debugger->pause();
-}
-
-void DebuggerAgent::pauseAll() const
-{
- foreach (Debugger *debugger, m_debuggers)
- pause(debugger);
-}
-
-void DebuggerAgent::resumeAll() const
-{
- foreach (Debugger *debugger, m_debuggers)
- if (debugger->state() == Debugger::Paused)
- debugger->resume(Debugger::FullThrottle);
-}
-
-int DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber, bool enabled, const QString &condition)
-{
- if (enabled)
- foreach (Debugger *debugger, m_debuggers)
- debugger->addBreakPoint(fileName, lineNumber, condition);
-
- int id = m_breakPoints.size();
- m_breakPoints.insert(id, BreakPoint(fileName, lineNumber, enabled, condition));
- return id;
-}
-
-void DebuggerAgent::removeBreakPoint(int id)
-{
- BreakPoint breakPoint = m_breakPoints.value(id);
- if (!breakPoint.isValid())
- return;
-
- m_breakPoints.remove(id);
-
- if (breakPoint.enabled)
- foreach (Debugger *debugger, m_debuggers)
- debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr);
-}
-
-void DebuggerAgent::removeAllBreakPoints()
-{
- QList<int> ids = m_breakPoints.keys();
- foreach (int id, ids)
- removeBreakPoint(id);
-}
-
-void DebuggerAgent::enableBreakPoint(int id, bool onoff)
-{
- BreakPoint &breakPoint = m_breakPoints[id];
- if (!breakPoint.isValid() || breakPoint.enabled == onoff)
- return;
- breakPoint.enabled = onoff;
-
- foreach (Debugger *debugger, m_debuggers) {
- if (onoff)
- debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition);
- else
- debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr);
- }
-}
-
-QList<int> DebuggerAgent::breakPointIds(const QString &fileName, int lineNumber) const
-{
- QList<int> ids;
-
- for (QHash<int, BreakPoint>::const_iterator i = m_breakPoints.begin(), ei = m_breakPoints.end(); i != ei; ++i)
- if (i->lineNr == lineNumber && fileName.endsWith(i->fileName))
- ids.push_back(i.key());
-
- return ids;
-}
-
-void DebuggerAgent::setBreakOnThrow(bool onoff)
-{
- if (onoff != m_breakOnThrow) {
- m_breakOnThrow = onoff;
- foreach (Debugger *debugger, m_debuggers)
- debugger->setBreakOnThrow(onoff);
- }
-}
-
-DebuggerAgent::~DebuggerAgent()
-{
- foreach (Debugger *debugger, m_debuggers)
- debugger->detachFromAgent();
-
- Q_ASSERT(m_debuggers.isEmpty());
-}
-
Debugger::Job::~Job()
{
}
diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h
index 424459a7d9..b85611f457 100644
--- a/src/qml/jsruntime/qv4debugging_p.h
+++ b/src/qml/jsruntime/qv4debugging_p.h
@@ -61,8 +61,6 @@ enum PauseReason {
Step
};
-class DebuggerAgent;
-
struct DebuggerBreakPoint {
DebuggerBreakPoint(const QString &fileName, int line)
: fileName(fileName), lineNumber(line)
@@ -137,8 +135,9 @@ private:
DataCollector::Refs *m_previousRefs;
};
-class Q_QML_EXPORT Debugger
+class Q_QML_EXPORT Debugger : public QObject
{
+ Q_OBJECT
public:
class Job
{
@@ -162,15 +161,10 @@ public:
};
Debugger(ExecutionEngine *engine);
- ~Debugger();
ExecutionEngine *engine() const
{ return m_engine; }
- void attachToAgent(DebuggerAgent *agent);
- void detachFromAgent();
- DebuggerAgent *agent() const { return m_agent; }
-
void gatherSources(int requestSequenceNr);
void pause();
void resume(Speed speed);
@@ -214,6 +208,10 @@ public: // execution hooks
void leavingFunction(const ReturnedValue &retVal);
void aboutToThrow();
+signals:
+ void sourcesCollected(QV4::Debugging::Debugger *self, const QStringList &sources, int seq);
+ void debuggerPaused(QV4::Debugging::Debugger *self, QV4::Debugging::PauseReason reason);
+
private:
Function *getFunction() const;
@@ -228,7 +226,6 @@ private:
private:
QV4::ExecutionEngine *m_engine;
QV4::PersistentValue m_currentContext;
- DebuggerAgent *m_agent;
QMutex m_lock;
QWaitCondition m_runningCondition;
State m_state;
@@ -245,54 +242,6 @@ private:
QWaitCondition m_jobIsRunning;
};
-class Q_QML_EXPORT DebuggerAgent : public QObject
-{
- Q_OBJECT
-public:
- DebuggerAgent(): m_breakOnThrow(false) {}
- ~DebuggerAgent();
-
- void addDebugger(Debugger *debugger);
- void removeDebugger(Debugger *debugger);
-
- void pause(Debugger *debugger) const;
- void pauseAll() const;
- void resumeAll() const;
- int addBreakPoint(const QString &fileName, int lineNumber, bool enabled = true, const QString &condition = QString());
- void removeBreakPoint(int id);
- void removeAllBreakPoints();
- void enableBreakPoint(int id, bool onoff);
- QList<int> breakPointIds(const QString &fileName, int lineNumber) const;
-
- bool breakOnThrow() const { return m_breakOnThrow; }
- void setBreakOnThrow(bool onoff);
-
- Q_INVOKABLE virtual void debuggerPaused(QV4::Debugging::Debugger *debugger,
- QV4::Debugging::PauseReason reason) = 0;
- Q_INVOKABLE virtual void sourcesCollected(QV4::Debugging::Debugger *debugger,
- QStringList sources, int requestSequenceNr) = 0;
-
-protected:
- QList<Debugger *> m_debuggers;
-
- struct BreakPoint {
- QString fileName;
- int lineNr;
- bool enabled;
- QString condition;
-
- BreakPoint(): lineNr(-1), enabled(false) {}
- BreakPoint(const QString &fileName, int lineNr, bool enabled, const QString &condition)
- : fileName(fileName), lineNr(lineNr), enabled(enabled), condition(condition)
- {}
-
- bool isValid() const { return lineNr >= 0 && !fileName.isEmpty(); }
- };
-
- QHash<int, BreakPoint> m_breakPoints;
- bool m_breakOnThrow;
-};
-
} // namespace Debugging
} // namespace QV4
diff --git a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp
index 78aa113450..ac780d272c 100644
--- a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp
+++ b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp
@@ -93,7 +93,7 @@ signals:
void evaluateFinished();
};
-class TestAgent : public QV4::Debugging::DebuggerAgent
+class TestAgent : public QObject
{
Q_OBJECT
public:
@@ -151,12 +151,14 @@ public:
, m_captureContextInfo(false)
, m_thrownValue(-1)
, collector(engine)
+ , m_debugger(0)
{
}
- virtual void debuggerPaused(Debugger *debugger, PauseReason reason)
+public slots:
+ void debuggerPaused(QV4::Debugging::Debugger *debugger, QV4::Debugging::PauseReason reason)
{
- Q_ASSERT(m_debuggers.count() == 1 && m_debuggers.first() == debugger);
+ Q_ASSERT(debugger == m_debugger);
Q_ASSERT(debugger->engine() == collector.engine());
m_wasPaused = true;
m_pauseReason = reason;
@@ -190,15 +192,7 @@ public:
debugger->resume(Debugger::FullThrottle);
}
- virtual void sourcesCollected(Debugger *debugger, QStringList sources, int requestSequenceNr)
- {
- Q_UNUSED(debugger);
- Q_UNUSED(sources);
- Q_UNUSED(requestSequenceNr);
- }
-
- int debuggerCount() const { return m_debuggers.count(); }
-
+public:
struct TestBreakPoint
{
TestBreakPoint() : lineNumber(-1) {}
@@ -221,6 +215,16 @@ public:
}
}
+ void addDebugger(QV4::Debugging::Debugger *debugger)
+ {
+ Q_ASSERT(!m_debugger);
+ m_debugger = debugger;
+ connect(m_debugger,
+ SIGNAL(debuggerPaused(QV4::Debugging::Debugger*,QV4::Debugging::PauseReason)),
+ this,
+ SLOT(debuggerPaused(QV4::Debugging::Debugger*,QV4::Debugging::PauseReason)));
+ }
+
bool m_wasPaused;
PauseReason m_pauseReason;
bool m_captureContextInfo;
@@ -238,6 +242,7 @@ public:
};
QVector<ExpressionRequest> m_expressionRequests;
QVector<Refs> m_expressionResults;
+ QV4::Debugging::Debugger *m_debugger;
// Utility methods:
void dumpStackTrace() const
@@ -315,7 +320,6 @@ void tst_qv4debugger::cleanup()
delete m_javaScriptThread;
m_engine = 0;
m_v4 = 0;
- QCOMPARE(m_debuggerAgent->debuggerCount(), 0);
delete m_debuggerAgent;
m_debuggerAgent = 0;
}
@@ -326,7 +330,7 @@ void tst_qv4debugger::breakAnywhere()
"var i = 42;\n"
"var j = i + 1\n"
"var k = i\n";
- m_debuggerAgent->pauseAll();
+ m_v4->debugger->pause();
evaluateJavaScript(script, "testFile");
QVERIFY(m_debuggerAgent->m_wasPaused);
}
@@ -337,7 +341,7 @@ void tst_qv4debugger::pendingBreakpoint()
"var i = 42;\n"
"var j = i + 1\n"
"var k = i\n";
- m_debuggerAgent->addBreakPoint("testfile", 2);
+ m_v4->debugger->addBreakPoint("testfile", 2);
evaluateJavaScript(script, "testfile");
QVERIFY(m_debuggerAgent->m_wasPaused);
QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 1);
@@ -353,7 +357,7 @@ void tst_qv4debugger::liveBreakPoint()
"var j = i + 1\n"
"var k = i\n";
m_debuggerAgent->m_breakPointsToAddWhenPaused << TestAgent::TestBreakPoint("liveBreakPoint", 3);
- m_debuggerAgent->pauseAll();
+ m_v4->debugger->pause();
evaluateJavaScript(script, "liveBreakPoint");
QVERIFY(m_debuggerAgent->m_wasPaused);
QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 2);
@@ -368,8 +372,8 @@ void tst_qv4debugger::removePendingBreakPoint()
"var i = 42;\n"
"var j = i + 1\n"
"var k = i\n";
- int id = m_debuggerAgent->addBreakPoint("removePendingBreakPoint", 2);
- m_debuggerAgent->removeBreakPoint(id);
+ m_v4->debugger->addBreakPoint("removePendingBreakPoint", 2);
+ m_v4->debugger->removeBreakPoint("removePendingBreakPoint", 2);
evaluateJavaScript(script, "removePendingBreakPoint");
QVERIFY(!m_debuggerAgent->m_wasPaused);
}
@@ -380,7 +384,7 @@ void tst_qv4debugger::addBreakPointWhilePaused()
"var i = 42;\n"
"var j = i + 1\n"
"var k = i\n";
- m_debuggerAgent->addBreakPoint("addBreakPointWhilePaused", 1);
+ m_v4->debugger->addBreakPoint("addBreakPointWhilePaused", 1);
m_debuggerAgent->m_breakPointsToAddWhenPaused << TestAgent::TestBreakPoint("addBreakPointWhilePaused", 2);
evaluateJavaScript(script, "addBreakPointWhilePaused");
QVERIFY(m_debuggerAgent->m_wasPaused);
@@ -410,7 +414,7 @@ void tst_qv4debugger::removeBreakPointForNextInstruction()
QMetaObject::invokeMethod(m_engine, "injectFunction", Qt::BlockingQueuedConnection,
Q_ARG(QString, "someCall"), Q_ARG(InjectedFunction, someCall));
- m_debuggerAgent->addBreakPoint("removeBreakPointForNextInstruction", 2);
+ m_v4->debugger->addBreakPoint("removeBreakPointForNextInstruction", 2);
evaluateJavaScript(script, "removeBreakPointForNextInstruction");
QVERIFY(!m_debuggerAgent->m_wasPaused);
@@ -427,7 +431,7 @@ void tst_qv4debugger::conditionalBreakPoint()
"}\n"
"test()\n";
- m_debuggerAgent->addBreakPoint("conditionalBreakPoint", 3, /*enabled*/true, QStringLiteral("i > 10"));
+ m_v4->debugger->addBreakPoint("conditionalBreakPoint", 3, QStringLiteral("i > 10"));
evaluateJavaScript(script, "conditionalBreakPoint");
QVERIFY(m_debuggerAgent->m_wasPaused);
QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 4);
@@ -465,7 +469,7 @@ void tst_qv4debugger::conditionalBreakPointInQml()
" }\n"
"}\n", QUrl("test.qml"));
- debuggerAgent->addBreakPoint("test.qml", 7, /*enabled*/true, "root.foo == 42");
+ v4->debugger->addBreakPoint("test.qml", 7, "root.foo == 42");
QScopedPointer<QObject> obj(component.create());
QCOMPARE(obj->property("success").toBool(), true);
@@ -487,7 +491,7 @@ void tst_qv4debugger::readArguments()
"}\n"
"var four;\n"
"f(1, 'two', null, four);\n";
- m_debuggerAgent->addBreakPoint("readArguments", 2);
+ m_v4->debugger->addBreakPoint("readArguments", 2);
evaluateJavaScript(script, "readArguments");
QVERIFY(m_debuggerAgent->m_wasPaused);
QVERIFY(m_debuggerAgent->m_capturedArguments.size() > 1);
@@ -511,7 +515,7 @@ void tst_qv4debugger::readLocals()
" return c === d\n"
"}\n"
"f(1, 2, 3);\n";
- m_debuggerAgent->addBreakPoint("readLocals", 3);
+ m_v4->debugger->addBreakPoint("readLocals", 3);
evaluateJavaScript(script, "readLocals");
QVERIFY(m_debuggerAgent->m_wasPaused);
QVERIFY(m_debuggerAgent->m_capturedLocals.size() > 1);
@@ -533,7 +537,7 @@ void tst_qv4debugger::readObject()
" return b\n"
"}\n"
"f({head: 1, tail: { head: 'asdf', tail: null }});\n";
- m_debuggerAgent->addBreakPoint("readObject", 3);
+ m_v4->debugger->addBreakPoint("readObject", 3);
evaluateJavaScript(script, "readObject");
QVERIFY(m_debuggerAgent->m_wasPaused);
QVERIFY(m_debuggerAgent->m_capturedLocals.size() > 1);
@@ -591,7 +595,7 @@ void tst_qv4debugger::readContextInAllFrames()
" return 1;\n" // breakpoint
"}\n"
"fact(12);\n";
- m_debuggerAgent->addBreakPoint("readFormalsInAllFrames", 7);
+ m_v4->debugger->addBreakPoint("readFormalsInAllFrames", 7);
evaluateJavaScript(script, "readFormalsInAllFrames");
QVERIFY(m_debuggerAgent->m_wasPaused);
QCOMPARE(m_debuggerAgent->m_stackTrace.size(), 13);
@@ -626,7 +630,7 @@ void tst_qv4debugger::pauseOnThrow()
" throw n\n"
"}\n"
"die('hard');\n";
- m_debuggerAgent->setBreakOnThrow(true);
+ m_v4->debugger->setBreakOnThrow(true);
evaluateJavaScript(script, "pauseOnThrow");
QVERIFY(m_debuggerAgent->m_wasPaused);
QCOMPARE(m_debuggerAgent->m_pauseReason, Throwing);
@@ -647,7 +651,7 @@ void tst_qv4debugger::breakInCatch()
" console.log(e, 'me');\n"
"}\n";
- m_debuggerAgent->addBreakPoint("breakInCatch", 4);
+ m_v4->debugger->addBreakPoint("breakInCatch", 4);
evaluateJavaScript(script, "breakInCatch");
QVERIFY(m_debuggerAgent->m_wasPaused);
QCOMPARE(m_debuggerAgent->m_pauseReason, BreakPoint);
@@ -664,7 +668,7 @@ void tst_qv4debugger::breakInWith()
" console.log('give the answer');\n"
"}\n";
- m_debuggerAgent->addBreakPoint("breakInWith", 2);
+ m_v4->debugger->addBreakPoint("breakInWith", 2);
evaluateJavaScript(script, "breakInWith");
QVERIFY(m_debuggerAgent->m_wasPaused);
QCOMPARE(m_debuggerAgent->m_pauseReason, BreakPoint);
@@ -692,7 +696,7 @@ void tst_qv4debugger::evaluateExpression()
request.frameNr = 1;
m_debuggerAgent->m_expressionRequests << request;
- m_debuggerAgent->addBreakPoint("evaluateExpression", 3);
+ m_v4->debugger->addBreakPoint("evaluateExpression", 3);
evaluateJavaScript(script, "evaluateExpression");