From bf5db2bbc1da83a9930832e628e65ec64cd4b831 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 21 Jul 2015 18:56:32 +0200 Subject: Move V4 debugger agent into the debugger plugin The debugger is the only thing that actually needs it. Note that for this to work we need to make QV4::Debugging::Debugger a QObject and add some signals. The net effect is still a reduction in binary size of about 1kb. Change-Id: Ibecb8cfa140fc26fc13c8cbefb3d027ebdcd28a4 Reviewed-by: Erik Verbruggen --- .../qmltooling/qmldbg_debugger/qmldbg_debugger.pro | 6 +- .../qmldbg_debugger/qv4debuggeragent.cpp | 251 +++++++++++++++++++++ .../qmltooling/qmldbg_debugger/qv4debuggeragent.h | 97 ++++++++ .../qmltooling/qmldbg_debugger/qv4debugservice.cpp | 84 ------- .../qmltooling/qmldbg_debugger/qv4debugservice.h | 19 +- 5 files changed, 353 insertions(+), 104 deletions(-) create mode 100644 src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp create mode 100644 src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h (limited to 'src/plugins/qmltooling/qmldbg_debugger') 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 +#include + +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 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(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 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 QV4DebuggerAgent::breakPointIds(const QString &fileName, int lineNumber) const +{ + QList ids; + + for (QHash::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 + +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 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 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 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 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 #include @@ -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 { Q_OBJECT -- cgit v1.2.3