diff options
Diffstat (limited to 'src/plugins/qmltooling/qmldbg_debugger')
21 files changed, 1581 insertions, 730 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.cpp index 6bccec08b1..31873f7915 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.cpp @@ -1,82 +1,85 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qdebugmessageservice.h" +#include "qqmldebugpacket.h" #include <private/qqmldebugconnector_p.h> -#include <QDataStream> - QT_BEGIN_NAMESPACE -const QString QDebugMessageService::s_key = QStringLiteral("DebugMessages"); - void DebugMessageHandler(QtMsgType type, const QMessageLogContext &ctxt, const QString &buf) { - QQmlDebugConnector::service<QDebugMessageService>()->sendDebugMessage(type, ctxt, buf); + QQmlDebugConnector::service<QDebugMessageServiceImpl>()->sendDebugMessage(type, ctxt, buf); } -QDebugMessageService::QDebugMessageService(QObject *parent) : - QQmlDebugService(s_key, 2, parent), oldMsgHandler(0), +QDebugMessageServiceImpl::QDebugMessageServiceImpl(QObject *parent) : + QDebugMessageService(2, parent), oldMsgHandler(0), prevState(QQmlDebugService::NotConnected) { // don't execute stateChanged() in parallel QMutexLocker lock(&initMutex); + timer.start(); if (state() == Enabled) { oldMsgHandler = qInstallMessageHandler(DebugMessageHandler); prevState = Enabled; } } -void QDebugMessageService::sendDebugMessage(QtMsgType type, +void QDebugMessageServiceImpl::sendDebugMessage(QtMsgType type, const QMessageLogContext &ctxt, const QString &buf) { //We do not want to alter the message handling mechanism //We just eavesdrop and forward the messages to a port //only if a client is connected to it. - QByteArray message; - QQmlDebugStream ws(&message, QIODevice::WriteOnly); + QQmlDebugPacket ws; ws << QByteArray("MESSAGE") << type << buf.toUtf8(); - ws << QString::fromLatin1(ctxt.file).toUtf8(); - ws << ctxt.line << QString::fromLatin1(ctxt.function).toUtf8(); + ws << QByteArray(ctxt.file) << ctxt.line << QByteArray(ctxt.function); + ws << QByteArray(ctxt.category) << timer.nsecsElapsed(); - emit messageToClient(name(), message); + emit messageToClient(name(), ws.data()); if (oldMsgHandler) (*oldMsgHandler)(type, ctxt, buf); } -void QDebugMessageService::stateChanged(State state) +void QDebugMessageServiceImpl::stateChanged(State state) { QMutexLocker lock(&initMutex); @@ -93,4 +96,10 @@ void QDebugMessageService::stateChanged(State state) prevState = state; } +void QDebugMessageServiceImpl::synchronizeTime(const QElapsedTimer &otherTimer) +{ + QMutexLocker lock(&initMutex); + timer = otherTimer; +} + QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.h b/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.h index c0dc41bcd0..c25e756c2d 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -45,36 +51,35 @@ // We mean it. // -#include <private/qqmldebugservice_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> #include <QtCore/qlogging.h> #include <QtCore/qmutex.h> +#include <QtCore/qelapsedtimer.h> QT_BEGIN_NAMESPACE class QDebugMessageServicePrivate; -class QDebugMessageService : public QQmlDebugService +class QDebugMessageServiceImpl : public QDebugMessageService { Q_OBJECT public: - QDebugMessageService(QObject *parent = 0); + QDebugMessageServiceImpl(QObject *parent = 0); - void sendDebugMessage(QtMsgType type, const QMessageLogContext &ctxt, - const QString &buf); + void sendDebugMessage(QtMsgType type, const QMessageLogContext &ctxt, const QString &buf); + void synchronizeTime(const QElapsedTimer &otherTimer); protected: - static const QString s_key; - void stateChanged(State); private: - friend class QQmlDebugConnector; friend class QQmlDebuggerServiceFactory; QtMessageHandler oldMsgHandler; QQmlDebugService::State prevState; QMutex initMutex; + QElapsedTimer timer; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro index dc923b2350..27b3a5b513 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro +++ b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro @@ -1,5 +1,5 @@ TARGET = qmldbg_debugger -QT = qml-private core-private +QT = qml-private core-private packetprotocol-private SOURCES += \ $$PWD/qdebugmessageservice.cpp \ @@ -8,19 +8,24 @@ SOURCES += \ $$PWD/qqmlnativedebugservice.cpp \ $$PWD/qqmlwatcher.cpp \ $$PWD/qv4debugservice.cpp \ + $$PWD/qv4debugger.cpp \ $$PWD/qv4debuggeragent.cpp \ - $$PWD/qv4datacollector.cpp + $$PWD/qv4datacollector.cpp \ + $$PWD/qv4debugjob.cpp HEADERS += \ $$PWD/../shared/qqmlconfigurabledebugservice.h \ + $$PWD/../shared/qqmldebugpacket.h \ $$PWD/qdebugmessageservice.h \ $$PWD/qqmldebuggerservicefactory.h \ $$PWD/qqmlenginedebugservice.h \ $$PWD/qqmlnativedebugservice.h \ $$PWD/qqmlwatcher.h \ $$PWD/qv4debugservice.h \ + $$PWD/qv4debugger.h \ $$PWD/qv4debuggeragent.h \ - $$PWD/qv4datacollector.h + $$PWD/qv4datacollector.h \ + $$PWD/qv4debugjob.h INCLUDEPATH += $$PWD \ $$PWD/../shared diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp index f379352cfa..ca3f07323d 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -42,8 +48,8 @@ QT_BEGIN_NAMESPACE QQmlDebugService *QQmlDebuggerServiceFactory::create(const QString &key) { - if (key == QDebugMessageService::s_key) - return new QDebugMessageService(this); + if (key == QDebugMessageServiceImpl::s_key) + return new QDebugMessageServiceImpl(this); if (key == QQmlEngineDebugServiceImpl::s_key) return new QQmlEngineDebugServiceImpl(this); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h index 2c7509ba12..99d6679833 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp index 8f53dc6d50..ff4e30835d 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -33,6 +39,7 @@ #include "qqmlenginedebugservice.h" #include "qqmlwatcher.h" +#include "qqmldebugpacket.h" #include <private/qqmldebugstatesdelegate_p.h> #include <private/qqmlboundsignal_p.h> @@ -89,8 +96,7 @@ QDataStream &operator<<(QDataStream &ds, ds << (int)data.type << data.name; // check first whether the data can be saved // (otherwise we assert in QVariant::operator<<) - QByteArray buffer; - QDataStream fakeStream(&buffer, QIODevice::WriteOnly); + QQmlDebugPacket fakeStream; if (QMetaType::save(fakeStream, data.value.type(), data.value.constData())) ds << data.value; else @@ -427,7 +433,7 @@ QList<QObject*> QQmlEngineDebugServiceImpl::objectForLocationInfo(const QString const QHash<int, QObject *> &hash = objectsForIds(); for (QHash<int, QObject *>::ConstIterator i = hash.constBegin(); i != hash.constEnd(); ++i) { QQmlData *ddata = QQmlData::get(i.value()); - if (ddata && ddata->outerContext) { + if (ddata && ddata->outerContext && ddata->outerContext->isValid()) { if (QFileInfo(ddata->outerContext->urlString()).fileName() == filename && ddata->lineNumber == lineNumber && ddata->columnNumber >= columnNumber) { @@ -440,21 +446,20 @@ QList<QObject*> QQmlEngineDebugServiceImpl::objectForLocationInfo(const QString void QQmlEngineDebugServiceImpl::processMessage(const QByteArray &message) { - QQmlDebugStream ds(message); + QQmlDebugPacket ds(message); QByteArray type; int queryId; ds >> type >> queryId; - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); + QQmlDebugPacket rs; if (type == "LIST_ENGINES") { rs << QByteArray("LIST_ENGINES_R"); rs << queryId << m_engines.count(); for (int ii = 0; ii < m_engines.count(); ++ii) { - QQmlEngine *engine = m_engines.at(ii); + QJSEngine *engine = m_engines.at(ii); QString engineName = engine->objectName(); int engineId = QQmlDebugService::idForObject(engine); @@ -617,7 +622,7 @@ void QQmlEngineDebugServiceImpl::processMessage(const QByteArray &message) rs << QByteArray("SET_METHOD_BODY_R") << queryId << ok; } - emit messageToClient(name(), reply); + emit messageToClient(name(), rs.data()); } bool QQmlEngineDebugServiceImpl::setBinding(int objectId, @@ -678,11 +683,13 @@ bool QQmlEngineDebugServiceImpl::resetBinding(int objectId, const QString &prope QQmlContext *context = qmlContext(object); if (object && context) { - QString parentProperty = propertyName; - if (propertyName.indexOf(QLatin1Char('.')) != -1) - parentProperty = propertyName.left(propertyName.indexOf(QLatin1Char('.'))); + QStringRef parentPropertyRef(&propertyName); + const int idx = parentPropertyRef.indexOf(QLatin1Char('.')); + if (idx != -1) + parentPropertyRef = parentPropertyRef.left(idx); - if (object->property(parentProperty.toLatin1()).isValid()) { + const QByteArray parentProperty = parentPropertyRef.toLatin1(); + if (object->property(parentProperty).isValid()) { QQmlProperty property(object, propertyName); QQmlPropertyPrivate::removeBinding(property); if (property.isResettable()) { @@ -695,7 +702,7 @@ bool QQmlEngineDebugServiceImpl::resetBinding(int objectId, const QString &prope // overwrite with default value if (QQmlType *objType = QQmlMetaType::qmlType(object->metaObject())) { if (QObject *emptyObject = objType->create()) { - if (emptyObject->property(parentProperty.toLatin1()).isValid()) { + if (emptyObject->property(parentProperty).isValid()) { QVariant defaultValue = QQmlProperty(emptyObject, propertyName).read(); if (defaultValue.isValid()) { setBinding(objectId, propertyName, defaultValue, true); @@ -769,15 +776,12 @@ bool QQmlEngineDebugServiceImpl::setMethodBody(int objectId, const QString &meth void QQmlEngineDebugServiceImpl::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value) { - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); - + QQmlDebugPacket rs; rs << QByteArray("UPDATE_WATCH") << id << objectId << QByteArray(property.name()) << valueContents(value); - - emit messageToClient(name(), reply); + emit messageToClient(name(), rs.data()); } -void QQmlEngineDebugServiceImpl::engineAboutToBeAdded(QQmlEngine *engine) +void QQmlEngineDebugServiceImpl::engineAboutToBeAdded(QJSEngine *engine) { Q_ASSERT(engine); Q_ASSERT(!m_engines.contains(engine)); @@ -786,7 +790,7 @@ void QQmlEngineDebugServiceImpl::engineAboutToBeAdded(QQmlEngine *engine) emit attachedToEngine(engine); } -void QQmlEngineDebugServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine) +void QQmlEngineDebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) { Q_ASSERT(engine); Q_ASSERT(m_engines.contains(engine)); @@ -795,7 +799,7 @@ void QQmlEngineDebugServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine) emit detachedFromEngine(engine); } -void QQmlEngineDebugServiceImpl::objectCreated(QQmlEngine *engine, QObject *object) +void QQmlEngineDebugServiceImpl::objectCreated(QJSEngine *engine, QObject *object) { Q_ASSERT(engine); Q_ASSERT(m_engines.contains(engine)); @@ -804,12 +808,11 @@ void QQmlEngineDebugServiceImpl::objectCreated(QQmlEngine *engine, QObject *obje int objectId = QQmlDebugService::idForObject(object); int parentId = QQmlDebugService::idForObject(object->parent()); - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); + QQmlDebugPacket rs; //unique queryId -1 rs << QByteArray("OBJECT_CREATED") << -1 << engineId << objectId << parentId; - emit messageToClient(name(), reply); + emit messageToClient(name(), rs.data()); } void QQmlEngineDebugServiceImpl::setStatesDelegate(QQmlDebugStatesDelegate *delegate) diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h index 68cb420cc0..cb75a63850 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -89,9 +95,9 @@ public: bool hasNotifySignal; }; - void engineAboutToBeAdded(QQmlEngine *) Q_DECL_OVERRIDE; - void engineAboutToBeRemoved(QQmlEngine *) Q_DECL_OVERRIDE; - void objectCreated(QQmlEngine *, QObject *) Q_DECL_OVERRIDE; + void engineAboutToBeAdded(QJSEngine *) Q_DECL_OVERRIDE; + void engineAboutToBeRemoved(QJSEngine *) Q_DECL_OVERRIDE; + void objectCreated(QJSEngine *, QObject *) Q_DECL_OVERRIDE; void setStatesDelegate(QQmlDebugStatesDelegate *) Q_DECL_OVERRIDE; @@ -120,7 +126,7 @@ private: QList<QObject *> objectForLocationInfo(const QString &filename, int lineNumber, int columnNumber); - QList<QQmlEngine *> m_engines; + QList<QJSEngine *> m_engines; QQmlWatcher *m_watch; QQmlDebugStatesDelegate *m_statesDelegate; }; diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp index 24d2a82413..e3b2bc0870 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp @@ -1,37 +1,44 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qqmlnativedebugservice.h" +#include "qqmldebugpacket.h" #include <private/qqmldebugconnector_p.h> #include <private/qv4debugging_p.h> @@ -46,8 +53,7 @@ #include <private/qv4isel_moth_p.h> #include <private/qqmldebugserviceinterfaces_p.h> -#include <qqmlengine.h> - +#include <QtQml/qjsengine.h> #include <QtCore/qjsonarray.h> #include <QtCore/qjsondocument.h> #include <QtCore/qjsonobject.h> @@ -313,16 +319,15 @@ void NativeDebugger::handleCommand(QJsonObject *response, const QString &cmd, static QString encodeContext(QV4::ExecutionContext *executionContext) { - QByteArray ba; - QDataStream ds(&ba, QIODevice::WriteOnly); + QQmlDebugPacket ds; ds << quintptr(executionContext); - return QString::fromLatin1(ba.toHex()); + return QString::fromLatin1(ds.data().toHex()); } static void decodeContext(const QString &context, QV4::ExecutionContext **executionContext) { quintptr rawContext; - QDataStream ds(QByteArray::fromHex(context.toLatin1())); + QQmlDebugPacket ds(QByteArray::fromHex(context.toLatin1())); ds >> rawContext; *executionContext = reinterpret_cast<QV4::ExecutionContext *>(rawContext); } @@ -699,7 +704,7 @@ bool NativeDebugger::reallyHitTheBreakPoint(const QV4::Function *function, int l const BreakPoint &bp = m_service->m_breakHandler->m_breakPoints.at(i); if (bp.lineNumber == lineNumber) { const QString fileName = function->sourceFile(); - const QString base = fileName.mid(fileName.lastIndexOf('/') + 1); + const QStringRef base = fileName.midRef(fileName.lastIndexOf('/') + 1); if (bp.fileName.endsWith(base)) { if (bp.condition.isEmpty() || checkCondition(bp.condition)) { BreakPoint &mbp = m_service->m_breakHandler->m_breakPoints[i]; @@ -724,7 +729,7 @@ QQmlNativeDebugServiceImpl::~QQmlNativeDebugServiceImpl() delete m_breakHandler; } -void QQmlNativeDebugServiceImpl::engineAboutToBeAdded(QQmlEngine *engine) +void QQmlNativeDebugServiceImpl::engineAboutToBeAdded(QJSEngine *engine) { TRACE_PROTOCOL("Adding engine" << engine); if (engine) { @@ -741,7 +746,7 @@ void QQmlNativeDebugServiceImpl::engineAboutToBeAdded(QQmlEngine *engine) QQmlDebugService::engineAboutToBeAdded(engine); } -void QQmlNativeDebugServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine) +void QQmlNativeDebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) { TRACE_PROTOCOL("Removing engine" << engine); if (engine) { diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h index 9d0780a203..8015513f9e 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -68,14 +74,14 @@ class QQmlNativeDebugServiceImpl : public QQmlNativeDebugService public: QQmlNativeDebugServiceImpl(QObject *parent); - ~QQmlNativeDebugServiceImpl(); + ~QQmlNativeDebugServiceImpl() Q_DECL_OVERRIDE; - void engineAboutToBeAdded(QQmlEngine *engine); - void engineAboutToBeRemoved(QQmlEngine *engine); + void engineAboutToBeAdded(QJSEngine *engine) Q_DECL_OVERRIDE; + void engineAboutToBeRemoved(QJSEngine *engine) Q_DECL_OVERRIDE; - void stateAboutToBeChanged(State state); + void stateAboutToBeChanged(State state) Q_DECL_OVERRIDE; - void messageReceived(const QByteArray &message); + void messageReceived(const QByteArray &message) Q_DECL_OVERRIDE; void emitAsynchronousMessageToClient(const QJsonObject &message); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp index 9f9a6eb33b..392080dd51 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.h b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.h index 329aee77d2..4b304a6087 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index adba1dbdd9..96f60b24bb 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -1,37 +1,45 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qv4datacollector.h" +#include "qv4debugger.h" +#include "qv4debugjob.h" #include <private/qv4script_p.h> #include <private/qv4string_p.h> @@ -39,7 +47,11 @@ #include <private/qv4identifier_p.h> #include <private/qv4runtime_p.h> +#include <private/qqmlcontext_p.h> +#include <private/qqmlengine_p.h> + #include <QtCore/qjsonarray.h> +#include <QtCore/qjsonobject.h> QT_BEGIN_NAMESPACE @@ -93,17 +105,13 @@ int QV4DataCollector::encodeScopeType(QV4::Heap::ExecutionContext::ContextType s switch (scopeType) { case QV4::Heap::ExecutionContext::Type_GlobalContext: return 0; - break; case QV4::Heap::ExecutionContext::Type_CatchContext: return 4; - break; case QV4::Heap::ExecutionContext::Type_WithContext: return 2; - break; case QV4::Heap::ExecutionContext::Type_SimpleCallContext: case QV4::Heap::ExecutionContext::Type_CallContext: return 1; - break; case QV4::Heap::ExecutionContext::Type_QmlContext: default: return -1; @@ -112,17 +120,13 @@ int QV4DataCollector::encodeScopeType(QV4::Heap::ExecutionContext::ContextType s QV4DataCollector::QV4DataCollector(QV4::ExecutionEngine *engine) : m_engine(engine) { - values.set(engine, engine->newArrayObject()); -} - -QV4DataCollector::~QV4DataCollector() -{ + m_values.set(engine, engine->newArrayObject()); } QV4DataCollector::Ref QV4DataCollector::collect(const QV4::ScopedValue &value) { Ref ref = addRef(value); - collectedRefs.append(ref); + m_collectedRefs.append(ref); return ref; } @@ -210,8 +214,8 @@ QV4DataCollector::Ref QV4DataCollector::addFunctionRef(const QString &functionNa dict.insert(QStringLiteral("handle"), qint64(ref)); dict.insert(QStringLiteral("type"), QStringLiteral("function")); dict.insert(QStringLiteral("name"), functionName); - specialRefs.insert(ref, dict); - collectedRefs.append(ref); + m_specialRefs.insert(ref, dict); + m_collectedRefs.append(ref); return ref; } @@ -224,8 +228,8 @@ QV4DataCollector::Ref QV4DataCollector::addScriptRef(const QString &scriptName) dict.insert(QStringLiteral("handle"), qint64(ref)); dict.insert(QStringLiteral("type"), QStringLiteral("script")); dict.insert(QStringLiteral("name"), scriptName); - specialRefs.insert(ref, dict); - collectedRefs.append(ref); + m_specialRefs.insert(ref, dict); + m_collectedRefs.append(ref); return ref; } @@ -233,7 +237,7 @@ QV4DataCollector::Ref QV4DataCollector::addScriptRef(const QString &scriptName) bool QV4DataCollector::isValidRef(QV4DataCollector::Ref ref) const { QV4::Scope scope(engine()); - QV4::ScopedObject array(scope, values.value()); + QV4::ScopedObject array(scope, m_values.value()); return ref < array->getLength(); } @@ -268,14 +272,14 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr) QV4::ScopedObject scopeObject(scope, engine()->newObject()); - Q_ASSERT(names.size() == collectedRefs.size()); - for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) + Q_ASSERT(names.size() == m_collectedRefs.size()); + for (int i = 0, ei = m_collectedRefs.size(); i != ei; ++i) scopeObject->put(engine(), names.at(i), - QV4::Value::fromReturnedValue(getValue(collectedRefs.at(i)))); + QV4::Value::fromReturnedValue(getValue(m_collectedRefs.at(i)))); Ref scopeObjectRef = addRef(scopeObject); dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef)); - collectedRefs.append(scopeObjectRef); + m_collectedRefs.append(scopeObjectRef); return true; } @@ -328,6 +332,7 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int scope[QLatin1String("type")] = type; scopes.push_back(scope); } + frame[QLatin1String("scopes")] = scopes; return frame; @@ -336,18 +341,25 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int QJsonArray QV4DataCollector::flushCollectedRefs() { QJsonArray refs; - std::sort(collectedRefs.begin(), collectedRefs.end()); - for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) { - QV4DataCollector::Ref ref = collectedRefs.at(i); - if (i > 0 && ref == collectedRefs.at(i - 1)) + std::sort(m_collectedRefs.begin(), m_collectedRefs.end()); + for (int i = 0, ei = m_collectedRefs.size(); i != ei; ++i) { + QV4DataCollector::Ref ref = m_collectedRefs.at(i); + if (i > 0 && ref == m_collectedRefs.at(i - 1)) continue; refs.append(lookupRef(ref)); } - collectedRefs.clear(); + m_collectedRefs.clear(); return refs; } +void QV4DataCollector::clear() +{ + m_values.set(engine(), engine()->newArrayObject()); + m_collectedRefs.clear(); + m_specialRefs.clear(); +} + QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicate) { class ExceptionStateSaver @@ -368,10 +380,10 @@ QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicat // if we wouldn't do this, the putIndexed won't work. ExceptionStateSaver resetExceptionState(engine()); QV4::Scope scope(engine()); - QV4::ScopedObject array(scope, values.value()); + QV4::ScopedObject array(scope, m_values.value()); if (deduplicate) { for (Ref i = 0; i < array->getLength(); ++i) { - if (array->getIndexed(i) == value.rawValue() && !specialRefs.contains(i)) + if (array->getIndexed(i) == value.rawValue() && !m_specialRefs.contains(i)) return i; } } @@ -384,15 +396,15 @@ QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicat QV4::ReturnedValue QV4DataCollector::getValue(Ref ref) { QV4::Scope scope(engine()); - QV4::ScopedObject array(scope, values.value()); + QV4::ScopedObject array(scope, m_values.value()); Q_ASSERT(ref < array->getLength()); return array->getIndexed(ref, Q_NULLPTR); } bool QV4DataCollector::lookupSpecialRef(Ref ref, QJsonObject *dict) { - SpecialRefs::const_iterator it = specialRefs.find(ref); - if (it == specialRefs.end()) + SpecialRefs::const_iterator it = m_specialRefs.constFind(ref); + if (it == m_specialRefs.cend()) return false; *dict = it.value(); @@ -428,154 +440,11 @@ QJsonObject QV4DataCollector::collectAsJson(const QString &name, const QV4::Scop if (value->isManaged() && !value->isString()) { Ref ref = addRef(value); dict.insert(QStringLiteral("ref"), qint64(ref)); - collectedRefs.append(ref); + m_collectedRefs.append(ref); } collectProperty(value, engine(), dict); return dict; } -BacktraceJob::BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame) : - CollectJob(collector), fromFrame(fromFrame), toFrame(toFrame) -{ -} - -void BacktraceJob::run() -{ - QJsonArray frameArray; - QVector<QV4::StackFrame> frames = collector->engine()->stackTrace(toFrame); - for (int i = fromFrame; i < toFrame && i < frames.size(); ++i) - frameArray.push_back(collector->buildFrame(frames[i], i)); - if (frameArray.isEmpty()) { - result.insert(QStringLiteral("totalFrames"), 0); - } else { - result.insert(QStringLiteral("fromFrame"), fromFrame); - result.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size()); - result.insert(QStringLiteral("frames"), frameArray); - } - collectedRefs = collector->flushCollectedRefs(); -} - -FrameJob::FrameJob(QV4DataCollector *collector, int frameNr) : - CollectJob(collector), frameNr(frameNr), success(false) -{ -} - -void FrameJob::run() -{ - QVector<QV4::StackFrame> frames = collector->engine()->stackTrace(frameNr + 1); - if (frameNr >= frames.length()) { - success = false; - } else { - result = collector->buildFrame(frames[frameNr], frameNr); - collectedRefs = collector->flushCollectedRefs(); - success = true; - } -} - -bool FrameJob::wasSuccessful() const -{ - return success; -} - -ScopeJob::ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr) : - CollectJob(collector), frameNr(frameNr), scopeNr(scopeNr), success(false) -{ -} - -void ScopeJob::run() -{ - QJsonObject object; - success = collector->collectScope(&object, frameNr, scopeNr); - - if (success) { - QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = - collector->getScopeTypes(frameNr); - result[QLatin1String("type")] = QV4DataCollector::encodeScopeType(scopeTypes[scopeNr]); - } else { - result[QLatin1String("type")] = -1; - } - result[QLatin1String("index")] = scopeNr; - result[QLatin1String("frameIndex")] = frameNr; - result[QLatin1String("object")] = object; - collectedRefs = collector->flushCollectedRefs(); -} - -bool ScopeJob::wasSuccessful() const -{ - return success; -} - -ValueLookupJob::ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector) : - CollectJob(collector), handles(handles) {} - -void ValueLookupJob::run() -{ - foreach (const QJsonValue &handle, handles) { - QV4DataCollector::Ref ref = handle.toInt(); - if (!collector->isValidRef(ref)) { - exception = QString::fromLatin1("Invalid Ref: %1").arg(ref); - break; - } - result[QString::number(ref)] = collector->lookupRef(ref); - } - collectedRefs = collector->flushCollectedRefs(); -} - -const QString &ValueLookupJob::exceptionMessage() const -{ - return exception; -} - -ExpressionEvalJob::ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, - const QString &expression, - QV4DataCollector *collector) - : JavaScriptJob(engine, frameNr, expression) - , collector(collector) -{ -} - -void ExpressionEvalJob::handleResult(QV4::ScopedValue &value) -{ - if (hasExeption()) - exception = value->toQStringNoThrow(); - result = collector->lookupRef(collector->collect(value)); - collectedRefs = collector->flushCollectedRefs(); -} - -const QString &ExpressionEvalJob::exceptionMessage() const -{ - return exception; -} - -const QJsonObject &ExpressionEvalJob::returnValue() const -{ - return result; -} - -const QJsonArray &ExpressionEvalJob::refs() const -{ - return collectedRefs; -} - -GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine, int seq) - : engine(engine) - , seq(seq) -{} - -void GatherSourcesJob::run() -{ - QStringList sources; - - foreach (QV4::CompiledData::CompilationUnit *unit, engine->compilationUnits) { - QString fileName = unit->fileName(); - if (!fileName.isEmpty()) - sources.append(fileName); - } - - QV4::Debugging::V4Debugger *debugger - = static_cast<QV4::Debugging::V4Debugger *>(engine->debugger); - emit debugger->sourcesCollected(debugger, sources, seq); -} - QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h index acc3a6022e..fd6356f22e 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -35,40 +41,44 @@ #define QV4DATACOLLECTOR_H #include <private/qv4engine_p.h> -#include <private/qv4debugging_p.h> +#include <private/qv4persistent_p.h> + +#include <QtCore/QJsonObject> +#include <QtCore/QJsonArray> #include <QtCore/QJsonObject> #include <QtCore/QJsonArray> QT_BEGIN_NAMESPACE +class QV4Debugger; class QV4DataCollector { public: typedef uint Ref; typedef QVector<uint> Refs; - static const Ref s_invalidRef; - QV4::CallContext *findContext(int frame); static QV4::Heap::CallContext *findScope(QV4::ExecutionContext *ctxt, int scope); - QVector<QV4::Heap::ExecutionContext::ContextType> getScopeTypes(int frame); static int encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType); + QVector<QV4::Heap::ExecutionContext::ContextType> getScopeTypes(int frame); + QV4::CallContext *findContext(int frame); + QV4DataCollector(QV4::ExecutionEngine *engine); - ~QV4DataCollector(); Ref collect(const QV4::ScopedValue &value); - bool isValidRef(Ref ref) const; - QJsonObject lookupRef(Ref ref); - Ref addFunctionRef(const QString &functionName); Ref addScriptRef(const QString &scriptName); + bool isValidRef(Ref ref) const; + QJsonObject lookupRef(Ref ref); + bool collectScope(QJsonObject *dict, int frameNr, int scopeNr); QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr); QV4::ExecutionEngine *engine() const { return m_engine; } QJsonArray flushCollectedRefs(); + void clear(); private: Ref addRef(QV4::Value value, bool deduplicate = true); @@ -80,91 +90,10 @@ private: void collectArgumentsInContext(); QV4::ExecutionEngine *m_engine; - Refs collectedRefs; - QV4::PersistentValue values; + Refs m_collectedRefs; + QV4::PersistentValue m_values; typedef QHash<Ref, QJsonObject> SpecialRefs; - SpecialRefs specialRefs; -}; - -class CollectJob : public QV4::Debugging::V4Debugger::Job -{ -protected: - QV4DataCollector *collector; - QJsonObject result; - QJsonArray collectedRefs; -public: - CollectJob(QV4DataCollector *collector) : collector(collector) {} - const QJsonObject &returnValue() const { return result; } - const QJsonArray &refs() const { return collectedRefs; } -}; - -class BacktraceJob: public CollectJob -{ - int fromFrame; - int toFrame; -public: - BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame); - void run(); -}; - -class FrameJob: public CollectJob -{ - int frameNr; - bool success; - -public: - FrameJob(QV4DataCollector *collector, int frameNr); - void run(); - bool wasSuccessful() const; -}; - -class ScopeJob: public CollectJob -{ - int frameNr; - int scopeNr; - bool success; - -public: - ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr); - void run(); - bool wasSuccessful() const; -}; - -class ValueLookupJob: public CollectJob -{ - const QJsonArray handles; - QString exception; - -public: - ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector); - void run(); - const QString &exceptionMessage() const; -}; - -class ExpressionEvalJob: public QV4::Debugging::V4Debugger::JavaScriptJob -{ - QV4DataCollector *collector; - QString exception; - QJsonObject result; - QJsonArray collectedRefs; - -public: - ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression, - QV4DataCollector *collector); - virtual void handleResult(QV4::ScopedValue &value); - const QString &exceptionMessage() const; - const QJsonObject &returnValue() const; - const QJsonArray &refs() const; -}; - -class GatherSourcesJob: public QV4::Debugging::V4Debugger::Job -{ - QV4::ExecutionEngine *engine; - const int seq; - -public: - GatherSourcesJob(QV4::ExecutionEngine *engine, int seq); - void run(); + SpecialRefs m_specialRefs; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp new file mode 100644 index 0000000000..53f2eab5ff --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp @@ -0,0 +1,328 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qv4debugger.h" +#include "qv4debugjob.h" +#include "qv4datacollector.h" + +#include <private/qv4scopedvalue_p.h> +#include <private/qv4script_p.h> +#include <private/qqmlcontext_p.h> +#include <private/qqmlengine_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::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) + , m_collector(engine) +{ + 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; +} + +const QV4DataCollector *QV4Debugger::collector() const +{ + return &m_collector; +} + +QV4DataCollector *QV4Debugger::collector() +{ + return &m_collector; +} + +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; +} + +void QV4Debugger::clearPauseRequest() +{ + QMutexLocker locker(&m_lock); + m_pauseRequested = false; +} + +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::runJobUnpaused() +{ + QMutexLocker locker(&m_lock); + if (m_runningJob) + m_runningJob->run(); + m_jobIsRunning.wakeAll(); +} + +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(QV4DebugJob *job) +{ + QMutexLocker locker(&m_lock); + runInEngine_havingLock(job); +} + +void QV4Debugger::runInEngine_havingLock(QV4DebugJob *job) +{ + Q_ASSERT(job); + Q_ASSERT(m_runningJob == 0); + + m_runningJob = job; + if (state() == Paused) + m_runningCondition.wakeAll(); + else + QMetaObject::invokeMethod(this, "runJobUnpaused", Qt::QueuedConnection); + m_jobIsRunning.wait(&m_lock); + m_runningJob = 0; +} + +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..3a5b6080cb --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $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 "qv4datacollector.h" +#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 QV4DebugJob; +class QV4DataCollector; +class QV4Debugger : public QV4::Debugging::Debugger +{ + Q_OBJECT +public: + struct BreakPoint { + BreakPoint(const QString &fileName, int line); + QString fileName; + int lineNumber; + }; + + 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; + const QV4DataCollector *collector() const; + QV4DataCollector *collector(); + + 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); + + void clearPauseRequest(); + + // 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(QV4DebugJob *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 slots: + void runJobUnpaused(); + +private: + // requires lock to be held + void pauseAndWait(PauseReason reason); + bool reallyHitTheBreakPoint(const QString &filename, int linenr); + void runInEngine_havingLock(QV4DebugJob *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; + + QV4DebugJob *m_gatherSources; + QV4DebugJob *m_runningJob; + QV4DataCollector m_collector; + 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 e33595c629..a90d03b010 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -44,38 +50,34 @@ QV4DebuggerAgent::QV4DebuggerAgent(QV4DebugServiceImpl *debugService) : m_breakOnThrow(false), m_debugService(debugService) {} -QV4::Debugging::V4Debugger *QV4DebuggerAgent::firstDebugger() const +QV4Debugger *QV4DebuggerAgent::pausedDebugger() const { - // Currently only 1 single engine is supported, so: - if (m_debuggers.isEmpty()) - return 0; - else - return m_debuggers.first(); + foreach (QV4Debugger *debugger, m_debuggers) { + if (debugger->state() == QV4Debugger::Paused) + return debugger; + } + return 0; } 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; - else - return false; + // "running" means none of the engines are paused. + return pausedDebugger() == 0; } -void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::V4Debugger *debugger, - QV4::Debugging::PauseReason reason) +void QV4DebuggerAgent::debuggerPaused(QV4Debugger *debugger, QV4Debugger::PauseReason reason) { Q_UNUSED(reason); - m_debugService->clearHandles(debugger->engine()); + debugger->collector()->clear(); QJsonObject event, body, script; 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 +94,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,28 +107,7 @@ void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::V4Debugger *debugger, m_debugService->send(event); } -void QV4DebuggerAgent::sourcesCollected(QV4::Debugging::V4Debugger *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::V4Debugger::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::V4Debugger *debugger) +void QV4DebuggerAgent::addDebugger(QV4Debugger *debugger) { Q_ASSERT(!m_debuggers.contains(debugger)); m_debuggers << debugger; @@ -137,57 +118,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(sourcesCollected(QV4::Debugging::V4Debugger*,QStringList,int)), - this, SLOT(sourcesCollected(QV4::Debugging::V4Debugger*,QStringList,int)), - Qt::QueuedConnection); - 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(sourcesCollected(QV4::Debugging::V4Debugger*,QStringList,int)), - this, SLOT(sourcesCollected(QV4::Debugging::V4Debugger*,QStringList,int))); - 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<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(); @@ -204,15 +178,14 @@ 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); } void QV4DebuggerAgent::removeAllBreakPoints() { - QList<int> ids = m_breakPoints.keys(); - foreach (int id, ids) - removeBreakPoint(id); + for (auto it = m_breakPoints.keyBegin(), end = m_breakPoints.keyEnd(); it != end; ++it) + removeBreakPoint(*it); } void QV4DebuggerAgent::enableBreakPoint(int id, bool onoff) @@ -222,7 +195,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 @@ -245,9 +218,15 @@ 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); } } +void QV4DebuggerAgent::clearAllPauseRequests() +{ + foreach (QV4Debugger *debugger, m_debuggers) + debugger->clearPauseRequest(); +} + QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h index eafb408e7a..1c7eb50ac7 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -34,7 +40,7 @@ #ifndef QV4DEBUGGERAGENT_H #define QV4DEBUGGERAGENT_H -#include <private/qv4debugging_p.h> +#include "qv4debugger.h" QT_BEGIN_NAMESPACE @@ -46,13 +52,14 @@ class QV4DebuggerAgent : public QObject public: QV4DebuggerAgent(QV4DebugServiceImpl *m_debugService); - QV4::Debugging::V4Debugger *firstDebugger() const; + QV4Debugger *pausedDebugger() const; bool isRunning() const; - void addDebugger(QV4::Debugging::V4Debugger *debugger); - void removeDebugger(QV4::Debugging::V4Debugger *debugger); + 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()); @@ -63,15 +70,14 @@ public: bool breakOnThrow() const { return m_breakOnThrow; } void setBreakOnThrow(bool onoff); + void clearAllPauseRequests(); public slots: - void debuggerPaused(QV4::Debugging::V4Debugger *debugger, QV4::Debugging::PauseReason reason); - void sourcesCollected(QV4::Debugging::V4Debugger *debugger, const QStringList &sources, - int requestSequenceNr); + 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/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp new file mode 100644 index 0000000000..a2d2fff72b --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp @@ -0,0 +1,287 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qv4debugjob.h" + +#include <private/qv4script_p.h> +#include <private/qqmlcontext_p.h> +#include <private/qv4qobjectwrapper_p.h> + +#include <QtQml/qqmlengine.h> + +QT_BEGIN_NAMESPACE + +QV4DebugJob::~QV4DebugJob() +{ +} + +JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, + const QString &script) : + engine(engine), frameNr(frameNr), script(script), resultIsException(false) +{} + +void JavaScriptJob::run() +{ + QV4::Scope scope(engine); + + QV4::ExecutionContextSaver saver(scope); + + QV4::ExecutionContext *ctx = engine->currentContext; + QObject scopeObject; + if (frameNr < 0) { // Use QML context if available + QQmlEngine *qmlEngine = engine->qmlEngine(); + if (qmlEngine) { + QQmlContext *qmlRootContext = qmlEngine->rootContext(); + QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(qmlRootContext); + + QV4::ScopedObject withContext(scope, engine->newObject()); + for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) { + QObject *object = ctxtPriv->instances.at(ii); + if (QQmlContext *context = qmlContext(object)) { + if (QQmlContextData *cdata = QQmlContextData::get(context)) { + QV4::ScopedValue v(scope, QV4::QObjectWrapper::wrap(engine, object)); + withContext->put(engine, cdata->findObjectId(object), v); + } + } + } + if (!engine->qmlContext()) { + engine->pushContext(ctx->newQmlContext(QQmlContextData::get(qmlRootContext), + &scopeObject)); + ctx = engine->currentContext; + } + engine->pushContext(ctx->newWithContext(withContext->toObject(engine))); + ctx = engine->currentContext; + } + } else { + if (frameNr > 0) { + for (int i = 0; i < frameNr; ++i) { + ctx = engine->parentContext(ctx); + } + engine->pushContext(ctx); + } + } + + QV4::Script script(ctx, this->script); + script.strictMode = ctx->d()->strictMode; + // In order for property lookups in QML to work, we need to disable fast v4 lookups. That + // is a side-effect of inheritContext. + script.inheritContext = true; + script.parse(); + QV4::ScopedValue result(scope); + if (!scope.engine->hasException) + result = script.run(); + if (scope.engine->hasException) { + result = scope.engine->catchException(); + resultIsException = true; + } + handleResult(result); +} + +bool JavaScriptJob::hasExeption() const +{ + return resultIsException; +} + +BacktraceJob::BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame) : + CollectJob(collector), fromFrame(fromFrame), toFrame(toFrame) +{ +} + +void BacktraceJob::run() +{ + QJsonArray frameArray; + QVector<QV4::StackFrame> frames = collector->engine()->stackTrace(toFrame); + for (int i = fromFrame; i < toFrame && i < frames.size(); ++i) + frameArray.push_back(collector->buildFrame(frames[i], i)); + if (frameArray.isEmpty()) { + result.insert(QStringLiteral("totalFrames"), 0); + } else { + result.insert(QStringLiteral("fromFrame"), fromFrame); + result.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size()); + result.insert(QStringLiteral("frames"), frameArray); + } + collectedRefs = collector->flushCollectedRefs(); +} + +FrameJob::FrameJob(QV4DataCollector *collector, int frameNr) : + CollectJob(collector), frameNr(frameNr), success(false) +{ +} + +void FrameJob::run() +{ + QVector<QV4::StackFrame> frames = collector->engine()->stackTrace(frameNr + 1); + if (frameNr >= frames.length()) { + success = false; + } else { + result = collector->buildFrame(frames[frameNr], frameNr); + collectedRefs = collector->flushCollectedRefs(); + success = true; + } +} + +bool FrameJob::wasSuccessful() const +{ + return success; +} + +ScopeJob::ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr) : + CollectJob(collector), frameNr(frameNr), scopeNr(scopeNr), success(false) +{ +} + +void ScopeJob::run() +{ + QJsonObject object; + success = collector->collectScope(&object, frameNr, scopeNr); + + if (success) { + QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = + collector->getScopeTypes(frameNr); + result[QLatin1String("type")] = QV4DataCollector::encodeScopeType(scopeTypes[scopeNr]); + } else { + result[QLatin1String("type")] = -1; + } + result[QLatin1String("index")] = scopeNr; + result[QLatin1String("frameIndex")] = frameNr; + result[QLatin1String("object")] = object; + collectedRefs = collector->flushCollectedRefs(); +} + +bool ScopeJob::wasSuccessful() const +{ + return success; +} + +ValueLookupJob::ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector) : + CollectJob(collector), handles(handles) {} + +void ValueLookupJob::run() +{ + // Open a QML context if we don't have one, yet. We might run into QML objects when looking up + // refs and that will crash without a valid QML context. Mind that engine->qmlContext() is only + // set if the engine is currently executing QML code. + QScopedPointer<QObject> scopeObject; + QV4::ExecutionEngine *engine = collector->engine(); + if (engine->qmlEngine() && !engine->qmlContext()) { + scopeObject.reset(new QObject); + engine->pushContext(engine->currentContext->newQmlContext( + QQmlContextData::get(engine->qmlEngine()->rootContext()), + scopeObject.data())); + } + foreach (const QJsonValue &handle, handles) { + QV4DataCollector::Ref ref = handle.toInt(); + if (!collector->isValidRef(ref)) { + exception = QString::fromLatin1("Invalid Ref: %1").arg(ref); + break; + } + result[QString::number(ref)] = collector->lookupRef(ref); + } + collectedRefs = collector->flushCollectedRefs(); + if (scopeObject) + engine->popContext(); +} + +const QString &ValueLookupJob::exceptionMessage() const +{ + return exception; +} + +ExpressionEvalJob::ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, + const QString &expression, QV4DataCollector *collector) : + JavaScriptJob(engine, frameNr, expression), collector(collector) +{ +} + +void ExpressionEvalJob::handleResult(QV4::ScopedValue &value) +{ + if (hasExeption()) + exception = value->toQStringNoThrow(); + result = collector->lookupRef(collector->collect(value)); + collectedRefs = collector->flushCollectedRefs(); +} + +const QString &ExpressionEvalJob::exceptionMessage() const +{ + return exception; +} + +const QJsonObject &ExpressionEvalJob::returnValue() const +{ + return result; +} + +const QJsonArray &ExpressionEvalJob::refs() const +{ + return collectedRefs; +} + +GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine) + : engine(engine) +{} + +void GatherSourcesJob::run() +{ + foreach (QV4::CompiledData::CompilationUnit *unit, engine->compilationUnits) { + QString fileName = unit->fileName(); + if (!fileName.isEmpty()) + sources.append(fileName); + } +} + +const QStringList &GatherSourcesJob::result() const +{ + return sources; +} + +EvalJob::EvalJob(QV4::ExecutionEngine *engine, const QString &script) : + JavaScriptJob(engine, /*frameNr*/-1, script), result(false) +{} + +void EvalJob::handleResult(QV4::ScopedValue &result) +{ + this->result = result->toBoolean(); +} + +bool EvalJob::resultAsBoolean() const +{ + return result; +} + +QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h new file mode 100644 index 0000000000..721f42b7c2 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QV4DEBUGJOB_H +#define QV4DEBUGJOB_H + +#include "qv4datacollector.h" +#include <private/qv4engine_p.h> + +#include <QtCore/qjsonarray.h> +#include <QtCore/qjsonobject.h> + +QT_BEGIN_NAMESPACE + +class QV4DataCollector; +class QV4DebugJob +{ +public: + virtual ~QV4DebugJob(); + virtual void run() = 0; +}; + +class JavaScriptJob : public QV4DebugJob +{ + QV4::ExecutionEngine *engine; + int frameNr; + const QString &script; + bool resultIsException; + +public: + JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, const QString &script); + void run(); + bool hasExeption() const; + +protected: + virtual void handleResult(QV4::ScopedValue &result) = 0; +}; + +class CollectJob : public QV4DebugJob +{ +protected: + QV4DataCollector *collector; + QJsonObject result; + QJsonArray collectedRefs; +public: + CollectJob(QV4DataCollector *collector) : collector(collector) {} + const QJsonObject &returnValue() const { return result; } + const QJsonArray &refs() const { return collectedRefs; } +}; + +class BacktraceJob: public CollectJob +{ + int fromFrame; + int toFrame; +public: + BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame); + void run(); +}; + +class FrameJob: public CollectJob +{ + int frameNr; + bool success; + +public: + FrameJob(QV4DataCollector *collector, int frameNr); + void run(); + bool wasSuccessful() const; +}; + +class ScopeJob: public CollectJob +{ + int frameNr; + int scopeNr; + bool success; + +public: + ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr); + void run(); + bool wasSuccessful() const; +}; + +class ValueLookupJob: public CollectJob +{ + const QJsonArray handles; + QString exception; + +public: + ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector); + void run(); + const QString &exceptionMessage() const; +}; + +class ExpressionEvalJob: public JavaScriptJob +{ + QV4DataCollector *collector; + QString exception; + QJsonObject result; + QJsonArray collectedRefs; + +public: + ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression, + QV4DataCollector *collector); + virtual void handleResult(QV4::ScopedValue &value); + const QString &exceptionMessage() const; + const QJsonObject &returnValue() const; + const QJsonArray &refs() const; +}; + +class GatherSourcesJob: public QV4DebugJob +{ + QV4::ExecutionEngine *engine; + QStringList sources; + +public: + GatherSourcesJob(QV4::ExecutionEngine *engine); + void run(); + const QStringList &result() const; +}; + +class EvalJob: public JavaScriptJob +{ + bool result; + +public: + EvalJob(QV4::ExecutionEngine *engine, const QString &script); + + virtual void handleResult(QV4::ScopedValue &result); + bool resultAsBoolean() const; +}; + +QT_END_NAMESPACE + +#endif // QV4DEBUGJOB_H + diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp index 7a9d4a66a4..5ee9e5e9e9 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp @@ -1,43 +1,51 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qv4debugservice.h" +#include "qv4debugjob.h" #include "qqmlengine.h" +#include "qqmldebugpacket.h" + #include <private/qv4engine_p.h> #include <private/qv4isel_moth_p.h> #include <private/qv4function_p.h> #include <private/qqmldebugconnector_p.h> - #include <private/qv8engine_p.h> #include <QtCore/QJsonArray> @@ -63,7 +71,6 @@ QT_BEGIN_NAMESPACE class V8CommandHandler; class UnknownV8CommandHandler; -int QV4DebugServiceImpl::debuggerIndex = 0; int QV4DebugServiceImpl::sequence = 0; class V8CommandHandler @@ -104,7 +111,7 @@ protected: void addCommand() { response.insert(QStringLiteral("command"), cmd); } void addRequestSequence() { response.insert(QStringLiteral("request_seq"), seq); } void addSuccess(bool success) { response.insert(QStringLiteral("success"), success); } - void addBody(const QJsonObject &body) + void addBody(const QJsonValue &body) { response.insert(QStringLiteral("body"), body); } @@ -169,6 +176,7 @@ public: QJsonObject body; body.insert(QStringLiteral("V8Version"), QLatin1String("this is not V8, this is V4 in Qt " QT_VERSION_STR)); + body.insert(QStringLiteral("UnpausedEvaluate"), true); addBody(body); } }; @@ -271,8 +279,14 @@ public: int toFrame = arguments.value(QStringLiteral("toFrame")).toInt(fromFrame + 10); // no idea what the bottom property is for, so we'll ignore it. - BacktraceJob job(debugService->collector(), fromFrame, toFrame); - debugService->debuggerAgent.firstDebugger()->runInEngine(&job); + QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); + if (!debugger) { + createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve backtraces.")); + return; + } + + BacktraceJob job(debugger->collector(), fromFrame, toFrame); + debugger->runInEngine(&job); // response: addCommand(); @@ -296,13 +310,19 @@ public: const int frameNr = arguments.value(QStringLiteral("number")).toInt( debugService->selectedFrame()); + QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); + if (!debugger) { + createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve frames.")); + return; + } + if (frameNr < 0) { createErrorResponse(QStringLiteral("frame command has invalid frame number")); return; } - FrameJob job(debugService->collector(), frameNr); - debugService->debuggerAgent.firstDebugger()->runInEngine(&job); + FrameJob job(debugger->collector(), frameNr); + debugger->runInEngine(&job); if (!job.wasSuccessful()) { createErrorResponse(QStringLiteral("frame retrieval failed")); return; @@ -333,6 +353,12 @@ public: debugService->selectedFrame()); const int scopeNr = arguments.value(QStringLiteral("number")).toInt(0); + QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); + if (!debugger) { + createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve scope.")); + return; + } + if (frameNr < 0) { createErrorResponse(QStringLiteral("scope command has invalid frame number")); return; @@ -342,8 +368,8 @@ public: return; } - ScopeJob job(debugService->collector(), frameNr, scopeNr); - debugService->debuggerAgent.firstDebugger()->runInEngine(&job); + ScopeJob job(debugger->collector(), frameNr, scopeNr); + debugger->runInEngine(&job); if (!job.wasSuccessful()) { createErrorResponse(QStringLiteral("scope retrieval failed")); return; @@ -370,8 +396,21 @@ public: QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); QJsonArray handles = arguments.value(QStringLiteral("handles")).toArray(); - ValueLookupJob job(handles, debugService->collector()); - debugService->debuggerAgent.firstDebugger()->runInEngine(&job); + QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); + if (!debugger) { + const QList<QV4Debugger *> &debuggers = debugService->debuggerAgent.debuggers(); + if (debuggers.count() > 1) { + createErrorResponse(QStringLiteral("Cannot lookup values if multiple debuggers are running and none is paused")); + return; + } else if (debuggers.count() == 0) { + createErrorResponse(QStringLiteral("No debuggers available to lookup values")); + return; + } + debugger = debuggers.first(); + } + + ValueLookupJob job(handles, debugger->collector()); + debugger->runInEngine(&job); if (!job.exceptionMessage().isEmpty()) { createErrorResponse(job.exceptionMessage()); } else { @@ -396,10 +435,15 @@ public: // decypher the payload: QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger(); + QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); + if (!debugger) { + createErrorResponse(QStringLiteral("Debugger has to be paused in order to continue.")); + return; + } + debugService->debuggerAgent.clearAllPauseRequests(); 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(); @@ -408,11 +452,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; @@ -504,11 +548,28 @@ public: } // do it: - QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger(); - GatherSourcesJob job(debugger->engine(), requestSequenceNr()); + QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); + if (!debugger) { + createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve scripts.")); + return; + } + + GatherSourcesJob job(debugger->engine()); debugger->runInEngine(&job); - // response will be send by + QJsonArray body; + foreach (const QString &source, job.result()) { + QJsonObject src; + src[QLatin1String("name")] = source; + src[QLatin1String("scriptType")] = 4; + body.append(src); + } + + addSuccess(true); + addRunning(); + addBody(body); + addCommand(); + addRequestSequence(); } }; @@ -547,27 +608,36 @@ public: virtual void handleRequest() { - QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger(); - if (debugger->state() == QV4::Debugging::V4Debugger::Paused) { - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - QString expression = arguments.value(QStringLiteral("expression")).toString(); - const int frame = arguments.value(QStringLiteral("frame")).toInt(0); - - QV4DataCollector *collector = debugService->collector(); - ExpressionEvalJob job(debugger->engine(), frame, expression, collector); - debugger->runInEngine(&job); - if (job.hasExeption()) { - createErrorResponse(job.exceptionMessage()); - } else { - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - addBody(job.returnValue()); - addRefs(job.refs()); + QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); + QString expression = arguments.value(QStringLiteral("expression")).toString(); + int frame = -1; + + QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); + if (!debugger) { + const QList<QV4Debugger *> &debuggers = debugService->debuggerAgent.debuggers(); + if (debuggers.count() > 1) { + createErrorResponse(QStringLiteral("Cannot evaluate expressions if multiple debuggers are running and none is paused")); + return; + } else if (debuggers.count() == 0) { + createErrorResponse(QStringLiteral("No debuggers available to evaluate expressions")); + return; } + debugger = debuggers.first(); } else { - createErrorResponse(QStringLiteral("Debugger has to be paused for evaluate to work.")); + frame = arguments.value(QStringLiteral("frame")).toInt(0); + } + + ExpressionEvalJob job(debugger->engine(), frame, expression, debugger->collector()); + debugger->runInEngine(&job); + if (job.hasExeption()) { + createErrorResponse(job.exceptionMessage()); + } else { + addCommand(); + addRequestSequence(); + addSuccess(true); + addRunning(); + addBody(job.returnValue()); + addRefs(job.refs()); } } }; @@ -589,7 +659,7 @@ V8CommandHandler *QV4DebugServiceImpl::v8CommandHandler(const QString &command) QV4DebugServiceImpl::QV4DebugServiceImpl(QObject *parent) : QQmlConfigurableDebugService<QV4DebugService>(1, parent), - debuggerAgent(this), version(1), theSelectedFrame(0), + debuggerAgent(this), theSelectedFrame(0), unknownV8CommandHandler(new UnknownV8CommandHandler) { addHandler(new V8VersionRequest); @@ -611,7 +681,7 @@ QV4DebugServiceImpl::~QV4DebugServiceImpl() qDeleteAll(handlers); } -void QV4DebugServiceImpl::engineAdded(QQmlEngine *engine) +void QV4DebugServiceImpl::engineAdded(QJSEngine *engine) { QMutexLocker lock(&m_configMutex); if (engine) { @@ -619,10 +689,9 @@ void QV4DebugServiceImpl::engineAdded(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); - debuggerMap.insert(debuggerIndex++, debugger); debuggerAgent.addDebugger(debugger); debuggerAgent.moveToThread(server->thread()); } @@ -631,25 +700,15 @@ void QV4DebugServiceImpl::engineAdded(QQmlEngine *engine) QQmlConfigurableDebugService<QV4DebugService>::engineAdded(engine); } -void QV4DebugServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine) +void QV4DebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) { QMutexLocker lock(&m_configMutex); if (engine){ const QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle()); if (ee) { - QV4::Debugging::V4Debugger *debugger - = qobject_cast<QV4::Debugging::V4Debugger *>(ee->debugger); - if (debugger) { - typedef QMap<int, QV4::Debugging::V4Debugger *>::const_iterator DebuggerMapIterator; - const DebuggerMapIterator end = debuggerMap.constEnd(); - for (DebuggerMapIterator i = debuggerMap.constBegin(); i != end; ++i) { - if (i.value() == debugger) { - debuggerMap.remove(i.key()); - break; - } - } + QV4Debugger *debugger = qobject_cast<QV4Debugger *>(ee->debugger); + if (debugger) debuggerAgent.removeDebugger(debugger); - } } } QQmlConfigurableDebugService<QV4DebugService>::engineAboutToBeRemoved(engine); @@ -659,12 +718,10 @@ void QV4DebugServiceImpl::stateAboutToBeChanged(State state) { QMutexLocker lock(&m_configMutex); if (state == Enabled) { - typedef QMap<int, QV4::Debugging::V4Debugger *>::const_iterator DebuggerMapIterator; - const DebuggerMapIterator end = debuggerMap.constEnd(); - for (DebuggerMapIterator i = debuggerMap.constBegin(); i != end; ++i) { - QV4::ExecutionEngine *ee = i.value()->engine(); + foreach (QV4Debugger *debugger, debuggerAgent.debuggers()) { + QV4::ExecutionEngine *ee = debugger->engine(); if (!ee->debugger) - ee->setDebugger(i.value()); + ee->setDebugger(debugger); } } QQmlConfigurableDebugService<QV4DebugService>::stateAboutToBeChanged(state); @@ -692,7 +749,7 @@ void QV4DebugServiceImpl::messageReceived(const QByteArray &message) { QMutexLocker lock(&m_configMutex); - QQmlDebugStream ms(message); + QQmlDebugPacket ms(message); QByteArray header; ms >> header; @@ -733,11 +790,10 @@ void QV4DebugServiceImpl::messageReceived(const QByteArray &message) void QV4DebugServiceImpl::sendSomethingToSomebody(const char *type, int magicNumber) { - QByteArray response; - QQmlDebugStream rs(&response, QIODevice::WriteOnly); + QQmlDebugPacket rs; rs << QByteArray(type) - << QByteArray::number(version) << QByteArray::number(magicNumber); - emit messageToClient(name(), packMessage(type, response)); + << QByteArray::number(int(version())) << QByteArray::number(magicNumber); + emit messageToClient(name(), packMessage(type, rs.data())); } void QV4DebugServiceImpl::handleV8Request(const QByteArray &payload) @@ -757,11 +813,10 @@ void QV4DebugServiceImpl::handleV8Request(const QByteArray &payload) QByteArray QV4DebugServiceImpl::packMessage(const QByteArray &command, const QByteArray &message) { - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); + QQmlDebugPacket rs; static const QByteArray cmd("V8DEBUG"); rs << cmd << command << message; - return reply; + return rs.data(); } void QV4DebugServiceImpl::send(QJsonObject v8Payload) @@ -780,16 +835,6 @@ void QV4DebugServiceImpl::send(QJsonObject v8Payload) emit messageToClient(name(), packMessage("v8message", responseData)); } -void QV4DebugServiceImpl::clearHandles(QV4::ExecutionEngine *engine) -{ - theCollector.reset(new QV4DataCollector(engine)); -} - -QV4DataCollector *QV4DebugServiceImpl::collector() const -{ - return theCollector.data(); -} - void QV4DebugServiceImpl::selectFrame(int frameNr) { theSelectedFrame = frameNr; diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h index fafe7d90bf..69e32189b8 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.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. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -57,7 +63,6 @@ QT_BEGIN_NAMESPACE namespace QV4 { struct ExecutionEngine; } -class QQmlEngine; class VariableCollector; class V8CommandHandler; class UnknownV8CommandHandler; @@ -68,26 +73,23 @@ class QV4DebugServiceImpl : public QQmlConfigurableDebugService<QV4DebugService> Q_OBJECT public: explicit QV4DebugServiceImpl(QObject *parent = 0); - ~QV4DebugServiceImpl(); + ~QV4DebugServiceImpl() Q_DECL_OVERRIDE; - void engineAdded(QQmlEngine *engine); - void engineAboutToBeRemoved(QQmlEngine *engine); + void engineAdded(QJSEngine *engine) Q_DECL_OVERRIDE; + void engineAboutToBeRemoved(QJSEngine *engine) Q_DECL_OVERRIDE; - void stateAboutToBeChanged(State state); + void stateAboutToBeChanged(State state) Q_DECL_OVERRIDE; - void signalEmitted(const QString &signal); + void signalEmitted(const QString &signal) Q_DECL_OVERRIDE; void send(QJsonObject v8Payload); int selectedFrame() const; void selectFrame(int frameNr); - void clearHandles(QV4::ExecutionEngine *engine); - - QV4DataCollector *collector() const; QV4DebuggerAgent debuggerAgent; protected: - void messageReceived(const QByteArray &); + void messageReceived(const QByteArray &) Q_DECL_OVERRIDE; void sendSomethingToSomebody(const char *type, int magicNumber = 1); private: @@ -100,12 +102,7 @@ private: V8CommandHandler *v8CommandHandler(const QString &command) const; QStringList breakOnSignals; - QMap<int, QV4::Debugging::V4Debugger *> debuggerMap; - static int debuggerIndex; static int sequence; - const int version; - - QScopedPointer<QV4DataCollector> theCollector; int theSelectedFrame; void addHandler(V8CommandHandler* handler); |