From f9990c90e1c6d212b66017a0d6dd485b550b26c4 Mon Sep 17 00:00:00 2001 From: Aurindam Jana Date: Thu, 28 Jul 2011 13:29:52 +0200 Subject: Enable v8 debugging Javascript v8 debugging service replaces the QScript debugging service. Change-Id: I25eea00eed3959b84a8f412e4c3484296d62e27b Reviewed-on: http://codereview.qt.nokia.com/2614 Reviewed-by: Qt Sanity Bot Reviewed-by: Kai Koehne --- src/declarative/debugger/debugger.pri | 6 +- .../debugger/qdeclarativedebugservice.cpp | 20 + .../debugger/qdeclarativedebugservice_p.h | 1 + src/declarative/debugger/qjsdebuggeragent.cpp | 571 --------------------- src/declarative/debugger/qjsdebuggeragent_p.h | 203 -------- src/declarative/debugger/qjsdebugservice.cpp | 208 -------- src/declarative/debugger/qjsdebugservice_p.h | 99 ---- src/declarative/debugger/qv8debugservice.cpp | 209 ++++++++ src/declarative/debugger/qv8debugservice_p.h | 103 ++++ src/declarative/qml/qdeclarativeengine.cpp | 4 +- src/declarative/qml/v8/qv8debug_p.h | 1 + src/declarative/qml/v8/qv8engine_p.h | 2 + src/declarative/qml/v8/v8.pri | 1 + 13 files changed, 341 insertions(+), 1087 deletions(-) delete mode 100644 src/declarative/debugger/qjsdebuggeragent.cpp delete mode 100644 src/declarative/debugger/qjsdebuggeragent_p.h delete mode 100644 src/declarative/debugger/qjsdebugservice.cpp delete mode 100644 src/declarative/debugger/qjsdebugservice_p.h create mode 100644 src/declarative/debugger/qv8debugservice.cpp create mode 100644 src/declarative/debugger/qv8debugservice_p.h create mode 100644 src/declarative/qml/v8/qv8debug_p.h (limited to 'src') diff --git a/src/declarative/debugger/debugger.pri b/src/declarative/debugger/debugger.pri index 3134c79d98..e7462d4e78 100644 --- a/src/declarative/debugger/debugger.pri +++ b/src/declarative/debugger/debugger.pri @@ -10,8 +10,7 @@ SOURCES += \ $$PWD/qdeclarativedebughelper.cpp \ $$PWD/qdeclarativedebugserver.cpp \ $$PWD/qdeclarativeinspectorservice.cpp \ - $$PWD/qjsdebuggeragent.cpp \ - $$PWD/qjsdebugservice.cpp + $$PWD/qv8debugservice.cpp HEADERS += \ $$PWD/qdeclarativedebuggerstatus_p.h \ @@ -26,5 +25,4 @@ HEADERS += \ $$PWD/qdeclarativedebugserverconnection_p.h \ $$PWD/qdeclarativeinspectorservice_p.h \ $$PWD/qdeclarativeinspectorinterface_p.h \ - $$PWD/qjsdebuggeragent_p.h \ - $$PWD/qjsdebugservice_p.h + $$PWD/qv8debugservice_p.h diff --git a/src/declarative/debugger/qdeclarativedebugservice.cpp b/src/declarative/debugger/qdeclarativedebugservice.cpp index 969ab35ce8..7274211bf2 100644 --- a/src/declarative/debugger/qdeclarativedebugservice.cpp +++ b/src/declarative/debugger/qdeclarativedebugservice.cpp @@ -72,6 +72,26 @@ QDeclarativeDebugService::QDeclarativeDebugService(const QString &name, QObject } } +QDeclarativeDebugService::QDeclarativeDebugService(QDeclarativeDebugServicePrivate &dd, + const QString &name, QObject *parent) + : QObject(dd, parent) +{ + Q_D(QDeclarativeDebugService); + d->name = name; + d->server = QDeclarativeDebugServer::instance(); + d->status = QDeclarativeDebugService::NotConnected; + + if (!d->server) + return; + + if (d->server->serviceNames().contains(name)) { + qWarning() << "QDeclarativeDebugService: Conflicting plugin name" << name; + d->server = 0; + } else { + d->server->addService(this); + } +} + QDeclarativeDebugService::~QDeclarativeDebugService() { Q_D(const QDeclarativeDebugService); diff --git a/src/declarative/debugger/qdeclarativedebugservice_p.h b/src/declarative/debugger/qdeclarativedebugservice_p.h index 4f1f1a6bd8..84e63c0ddc 100644 --- a/src/declarative/debugger/qdeclarativedebugservice_p.h +++ b/src/declarative/debugger/qdeclarativedebugservice_p.h @@ -80,6 +80,7 @@ public: static bool hasDebuggingClient(); protected: + QDeclarativeDebugService(QDeclarativeDebugServicePrivate &dd, const QString &, QObject *parent = 0); virtual void statusChanged(Status); virtual void messageReceived(const QByteArray &); diff --git a/src/declarative/debugger/qjsdebuggeragent.cpp b/src/declarative/debugger/qjsdebuggeragent.cpp deleted file mode 100644 index f47def802a..0000000000 --- a/src/declarative/debugger/qjsdebuggeragent.cpp +++ /dev/null @@ -1,571 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt 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 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "private/qjsdebuggeragent_p.h" -#include "private/qdeclarativedebughelper_p.h" - -#include -#include -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -class QJSDebuggerAgentPrivate -{ -public: - QJSDebuggerAgentPrivate(QJSDebuggerAgent *q) - : q(q), state(NoState), isInitialized(false) - {} - - void continueExec(); - void recordKnownObjects(const QList &); - QList getLocals(void *); - void positionChange(qint64 scriptId, int lineNumber, int columnNumber); - QJSEngine *engine() { return q->engine(); } - void stopped(); - -public: - QJSDebuggerAgent *q; - JSDebuggerState state; - int stepDepth; - int stepCount; - - QEventLoop loop; - QHash filenames; - JSAgentBreakpoints breakpoints; - // breakpoints by filename (without path) - QHash fileNameToBreakpoints; - QStringList watchExpressions; - QSet knownObjectIds; - bool isInitialized; -}; - -namespace { - -class SetupExecEnv -{ -public: - SetupExecEnv(QJSDebuggerAgentPrivate *a) - : agent(a), - previousState(a->state), - hadException(a->engine()->hasUncaughtException()) - { - agent->state = StoppedState; - } - - ~SetupExecEnv() - { - if (!hadException && agent->engine()->hasUncaughtException()) - agent->engine()->clearExceptions(); - agent->state = previousState; - } - -private: - QJSDebuggerAgentPrivate *agent; - JSDebuggerState previousState; - bool hadException; -}; - -} // anonymous namespace - -static JSAgentWatchData fromScriptValue(const QString &expression, - const QJSValue &value) -{ - static const QString arrayStr = QCoreApplication::translate - ("Debugger::JSAgentWatchData", "[Array of length %1]"); - static const QString undefinedStr = QCoreApplication::translate - ("Debugger::JSAgentWatchData", ""); - - JSAgentWatchData data; - data.exp = expression.toUtf8(); - data.name = data.exp; - data.hasChildren = false; - data.value = value.toString().toUtf8(); - // data.objectId = value.objectId(); - if (value.isArray()) { - data.type = "Array"; - data.value = arrayStr.arg(value.property(QLatin1String("length")).toString()).toUtf8(); - data.hasChildren = true; - } else if (value.isBool()) { - data.type = "Bool"; - // data.value = value.toBool() ? "true" : "false"; - } else if (value.isDate()) { - data.type = "Date"; - data.value = value.toDateTime().toString().toUtf8(); - } else if (value.isError()) { - data.type = "Error"; - } else if (value.isFunction()) { - data.type = "Function"; - } else if (value.isUndefined()) { - data.type = undefinedStr.toUtf8(); - } else if (value.isNumber()) { - data.type = "Number"; - } else if (value.isRegExp()) { - data.type = "RegExp"; - } else if (value.isString()) { - data.type = "String"; - } else if (value.isVariant()) { - data.type = "Variant"; - } else if (value.isQObject()) { - const QObject *obj = value.toQObject(); - data.type = "Object"; - data.value += '['; - data.value += obj->metaObject()->className(); - data.value += ']'; - data.hasChildren = true; - } else if (value.isObject()) { - data.type = "Object"; - data.hasChildren = true; - data.value = "[Object]"; - } else if (value.isNull()) { - data.type = ""; - } else { - data.type = ""; - } - return data; -} - -static QList expandObject(const QJSValue &object) -{ - QList result; -// QScriptValueIterator it(object); -// while (it.hasNext()) { -// it.next(); -// if (it.flags() & QScriptValue::SkipInEnumeration) -// continue; -// if (/*object.isQObject() &&*/ it.value().isFunction()) { -// // Cosmetics: skip all functions and slot, there are too many of them, -// // and it is not useful information in the debugger. -// continue; -// } -// JSAgentWatchData data = fromScriptValue(it.name(), it.value()); -// result.append(data); -// } -// if (result.isEmpty()) { -// JSAgentWatchData data; -// data.name = ""; -// data.hasChildren = false; -// data.value = " "; -// data.objectId = 0; -// result.append(data); -// } - return result; -} - -static QString fileName(const QString &fileUrl) -{ - int lastDelimiterPos = fileUrl.lastIndexOf(QLatin1Char('/')); - return fileUrl.mid(lastDelimiterPos, fileUrl.size() - lastDelimiterPos); -} - -void QJSDebuggerAgentPrivate::recordKnownObjects(const QList& list) -{ - foreach (const JSAgentWatchData &data, list) - knownObjectIds << data.objectId; -} - -QList QJSDebuggerAgentPrivate::getLocals(void *ctx) -{ - QList locals; -// if (ctx) { -// QScriptValue activationObject = ctx->activationObject(); -// QScriptValue thisObject = ctx->thisObject(); -// locals = expandObject(activationObject); -// if (thisObject.isObject() -// && thisObject.objectId() != engine()->globalObject().objectId() -// && QScriptValueIterator(thisObject).hasNext()) -// locals.prepend(fromScriptValue(QLatin1String("this"), thisObject)); -// recordKnownObjects(locals); -// knownObjectIds << activationObject.objectId(); -// } - return locals; -} - -/*! - Constructs a new agent for the given \a engine. The agent will - report debugging-related events (e.g. step completion) to the given - \a backend. -*/ -QJSDebuggerAgent::QJSDebuggerAgent(QJSEngine *engine, QObject *parent) - : QObject(parent) - , d(new QJSDebuggerAgentPrivate(this)) -{ - //QJSDebuggerAgent::engine()->setAgent(this); -} - -QJSDebuggerAgent::QJSDebuggerAgent(QDeclarativeEngine *engine, QObject *parent) - : QObject(parent) - , d(new QJSDebuggerAgentPrivate(this)) -{ - //QJSDebuggerAgent::engine()->setAgent(this); -} - -/*! - Destroys this QJSDebuggerAgent. -*/ -QJSDebuggerAgent::~QJSDebuggerAgent() -{ - //engine()->setAgent(0); - delete d; -} - -/*! - Indicates whether the agent got the list of breakpoints. - */ -bool QJSDebuggerAgent::isInitialized() const -{ - return d->isInitialized; -} - -void QJSDebuggerAgent::setBreakpoints(const JSAgentBreakpoints &breakpoints) -{ - d->breakpoints = breakpoints; - - d->fileNameToBreakpoints.clear(); - foreach (const JSAgentBreakpointData &bp, breakpoints) - d->fileNameToBreakpoints.insertMulti(fileName(QString::fromUtf8(bp.fileUrl)), bp); - - d->isInitialized = true; -} - -void QJSDebuggerAgent::setWatchExpressions(const QStringList &watchExpressions) -{ - d->watchExpressions = watchExpressions; -} - -void QJSDebuggerAgent::stepOver() -{ - d->stepDepth = 0; - d->state = SteppingOverState; - d->continueExec(); -} - -void QJSDebuggerAgent::stepInto() -{ - d->stepDepth = 0; - d->state = SteppingIntoState; - d->continueExec(); -} - -void QJSDebuggerAgent::stepOut() -{ - d->stepDepth = 0; - d->state = SteppingOutState; - d->continueExec(); -} - -void QJSDebuggerAgent::continueExecution() -{ - d->state = NoState; - d->continueExec(); -} - -JSAgentWatchData QJSDebuggerAgent::executeExpression(const QString &expr) -{ - SetupExecEnv execEnv(d); - - JSAgentWatchData data = fromScriptValue(expr, engine()->evaluate(expr)); - d->knownObjectIds << data.objectId; - return data; -} - -QList QJSDebuggerAgent::expandObjectById(quint64 objectId) -{ - SetupExecEnv execEnv(d); - - QJSValue v; -// if (d->knownObjectIds.contains(objectId)) -// v = engine()->objectById(objectId); - - QList result = expandObject(v); - d->recordKnownObjects(result); - return result; -} - -QList QJSDebuggerAgent::locals() -{ - SetupExecEnv execEnv(d); - return d->getLocals(0/*engine()->currentContext()*/); -} - -QList QJSDebuggerAgent::localsAtFrame(int frameId) -{ - SetupExecEnv execEnv(d); - -// int deep = 0; -// QScriptContext *ctx = engine()->currentContext(); -// while (ctx && deep < frameId) { -// ctx = ctx->parentContext(); -// deep++; -// } - - return d->getLocals(0/*ctx*/); -} - -QList QJSDebuggerAgent::backtrace() -{ - SetupExecEnv execEnv(d); - - QList backtrace; - -// for (QScriptContext *ctx = engine()->currentContext(); ctx; ctx = ctx->parentContext()) { -// QScriptContextInfo info(ctx); - -// JSAgentStackData frame; -// frame.functionName = info.functionName().toUtf8(); -// if (frame.functionName.isEmpty()) { -// if (ctx->parentContext()) { -// switch (info.functionType()) { -// case QScriptContextInfo::ScriptFunction: -// frame.functionName = ""; -// break; -// case QScriptContextInfo::NativeFunction: -// frame.functionName = ""; -// break; -// case QScriptContextInfo::QtFunction: -// case QScriptContextInfo::QtPropertyFunction: -// frame.functionName = ""; -// break; -// } -// } else { -// frame.functionName = ""; -// } -// } -// frame.lineNumber = info.lineNumber(); -// // if the line number is unknown, fallback to the function line number -// if (frame.lineNumber == -1) -// frame.lineNumber = info.functionStartLineNumber(); - -// frame.fileUrl = info.fileName().toUtf8(); -// backtrace.append(frame); -// } - - return backtrace; -} - -QList QJSDebuggerAgent::watches() -{ - SetupExecEnv execEnv(d); - - QList watches; - foreach (const QString &expr, d->watchExpressions) - watches << fromScriptValue(expr, engine()->evaluate(expr)); - d->recordKnownObjects(watches); - return watches; -} - -void QJSDebuggerAgent::setProperty(qint64 objectId, - const QString &property, - const QString &value) -{ - SetupExecEnv execEnv(d); - - if (d->knownObjectIds.contains(objectId)) { - QJSValue object;// = engine()->objectById(objectId); - if (object.isObject()) { - QJSValue result = engine()->evaluate(value); - object.setProperty(property, result); - } - } -} - -/*! - \reimp -*/ -void QJSDebuggerAgent::scriptLoad(qint64 id, const QString &program, - const QString &fileName, int) -{ - Q_UNUSED(program); - d->filenames.insert(id, fileName); -} - -/*! - \reimp -*/ -void QJSDebuggerAgent::scriptUnload(qint64 id) -{ - d->filenames.remove(id); -} - -/*! - \reimp -*/ -void QJSDebuggerAgent::contextPush() -{ -} - -/*! - \reimp -*/ -void QJSDebuggerAgent::contextPop() -{ -} - -/*! - \reimp -*/ -void QJSDebuggerAgent::functionEntry(qint64 scriptId) -{ - Q_UNUSED(scriptId); - d->stepDepth++; -} - -/*! - \reimp -*/ -void QJSDebuggerAgent::functionExit(qint64 scriptId, const QJSValue &returnValue) -{ - Q_UNUSED(scriptId); - Q_UNUSED(returnValue); - d->stepDepth--; -} - -/*! - \reimp -*/ -void QJSDebuggerAgent::positionChange(qint64 scriptId, int lineNumber, int columnNumber) -{ - d->positionChange(scriptId, lineNumber, columnNumber); -} - -void QJSDebuggerAgentPrivate::positionChange(qint64 scriptId, int lineNumber, int columnNumber) -{ - Q_UNUSED(columnNumber); - -// if (state == StoppedState) -// return; //no re-entrency - -// // check breakpoints -// if (!breakpoints.isEmpty()) { -// QHash::const_iterator it = filenames.constFind(scriptId); -// QScriptContext *ctx = engine()->currentContext(); -// QScriptContextInfo info(ctx); -// if (it == filenames.constEnd()) { -// // It is possible that the scripts are loaded before the agent is attached -// QString filename = info.fileName(); - -// JSAgentStackData frame; -// frame.functionName = info.functionName().toUtf8(); - -// QPair key = qMakePair(filename, lineNumber); -// it = filenames.insert(scriptId, filename); -// } - -// const QString filePath = it.value(); -// JSAgentBreakpoints bps = fileNameToBreakpoints.values(fileName(filePath)).toSet(); - -// foreach (const JSAgentBreakpointData &bp, bps) { -// if (bp.lineNumber == lineNumber) { -// stopped(); -// return; -// } -// } -// } - -// switch (state) { -// case NoState: -// case StoppedState: -// // Do nothing -// break; -// case SteppingOutState: -// if (stepDepth >= 0) -// break; -// //fallthough -// case SteppingOverState: -// if (stepDepth > 0) -// break; -// //fallthough -// case SteppingIntoState: -// stopped(); -// break; -// } - -} - -/*! - \reimp -*/ -void QJSDebuggerAgent::exceptionThrow(qint64 scriptId, - const QJSValue &exception, - bool hasHandler) -{ - Q_UNUSED(scriptId); - Q_UNUSED(exception); - Q_UNUSED(hasHandler); -// qDebug() << Q_FUNC_INFO << exception.toString() << hasHandler; -#if 0 //sometimes, we get exceptions that we should just ignore. - if (!hasHandler && state != StoppedState) - stopped(true, exception); -#endif -} - -/*! - \reimp -*/ -void QJSDebuggerAgent::exceptionCatch(qint64 scriptId, const QJSValue &exception) -{ - Q_UNUSED(scriptId); - Q_UNUSED(exception); -} - -void QJSDebuggerAgentPrivate::stopped() -{ - bool becauseOfException = false; - const QJSValue &exception = QJSValue(); - - knownObjectIds.clear(); - state = StoppedState; - - emit q->stopped(becauseOfException, exception.toString()); - - loop.exec(QEventLoop::ExcludeUserInputEvents); -} - -void QJSDebuggerAgentPrivate::continueExec() -{ - loop.quit(); -} - -QT_END_NAMESPACE diff --git a/src/declarative/debugger/qjsdebuggeragent_p.h b/src/declarative/debugger/qjsdebuggeragent_p.h deleted file mode 100644 index 30cbfe67b4..0000000000 --- a/src/declarative/debugger/qjsdebuggeragent_p.h +++ /dev/null @@ -1,203 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt 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 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QJSDEBUGGERAGENT_P_H -#define QJSDEBUGGERAGENT_P_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 -#include - -QT_BEGIN_NAMESPACE -class QJSValue; -class QDeclarativeEngine; -QT_END_NAMESPACE - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class QJSDebuggerAgentPrivate; - -enum JSDebuggerState -{ - NoState, - SteppingIntoState, - SteppingOverState, - SteppingOutState, - StoppedState -}; - -struct JSAgentWatchData -{ - QByteArray exp; - QByteArray name; - QByteArray value; - QByteArray type; - bool hasChildren; - quint64 objectId; -}; - -inline QDataStream &operator<<(QDataStream &s, const JSAgentWatchData &data) -{ - return s << data.exp << data.name << data.value - << data.type << data.hasChildren << data.objectId; -} - -struct JSAgentStackData -{ - QByteArray functionName; - QByteArray fileUrl; - qint32 lineNumber; -}; - -inline QDataStream &operator<<(QDataStream &s, const JSAgentStackData &data) -{ - return s << data.functionName << data.fileUrl << data.lineNumber; -} - -struct JSAgentBreakpointData -{ - QByteArray functionName; - QByteArray fileUrl; - qint32 lineNumber; -}; - -typedef QSet JSAgentBreakpoints; - -inline QDataStream &operator<<(QDataStream &s, const JSAgentBreakpointData &data) -{ - return s << data.functionName << data.fileUrl << data.lineNumber; -} - -inline QDataStream &operator>>(QDataStream &s, JSAgentBreakpointData &data) -{ - return s >> data.functionName >> data.fileUrl >> data.lineNumber; -} - -inline bool operator==(const JSAgentBreakpointData &b1, const JSAgentBreakpointData &b2) -{ - return b1.lineNumber == b2.lineNumber && b1.fileUrl == b2.fileUrl; -} - -inline uint qHash(const JSAgentBreakpointData &b) -{ - return b.lineNumber ^ qHash(b.fileUrl); -} - - -class QJSDebuggerAgent : public QObject -{ - Q_OBJECT - -public: - QJSDebuggerAgent(QJSEngine *engine, QObject *parent = 0); - QJSDebuggerAgent(QDeclarativeEngine *engine, QObject *parent = 0); - ~QJSDebuggerAgent(); - - bool isInitialized() const; - QJSEngine * engine() {return 0; } - - void setBreakpoints(const JSAgentBreakpoints &); - void setWatchExpressions(const QStringList &); - - void stepOver(); - void stepInto(); - void stepOut(); - void continueExecution(); - - JSAgentWatchData executeExpression(const QString &expr); - QList expandObjectById(quint64 objectId); - QList locals(); - QList localsAtFrame(int frameId); - QList backtrace(); - QList watches(); - void setProperty(qint64 objectId, - const QString &property, - const QString &value); - - // reimplemented - void scriptLoad(qint64 id, const QString &program, - const QString &fileName, int baseLineNumber); - void scriptUnload(qint64 id); - - void contextPush(); - void contextPop(); - - void functionEntry(qint64 scriptId); - void functionExit(qint64 scriptId, - const QJSValue &returnValue); - - void positionChange(qint64 scriptId, - int lineNumber, int columnNumber); - - void exceptionThrow(qint64 scriptId, - const QJSValue &exception, - bool hasHandler); - void exceptionCatch(qint64 scriptId, - const QJSValue &exception); - -Q_SIGNALS: - void stopped(bool becauseOfException, - const QString &exception); - -private: - friend class QJSDebuggerAgentPrivate; - QJSDebuggerAgentPrivate *d; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QJSDEBUGGERAGENT_P_H diff --git a/src/declarative/debugger/qjsdebugservice.cpp b/src/declarative/debugger/qjsdebugservice.cpp deleted file mode 100644 index ad84f656f7..0000000000 --- a/src/declarative/debugger/qjsdebugservice.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt 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 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "private/qjsdebugservice_p.h" -#include "private/qjsdebuggeragent_p.h" - -#include -#include -#include -#include - -Q_GLOBAL_STATIC(QJSDebugService, serviceInstance) - -QJSDebugService::QJSDebugService(QObject *parent) - : QDeclarativeDebugService(QLatin1String("JSDebugger"), parent) - , m_agent(0) -{ -} - -QJSDebugService::~QJSDebugService() -{ - delete m_agent; -} - -QJSDebugService *QJSDebugService::instance() -{ - return serviceInstance(); -} - -void QJSDebugService::addEngine(QDeclarativeEngine *engine) -{ - Q_ASSERT(engine); - Q_ASSERT(!m_engines.contains(engine)); - - m_engines.append(engine); - - if (status() == Enabled && !m_engines.isEmpty() && !m_agent) { - m_agent = new QJSDebuggerAgent(engine, engine); - connect(m_agent, SIGNAL(stopped(bool,QString)), - this, SLOT(executionStopped(bool,QString))); - - while (!m_agent->isInitialized()) { - waitForMessage(); - } - } -} - -void QJSDebugService::removeEngine(QDeclarativeEngine *engine) -{ - Q_ASSERT(engine); - Q_ASSERT(m_engines.contains(engine)); - - m_engines.removeAll(engine); -} - -void QJSDebugService::statusChanged(Status status) -{ - if (status == Enabled && !m_engines.isEmpty() && !m_agent) { - // Multiple engines are currently unsupported - QDeclarativeEngine *engine = m_engines.first(); - m_agent = new QJSDebuggerAgent(engine, engine); - - connect(m_agent, SIGNAL(stopped(bool,QString)), - this, SLOT(executionStopped(bool,QString))); - - } else if (status != Enabled && m_agent) { - delete m_agent; - m_agent = 0; - } -} - -void QJSDebugService::messageReceived(const QByteArray &message) -{ - if (!m_agent) { - qWarning() << "QJSDebugService::messageReceived: No QJSDebuggerAgent available"; - return; - } - - QDataStream ds(message); - QByteArray command; - ds >> command; - if (command == "BREAKPOINTS") { - JSAgentBreakpoints breakpoints; - ds >> breakpoints; - m_agent->setBreakpoints(breakpoints); - - //qDebug() << "BREAKPOINTS"; - //foreach (const JSAgentBreakpointData &bp, breakpoints) - // qDebug() << "BREAKPOINT: " << bp.fileUrl << bp.lineNumber; - } else if (command == "WATCH_EXPRESSIONS") { - QStringList watchExpressions; - ds >> watchExpressions; - m_agent->setWatchExpressions(watchExpressions); - } else if (command == "STEPOVER") { - m_agent->stepOver(); - } else if (command == "STEPINTO" || command == "INTERRUPT") { - m_agent->stepInto(); - } else if (command == "STEPOUT") { - m_agent->stepOut(); - } else if (command == "CONTINUE") { - m_agent->continueExecution(); - } else if (command == "EXEC") { - QByteArray id; - QString expr; - ds >> id >> expr; - - JSAgentWatchData data = m_agent->executeExpression(expr); - - QByteArray reply; - QDataStream rs(&reply, QIODevice::WriteOnly); - rs << QByteArray("RESULT") << id << data; - sendMessage(reply); - } else if (command == "EXPAND") { - QByteArray requestId; - quint64 objectId; - ds >> requestId >> objectId; - - QList result = m_agent->expandObjectById(objectId); - - QByteArray reply; - QDataStream rs(&reply, QIODevice::WriteOnly); - rs << QByteArray("EXPANDED") << requestId << result; - sendMessage(reply); - } else if (command == "ACTIVATE_FRAME") { - int frameId; - ds >> frameId; - - QList locals = m_agent->localsAtFrame(frameId); - - QByteArray reply; - QDataStream rs(&reply, QIODevice::WriteOnly); - rs << QByteArray("LOCALS") << frameId << locals; - sendMessage(reply); - } else if (command == "SET_PROPERTY") { - QByteArray id; - qint64 objectId; - QString property; - QString value; - ds >> id >> objectId >> property >> value; - - m_agent->setProperty(objectId, property, value); - - //TODO: feedback - } else if (command == "PING") { - int ping; - ds >> ping; - QByteArray reply; - QDataStream rs(&reply, QIODevice::WriteOnly); - rs << QByteArray("PONG") << ping; - sendMessage(reply); - } else { - qDebug() << Q_FUNC_INFO << "Unknown command" << command; - } - - QDeclarativeDebugService::messageReceived(message); -} - -void QJSDebugService::executionStopped(bool becauseOfException, - const QString &exception) -{ - const QList backtrace = m_agent->backtrace(); - const QList watches = m_agent->watches(); - const QList locals = m_agent->locals(); - - QByteArray reply; - QDataStream rs(&reply, QIODevice::WriteOnly); - rs << QByteArray("STOPPED") << backtrace << watches << locals - << becauseOfException << exception; - sendMessage(reply); -} diff --git a/src/declarative/debugger/qjsdebugservice_p.h b/src/declarative/debugger/qjsdebugservice_p.h deleted file mode 100644 index 7e7642eb9b..0000000000 --- a/src/declarative/debugger/qjsdebugservice_p.h +++ /dev/null @@ -1,99 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt 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 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QJSDEBUGSERVICE_P_H -#define QJSDEBUGSERVICE_P_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 - -#include "private/qdeclarativedebugservice_p.h" - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class QDeclarativeEngine; -class QJSDebuggerAgent; - -class QJSDebugService : public QDeclarativeDebugService -{ - Q_OBJECT - -public: - QJSDebugService(QObject *parent = 0); - ~QJSDebugService(); - - static QJSDebugService *instance(); - - void addEngine(QDeclarativeEngine *); - void removeEngine(QDeclarativeEngine *); - -protected: - void statusChanged(Status status); - void messageReceived(const QByteArray &); - -private Q_SLOTS: - void executionStopped(bool becauseOfException, - const QString &exception); - -private: - QList m_engines; - QPointer m_agent; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QJSDEBUGSERVICE_P_H diff --git a/src/declarative/debugger/qv8debugservice.cpp b/src/declarative/debugger/qv8debugservice.cpp new file mode 100644 index 0000000000..0358d082d3 --- /dev/null +++ b/src/declarative/debugger/qv8debugservice.cpp @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt 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 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qv8debugservice_p.h" +#include "qdeclarativedebugservice_p_p.h" +#include "qv8debug_p.h" +#include "qv8engine_p.h" +#include "qdeclarativeengine_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC(QV8DebugService, v8ServiceInstance) + +void DebugMessageHandler(const v8::Debug::Message& message) +{ + v8::DebugEvent event = message.GetEvent(); + if (event != v8::Break && event != v8::Exception && event != v8::AfterCompile) { + return; + } + + QByteArray response(QV8Engine::toStringStatic(message.GetJSON()).toUtf8()); + + QV8DebugService *service = QV8DebugService::instance(); + service->debugMessageHandler(response); + + if (event == v8::Break && !message.WillStartRunning()) { + service->executionStopped(); + } else if (event == v8::AfterCompile) { + service->appendSourcePath(response); + } //TODO::v8::Exception +} + +class QV8DebugServicePrivate : public QDeclarativeDebugServicePrivate +{ +public: + QJSEngine engine; + QList engines; + QEventLoop loop; + QHash sourcePath; +}; + +QV8DebugService::QV8DebugService(QObject *parent) + : QDeclarativeDebugService(*(new QV8DebugServicePrivate()),QLatin1String("V8Debugger"), parent) +{ + v8::Debug::SetMessageHandler2(DebugMessageHandler); +} + +QV8DebugService::~QV8DebugService() +{ +} + +QV8DebugService *QV8DebugService::instance() +{ + return v8ServiceInstance(); +} + +void QV8DebugService::addEngine(QDeclarativeEngine *engine) +{ + Q_D(QV8DebugService); + Q_ASSERT(engine); + Q_ASSERT(!d->engines.contains(engine)); + + d->engines.append(engine); +} + +void QV8DebugService::removeEngine(QDeclarativeEngine *engine) +{ + Q_D(QV8DebugService); + Q_ASSERT(engine); + Q_ASSERT(d->engines.contains(engine)); + + d->engines.removeAll(engine); +} + +void QV8DebugService::debugMessageHandler(QByteArray message) +{ + sendMessage(packMessage(message)); +} + +void QV8DebugService::executionStopped() +{ + Q_D(QV8DebugService); + + d->loop.exec(QEventLoop::ExcludeUserInputEvents); +} + +void QV8DebugService::appendSourcePath(QByteArray message) +{ + Q_D(QV8DebugService); + + QVariantMap msgMap; + { + QString msg(message); + QJSValue parser = d->engine.evaluate("JSON.parse"); + QJSValue out = parser.call(QJSValue(),QJSValueList() << QJSValue(msg)); + msgMap = out.toVariant().toMap(); + } + + QString sourcePath(msgMap.value("body").toMap().value("script").toMap().value("name").toString()); + QString fileName(QFileInfo(sourcePath).fileName()); + + d->sourcePath.insert(fileName,sourcePath); +} + +void QV8DebugService::messageReceived(const QByteArray &message) +{ + Q_D(QV8DebugService); + + QDataStream ds(message); + QByteArray command; + ds >> command; + + if (command == "V8DEBUG") { + QByteArray request; + ds >> request; + + QVariantMap reqMap; + { + QString req(request); + QJSValue parser = d->engine.evaluate("JSON.parse"); + QJSValue out = parser.call(QJSValue(),QJSValueList() << QJSValue(req)); + reqMap = out.toVariant().toMap(); + } + + QString debugCommand(reqMap.value("command").toString()); + + if (debugCommand == QString("interrupt")) { + v8::Debug::DebugBreak(); + + } else { + if (debugCommand == QString("setbreakpoint")){ + QVariantMap arguments = reqMap.value("arguments").toMap(); + QString type(arguments.value("type").toString()); + if (type == QString("script")) { + QString fileName(arguments.value("target").toString()); + QString filePath = d->sourcePath.value(fileName); + request.replace(fileName.toUtf8(),filePath.toUtf8()); + } + } + sendDebugMessage(request); + } + } + + QDeclarativeDebugService::messageReceived(message); +} + +void QV8DebugService::sendDebugMessage(const QByteArray &msg) +{ + Q_D(QV8DebugService); + + QString message(msg); + if (d->loop.isRunning()) { + d->loop.exit(); + } + v8::Debug::SendCommand(message.utf16(), message.size()); +} + +QByteArray QV8DebugService::packMessage(QByteArray &message) +{ + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + QByteArray cmd = "V8DEBUG"; + rs << cmd << message; + return reply; +} + +QT_END_NAMESPACE diff --git a/src/declarative/debugger/qv8debugservice_p.h b/src/declarative/debugger/qv8debugservice_p.h new file mode 100644 index 0000000000..7666066f50 --- /dev/null +++ b/src/declarative/debugger/qv8debugservice_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt 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 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QV8DEBUGSERVICE_P_H +#define QV8DEBUGSERVICE_P_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 + +#include "private/qdeclarativedebugservice_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeEngine; +class QJSEngine; +class QV8DebugServicePrivate; + +class QV8DebugService : public QDeclarativeDebugService +{ + Q_OBJECT +public: + QV8DebugService(QObject *parent = 0); + ~QV8DebugService(); + + static QV8DebugService *instance(); + + void addEngine(QDeclarativeEngine *); + void removeEngine(QDeclarativeEngine *); + + void debugMessageHandler(QByteArray message); + void executionStopped(); + + void appendSourcePath(QByteArray message); + +protected: + void messageReceived(const QByteArray &); + +private: + void sendDebugMessage(const QByteArray &msg); + QByteArray packMessage(QByteArray &message); + +private: + Q_DISABLE_COPY(QV8DebugService) + Q_DECLARE_PRIVATE(QV8DebugService) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QV8DEBUGSERVICE_P_H diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index f7c81d399b..c61849a8ac 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -67,7 +67,7 @@ #include "private/qdeclarativenotifier_p.h" #include "private/qdeclarativedebugtrace_p.h" #include "private/qdeclarativeapplication_p.h" -#include "private/qjsdebugservice_p.h" +#include "private/qv8debugservice_p.h" #include #include @@ -451,7 +451,7 @@ void QDeclarativeEnginePrivate::init() QDeclarativeEngineDebugServer::isDebuggingEnabled()) { isDebugging = true; QDeclarativeEngineDebugServer::instance()->addEngine(q); - QJSDebugService::instance()->addEngine(q); + QV8DebugService::instance()->addEngine(q); } } diff --git a/src/declarative/qml/v8/qv8debug_p.h b/src/declarative/qml/v8/qv8debug_p.h new file mode 100644 index 0000000000..51208aac8e --- /dev/null +++ b/src/declarative/qml/v8/qv8debug_p.h @@ -0,0 +1 @@ +#include "../../../3rdparty/v8/include/v8-debug.h" diff --git a/src/declarative/qml/v8/qv8engine_p.h b/src/declarative/qml/v8/qv8engine_p.h index 22c3504565..b3cc02321c 100644 --- a/src/declarative/qml/v8/qv8engine_p.h +++ b/src/declarative/qml/v8/qv8engine_p.h @@ -460,6 +460,7 @@ protected: double qtDateTimeToJsDate(const QDateTime &dt); QDateTime qtDateTimeFromJsDate(double jsDate); + private: typedef QScriptIntrusiveList ValueList; ValueList m_values; @@ -467,6 +468,7 @@ private: ValueIteratorList m_valueIterators; Q_DISABLE_COPY(QV8Engine) + friend class QV8DebugService; }; // Allocate a new Persistent handle. *ALL* persistent handles in QML must be allocated diff --git a/src/declarative/qml/v8/v8.pri b/src/declarative/qml/v8/v8.pri index 97b3d679df..448d501b98 100644 --- a/src/declarative/qml/v8/v8.pri +++ b/src/declarative/qml/v8/v8.pri @@ -5,6 +5,7 @@ include(script.pri) HEADERS += \ $$PWD/qv8_p.h \ + $$PWD/qv8debug_p.h \ $$PWD/qv8stringwrapper_p.h \ $$PWD/qv8engine_p.h \ $$PWD/qhashedstring_p.h \ -- cgit v1.2.3