From d7fb215e2e207312c8dd4d0fabd6bb0861b0b669 Mon Sep 17 00:00:00 2001 From: Olivier Goffart <olivier.goffart@nokia.com> Date: Mon, 30 Aug 2010 12:05:26 +0200 Subject: [PATCH] qml debugger: Use a hash table to store the debugId This should speed up the matching between the AST nodes and the debugIds --- .../qmljsinspector/qmljsclientproxy.cpp | 40 +++++++++ src/plugins/qmljsinspector/qmljsclientproxy.h | 7 ++ .../qmljsinspector/qmljslivetextpreview.cpp | 82 ++++++------------- 3 files changed, 71 insertions(+), 58 deletions(-) diff --git a/src/plugins/qmljsinspector/qmljsclientproxy.cpp b/src/plugins/qmljsinspector/qmljsclientproxy.cpp index fd0100bd65f..fb9393d71d8 100644 --- a/src/plugins/qmljsinspector/qmljsclientproxy.cpp +++ b/src/plugins/qmljsinspector/qmljsclientproxy.cpp @@ -30,6 +30,7 @@ #include "qmljsclientproxy.h" #include "qmljsprivateapi.h" #include "qmljsdesigndebugclient.h" +#include "qmljsinspector.h" #include <debugger/debuggerplugin.h> #include <debugger/debuggerrunner.h> @@ -37,10 +38,12 @@ #include <debugger/qml/qmladapter.h> #include <extensionsystem/pluginmanager.h> #include <utils/qtcassert.h> +#include <projectexplorer/project.h> #include <QUrl> #include <QAbstractSocket> #include <QDebug> +#include <QFileInfo> using namespace QmlJSInspector::Internal; @@ -328,6 +331,11 @@ void ClientProxy::objectTreeFetched(QDeclarativeDebugQuery::State state) delete query; if (m_objectTreeQuery.isEmpty()) { + int old_count = m_debugIdHash.count(); + m_debugIdHash.clear(); + m_debugIdHash.reserve(old_count + 1); + foreach(const QDeclarativeDebugObjectReference &it, m_rootObjects) + buildDebugIdHashRecursive(it); emit objectTreeUpdated(); if (isDesignClientConnected()) { @@ -339,6 +347,38 @@ void ClientProxy::objectTreeFetched(QDeclarativeDebugQuery::State state) } } +void ClientProxy::buildDebugIdHashRecursive(const QDeclarativeDebugObjectReference& ref) +{ + QString filename = ref.source().url().toLocalFile(); + int lineNum = ref.source().lineNumber(); + int colNum = ref.source().columnNumber(); + int rev = 0; + static QRegExp rx("^(.*)_(\\d+):(\\d+)$"); + if (rx.exactMatch(filename)) { + filename = rx.cap(1); + rev = rx.cap(2).toInt(); + lineNum += rx.cap(3).toInt() - 1; + } + + //convert the filename to a canonical filename in case of febug build. + bool isShadowBuild = InspectorUi::instance()->isShadowBuildProject(); + if (isShadowBuild && rev == 0) { + QString shadowBuildDir = InspectorUi::instance()->debugProjectBuildDirectory(); + + //QFileInfo objectFileInfo(filename); + if (filename.startsWith(shadowBuildDir)) { + ProjectExplorer::Project *debugProject = InspectorUi::instance()->debugProject(); + filename = debugProject->projectDirectory() + filename.mid(shadowBuildDir.length()); + } + } + + m_debugIdHash[qMakePair<QString, int>(filename, rev)][qMakePair<int, int>(lineNum, colNum)].append(ref.debugId()); + + foreach(const QDeclarativeDebugObjectReference &it, ref.children()) + buildDebugIdHashRecursive(it); +} + + void ClientProxy::reloadQmlViewer() { if (isDesignClientConnected()) diff --git a/src/plugins/qmljsinspector/qmljsclientproxy.h b/src/plugins/qmljsinspector/qmljsclientproxy.h index a6e3b1cec63..0642f2ee18d 100644 --- a/src/plugins/qmljsinspector/qmljsclientproxy.h +++ b/src/plugins/qmljsinspector/qmljsclientproxy.h @@ -42,6 +42,10 @@ class QmlAdapter; } namespace QmlJSInspector { + +//map <filename, editorRevision> -> <lineNumber, columnNumber> -> debugIds +typedef QHash<QPair<QString, int>, QHash<QPair<int, int>, QList<int> > > DebugIdHash; + namespace Internal { class InspectorPlugin; @@ -67,6 +71,7 @@ public: QList<QDeclarativeDebugObjectReference> objectReferences(const QUrl &url = QUrl()) const; QDeclarativeDebugObjectReference objectReferenceForId(int debugId) const; QList<QDeclarativeDebugObjectReference> rootObjectReference() const; + DebugIdHash debugIdHash() const { return m_debugIdHash; }; bool isConnected() const; @@ -137,6 +142,7 @@ private: private: Q_DISABLE_COPY(ClientProxy); + void buildDebugIdHashRecursive(const QDeclarativeDebugObjectReference &ref); Debugger::Internal::QmlAdapter *m_adapter; QDeclarativeEngineDebug *m_client; @@ -149,6 +155,7 @@ private: QList<QDeclarativeDebugObjectReference> m_rootObjects; QList<QDeclarativeDebugEngineReference> m_engines; QTimer m_requestObjectsTimer; + DebugIdHash m_debugIdHash; }; } // namespace Internal diff --git a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp index d4ab06db305..e6645115653 100644 --- a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp +++ b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp @@ -71,16 +71,15 @@ class MapObjectWithDebugReference : public Visitor virtual bool visit(UiObjectDefinition *ast) ; virtual bool visit(UiObjectBinding *ast) ; - QList<QDeclarativeDebugObjectReference> root; + QHash<QPair<int, int>, DebugIdList> ids; QString filename; QHash<UiObjectMember *, DebugIdList> result; - QSet<QmlJS::AST::UiObjectMember *> lookupObjects; - Document::Ptr doc; + QSet<UiObjectMember *> lookupObjects; + private: - bool filenamesMatch(const QString &objectFileName, const QString &buildFilename) const; + void process(UiObjectMember *ast); private: int activated; - void processRecursive(const QDeclarativeDebugObjectReference &object, UiObjectMember *ast); }; bool MapObjectWithDebugReference::visit(UiObjectDefinition* ast) @@ -99,66 +98,25 @@ bool MapObjectWithDebugReference::visit(UiObjectBinding* ast) void MapObjectWithDebugReference::endVisit(UiObjectDefinition* ast) { - if (lookupObjects.isEmpty() || activated) { - foreach(const QDeclarativeDebugObjectReference& it, root) - processRecursive(it, ast); - } - + process(ast); if (lookupObjects.contains(ast)) activated--; } void MapObjectWithDebugReference::endVisit(UiObjectBinding* ast) { - if (lookupObjects.isEmpty() || activated) { - foreach(const QDeclarativeDebugObjectReference& it, root) - processRecursive(it, ast); - } - + process(ast); if (lookupObjects.contains(ast)) activated--; } -bool MapObjectWithDebugReference::filenamesMatch(const QString &objectFileName, const QString &buildFilename) const +void MapObjectWithDebugReference::process(UiObjectMember* ast) { - bool isShadowBuild = InspectorUi::instance()->isShadowBuildProject(); - ProjectExplorer::Project *debugProject = InspectorUi::instance()->debugProject(); - - if (!isShadowBuild) { - return (objectFileName == buildFilename); - } else { - QString projectDir = debugProject->projectDirectory(); - QString shadowBuildDir = InspectorUi::instance()->debugProjectBuildDirectory(); - - QFileInfo objectFileInfo(objectFileName); - QFileInfo buildFileInfo(buildFilename); - QString objectRelativePath = objectFileInfo.absoluteFilePath().mid(shadowBuildDir.length()); - QString buildRelativePath = buildFileInfo.absoluteFilePath().mid(projectDir.length()); - - return (objectRelativePath == buildRelativePath); - } -} - -void MapObjectWithDebugReference::processRecursive(const QDeclarativeDebugObjectReference& object, UiObjectMember* ast) -{ - // If this is too slow, it can be speed up by indexing - // the QDeclarativeDebugObjectReference by filename/loc in a fist pass - - SourceLocation loc = ast->firstSourceLocation(); - if (object.source().columnNumber() == int(loc.startColumn)) { - QString objectFileName = object.source().url().toLocalFile(); - if (!doc && object.source().lineNumber() == int(loc.startLine) && filenamesMatch(objectFileName, filename)) { - result[ast] += object.debugId(); - } else if (doc && objectFileName.startsWith(filename + QLatin1Char('_') + QString::number(doc->editorRevision()) + QLatin1Char(':'))) { - bool ok; - int line = objectFileName.mid(objectFileName.lastIndexOf(':') + 1).toInt(&ok); - if (ok && int(loc.startLine) == line + object.source().lineNumber() - 1) - result[ast] += object.debugId(); - } - } - - foreach (const QDeclarativeDebugObjectReference &it, object.children()) { - processRecursive(it, ast); + if (lookupObjects.isEmpty() || activated) { + SourceLocation loc = ast->firstSourceLocation(); + QHash<QPair<int, int>, DebugIdList>::const_iterator it = ids.constFind(qMakePair<int, int>(loc.startLine, loc.startColumn)); + if (it != ids.constEnd()) + result[ast].append(*it); } } @@ -314,10 +272,13 @@ void QmlJSLiveTextPreview::updateDebugIds() if (!clientProxy) return; - { // Map all the object that comes from the document as it has been loaded by the server. + DebugIdHash::const_iterator it = clientProxy->debugIdHash().constFind(qMakePair<QString, int>(m_initialDoc->fileName(), 0)); + if (it != clientProxy->debugIdHash().constEnd()) { + // Map all the object that comes from the document as it has been loaded by the server. const QmlJS::Document::Ptr &doc = m_initialDoc; + MapObjectWithDebugReference visitor; - visitor.root = clientProxy->rootObjectReference(); + visitor.ids = (*it); visitor.filename = doc->fileName(); doc->qmlProgram()->accept(&visitor); @@ -347,11 +308,16 @@ void QmlJSLiveTextPreview::updateDebugIds() it != m_createdObjects.constEnd(); ++it) { const QmlJS::Document::Ptr &doc = it.key(); + + DebugIdHash::const_iterator id_it = clientProxy->debugIdHash().constFind( + qMakePair<QString, int>(doc->fileName(), doc->editorRevision())); + if (id_it == clientProxy->debugIdHash().constEnd()) + continue; + MapObjectWithDebugReference visitor; - visitor.root = clientProxy->rootObjectReference(); + visitor.ids = *id_it; visitor.filename = doc->fileName(); visitor.lookupObjects = it.value(); - visitor.doc = doc; doc->qmlProgram()->accept(&visitor); Delta::DebugIdMap debugIds = visitor.result; -- GitLab