From f0ba75d407f72de60306e4505e9ebd259e5e287c Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 18 Dec 2013 12:07:38 +0100 Subject: tst_qquickpathview: Use QCOMPARE instead of QVERIFY. Attempting to get some diagnostic output for the failues. Task-number: QTBUG-35705 Change-Id: Iffebae89743c31e88125c0b1e21be172d3373b05 Reviewed-by: Frederik Gladhorn --- tests/auto/quick/qquickpathview/tst_qquickpathview.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp index 81d1bbd01d..2c868231c8 100644 --- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp @@ -793,7 +793,7 @@ void tst_QQuickPathView::dataModel() QCOMPARE(window->rootObject()->property("viewCount").toInt(), model.count()); QTRY_COMPARE(findItems(pathview, "wrapper").count(), 14); - QVERIFY(pathview->currentIndex() == 0); + QCOMPARE(pathview->currentIndex(), 0); QCOMPARE(pathview->currentItem(), findItem(pathview, "wrapper", 0)); QQuickText *text = findItem(pathview, "myText", 4); @@ -826,7 +826,7 @@ void tst_QQuickPathView::dataModel() QTest::qWait(100); QTRY_COMPARE(findItems(pathview, "wrapper").count(), 5); - QVERIFY(pathview->currentIndex() == 1); + QCOMPARE(pathview->currentIndex(), 1); QCOMPARE(pathview->currentItem(), findItem(pathview, "wrapper", 1)); text = findItem(pathview, "myText", 2); @@ -1876,7 +1876,7 @@ void tst_QQuickPathView::snapToItem() if (enforceRange) QVERIFY(pathview->currentIndex() != currentIndex); else - QVERIFY(pathview->currentIndex() == currentIndex); + QCOMPARE(pathview->currentIndex(), currentIndex); } @@ -1908,7 +1908,7 @@ void tst_QQuickPathView::snapOneItem() QSignalSpy snapModeSpy(pathview, SIGNAL(snapModeChanged())); window->rootObject()->setProperty("snapOne", true); - QVERIFY(snapModeSpy.count() == 1); + QCOMPARE(snapModeSpy.count(), 1); QTRY_VERIFY(!pathview->isMoving()); // ensure stable int currentIndex = pathview->currentIndex(); @@ -1923,9 +1923,9 @@ void tst_QQuickPathView::snapOneItem() QCOMPARE(pathview->offset(), fmodf(3.0 + startOffset - 1.0, 3.0)); if (enforceRange) - QVERIFY(pathview->currentIndex() == currentIndex+1); + QCOMPARE(pathview->currentIndex(), currentIndex + 1); else - QVERIFY(pathview->currentIndex() == currentIndex); + QCOMPARE(pathview->currentIndex(), currentIndex); } @@ -2061,7 +2061,7 @@ void tst_QQuickPathView::cacheItemCount() pathview->setOffset(0); pathview->setCacheItemCount(3); - QVERIFY(pathview->cacheItemCount() == 3); + QCOMPARE(pathview->cacheItemCount(), 3); QQmlIncubationController controller; window->engine()->setIncubationController(&controller); -- cgit v1.2.3 From aae772e7c3820fe3559dafcaa958711d89a78827 Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Tue, 31 Dec 2013 03:06:02 +0900 Subject: Make qtdeclarative compile with QT_NO_TRANSLATION Change-Id: I73efc8c568e2368bc804eacab9e8f9cced8a030b Reviewed-by: Alan Alpert Reviewed-by: Oswald Buddenhagen --- src/qml/qml/qqmlapplicationengine.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp index b4ace17738..20894944f3 100644 --- a/src/qml/qml/qqmlapplicationengine.cpp +++ b/src/qml/qml/qqmlapplicationengine.cpp @@ -60,7 +60,7 @@ QQmlApplicationEnginePrivate::~QQmlApplicationEnginePrivate() void QQmlApplicationEnginePrivate::cleanUp() { qDeleteAll(objects); -#ifndef QT_NO_TRANSLATIONS +#ifndef QT_NO_TRANSLATION qDeleteAll(translators); #endif } @@ -71,7 +71,7 @@ void QQmlApplicationEnginePrivate::init() q->connect(&statusMapper, SIGNAL(mapped(QObject*)), q, SLOT(_q_finishLoad(QObject*))); q->connect(q, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit())); -#ifndef QT_NO_TRANSLATIONS +#ifndef QT_NO_TRANSLATION QTranslator* qtTranslator = new QTranslator; if (qtTranslator->load(QLatin1String("qt_") + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) QCoreApplication::installTranslator(qtTranslator); @@ -83,7 +83,7 @@ void QQmlApplicationEnginePrivate::init() void QQmlApplicationEnginePrivate::loadTranslations(const QUrl &rootFile) { -#ifndef QT_NO_TRANSLATIONS +#ifndef QT_NO_TRANSLATION if (rootFile.scheme() != QLatin1String("file") && rootFile.scheme() != QLatin1String("qrc")) return; @@ -96,6 +96,8 @@ void QQmlApplicationEnginePrivate::loadTranslations(const QUrl &rootFile) } else { delete translator; } +#else + Q_UNUSED(rootFile) #endif } -- cgit v1.2.3 From a1b64d9566a49d287a8fad122859e8a99ad92151 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Wed, 8 Jan 2014 16:15:21 +0100 Subject: On Mac only editable ComboBox should receive tab focus [ChangeLog][QtQuickControls] Mac: ComboBox will only get tab focus when it is editable. Change-Id: Ife04de67b2e3dea77ba878b247ad0b676c879c02 Reviewed-by: Liang Qi Reviewed-by: Jens Bache-Wiig --- src/plugins/accessible/quick/qaccessiblequickitem.cpp | 5 ++++- src/quick/items/qquickitem.cpp | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/plugins/accessible/quick/qaccessiblequickitem.cpp b/src/plugins/accessible/quick/qaccessiblequickitem.cpp index 9e8c2a6020..3521d4f98e 100644 --- a/src/plugins/accessible/quick/qaccessiblequickitem.cpp +++ b/src/plugins/accessible/quick/qaccessiblequickitem.cpp @@ -185,11 +185,14 @@ QAccessible::State QAccessibleQuickItem::state() const case QAccessible::PageTab: case QAccessible::EditableText: case QAccessible::SpinBox: - case QAccessible::ComboBox: case QAccessible::Terminal: case QAccessible::ScrollBar: state.focusable = true; break; + case QAccessible::ComboBox: + state.focusable = true; + state.editable = item()->property("editable").toBool(); + break; default: break; } diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index c308a7230a..5739d6874e 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2067,8 +2067,12 @@ bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item) if (role == QAccessible::EditableText || role == QAccessible::Table || role == QAccessible::List - || role == QAccessible::SpinBox) + || role == QAccessible::SpinBox) { result = true; + } else if (role == QAccessible::ComboBox) { + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(item); + return iface->state().editable; + } } #endif -- cgit v1.2.3 From e2c8ef1544008c36fa6dde1a1d97b46de388386a Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 9 Jan 2014 22:10:21 -0800 Subject: Fix warning about cast from char* to QString Use QStringLiteral. Change-Id: I201fc44b2a6bf0f7ff3ff1c9ea81ff3b64b2bba9 Reviewed-by: Alan Alpert --- src/quick/items/qquicklistview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index 9f2f90a2a7..06749be819 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -892,12 +892,12 @@ void QQuickListViewPrivate::createHighlight() highlightWidthAnimator = new QSmoothedAnimation; highlightWidthAnimator->velocity = highlightResizeVelocity; highlightWidthAnimator->userDuration = highlightResizeDuration; - highlightWidthAnimator->target = QQmlProperty(item, "width"); + highlightWidthAnimator->target = QQmlProperty(item, QStringLiteral("width")); highlightHeightAnimator = new QSmoothedAnimation; highlightHeightAnimator->velocity = highlightResizeVelocity; highlightHeightAnimator->userDuration = highlightResizeDuration; - highlightHeightAnimator->target = QQmlProperty(item, "height"); + highlightHeightAnimator->target = QQmlProperty(item, QStringLiteral("height")); highlight = newHighlight; changed = true; -- cgit v1.2.3 From 51f4f6f0c376607543cf046fb27b199aecac0912 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Thu, 9 Jan 2014 09:18:44 +0100 Subject: Fix nodetest autotest. GL context was initialized with the wrong surface format resulting in warnings, and we did not clean up the render context properly. Change-Id: I19f748ca985a0becf1f7a6caa987f21567029cfd Reviewed-by: Laszlo Agocs Reviewed-by: Alex Montgomery --- tests/auto/quick/nodes/tst_nodestest.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/auto/quick/nodes/tst_nodestest.cpp b/tests/auto/quick/nodes/tst_nodestest.cpp index d07fd7177d..7c84cdb5cf 100644 --- a/tests/auto/quick/nodes/tst_nodestest.cpp +++ b/tests/auto/quick/nodes/tst_nodestest.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the Qt scene graph research project. +** This file is part of the test suite of the Qt toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -97,6 +97,8 @@ void NodesTest::initTestCase() void NodesTest::cleanupTestCase() { + renderContext->invalidate(); + delete renderContext; context->doneCurrent(); delete context; delete surface; -- cgit v1.2.3 From 14ebfef611d5703e3a2d74cfb5a42f93e66644a6 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 13 Jan 2014 11:09:34 +0100 Subject: Do not crash if /proc is not mounted When proc is not mounted pthread_getattr_np fails, so default to 1MB stack in getStackLimit and to exactGC in MemoryManager Change-Id: Ic7515fd420f2d39a656808d24a3915a657722891 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4engine.cpp | 33 ++++++++++++++++++++------------- src/qml/jsruntime/qv4mm.cpp | 15 ++++++++++----- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 539bc5ddd6..ac18e56868 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -109,21 +109,28 @@ quintptr getStackLimit() # else void* stackBottom = 0; pthread_attr_t attr; - pthread_getattr_np(pthread_self(), &attr); - size_t stackSize = 0; - pthread_attr_getstack(&attr, &stackBottom, &stackSize); - pthread_attr_destroy(&attr); - -# if defined(Q_OS_ANDROID) - // Bionic pretends that the main thread has a tiny stack; work around it - if (gettid() == getpid()) { - rlimit limit; - getrlimit(RLIMIT_STACK, &limit); - stackBottom = reinterpret_cast(reinterpret_cast(stackBottom) + stackSize - limit.rlim_cur); + if (pthread_getattr_np(pthread_self(), &attr) == 0) { + size_t stackSize = 0; + pthread_attr_getstack(&attr, &stackBottom, &stackSize); + pthread_attr_destroy(&attr); + +# if defined(Q_OS_ANDROID) + // Bionic pretends that the main thread has a tiny stack; work around it + if (gettid() == getpid()) { + rlimit limit; + getrlimit(RLIMIT_STACK, &limit); + stackBottom = reinterpret_cast(reinterpret_cast(stackBottom) + stackSize - limit.rlim_cur); + } +# endif + + stackLimit = reinterpret_cast(stackBottom); + } else { + int dummy; + // this is inexact, as part of the stack is used when being called here, + // but let's simply default to 1MB from where the stack is right now + stackLimit = reinterpret_cast(&dummy) - 1024*1024; } -# endif - stackLimit = reinterpret_cast(stackBottom); # endif // This is wrong. StackLimit is the currently committed stack size, not the real end. // only way to get that limit is apparently by using VirtualQuery (Yuck) diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp index f67efaffb9..9923c8834c 100644 --- a/src/qml/jsruntime/qv4mm.cpp +++ b/src/qml/jsruntime/qv4mm.cpp @@ -234,12 +234,17 @@ MemoryManager::MemoryManager() # else void* stackBottom = 0; pthread_attr_t attr; - pthread_getattr_np(pthread_self(), &attr); - size_t stackSize = 0; - pthread_attr_getstack(&attr, &stackBottom, &stackSize); - pthread_attr_destroy(&attr); + if (pthread_getattr_np(pthread_self(), &attr) == 0) { + size_t stackSize = 0; + pthread_attr_getstack(&attr, &stackBottom, &stackSize); + pthread_attr_destroy(&attr); - m_d->stackTop = static_cast(stackBottom) + stackSize/sizeof(quintptr); + m_d->stackTop = static_cast(stackBottom) + stackSize/sizeof(quintptr); + } else { + // can't scan the native stack so have to rely on exact gc + m_d->stackTop = 0; + m_d->exactGC = true; + } # endif #elif OS(WINCE) if (false && g_stackBase) { -- cgit v1.2.3 From c70b046648522c8a899fc1fa6e4d4a5924206313 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 14 Jan 2014 12:31:39 +0100 Subject: Fix some compiler warnings in tests and examples. Change-Id: Ia739c995005635caf6fd0bd4e495ed8567350e83 Reviewed-by: Alan Alpert (Personal) <416365416c@gmail.com> --- examples/quick/models/abstractitemmodel/model.cpp | 1 + tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp | 1 + tests/auto/quick/qquickimage/tst_qquickimage.cpp | 1 + tests/auto/quick/qquickview/tst_qquickview.cpp | 4 ---- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/quick/models/abstractitemmodel/model.cpp b/examples/quick/models/abstractitemmodel/model.cpp index 724e2ed779..30eff6a7c0 100644 --- a/examples/quick/models/abstractitemmodel/model.cpp +++ b/examples/quick/models/abstractitemmodel/model.cpp @@ -67,6 +67,7 @@ void AnimalModel::addAnimal(const Animal &animal) } int AnimalModel::rowCount(const QModelIndex & parent) const { + Q_UNUSED(parent); return m_animals.count(); } diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp index 4f21231184..553663ac22 100644 --- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp +++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp @@ -676,6 +676,7 @@ void tst_qqmlcontext::qobjectDerived() QQmlContext context(engine.rootContext()); QObject *o1 = component.create(&context); + Q_UNUSED(o1); QCOMPARE(command.count, 2); } diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp index 8bdb9c9de5..7fa58036dd 100644 --- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp +++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp @@ -885,6 +885,7 @@ public: QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize) { + Q_UNUSED(requestedSize); if (id == QLatin1String("first-image.png")) { QTest::qWait(50); int width = 100; diff --git a/tests/auto/quick/qquickview/tst_qquickview.cpp b/tests/auto/quick/qquickview/tst_qquickview.cpp index a4ed1267ac..02c00ff073 100644 --- a/tests/auto/quick/qquickview/tst_qquickview.cpp +++ b/tests/auto/quick/qquickview/tst_qquickview.cpp @@ -186,10 +186,6 @@ void tst_QQuickView::resizemodeitem() delete view; } -static void silentErrorsMsgHandler(QtMsgType, const QMessageLogContext &, const QString &) -{ -} - void tst_QQuickView::errors() { QQuickView *view = new QQuickView; -- cgit v1.2.3 From 662046fe17c76d4fe505f0a04a66aa3477c14b32 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Sun, 5 Jan 2014 20:36:13 +0100 Subject: Add support for a separate index buffer The renderer binds same buffer both for vertex and index data. This is allowed on desktop & ES but is forbidden in WebGL. Add a compile-time flag to disable this optimization(?) and force using a separate buffer for the index data. Change-Id: I57c17c883a55e02513a8e4427efb202cafaaf37e Reviewed-by: Gunnar Sletta --- src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 74 +++++++++++++++++++---- src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h | 8 ++- src/quick/scenegraph/scenegraph.pri | 2 + 3 files changed, 70 insertions(+), 14 deletions(-) diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index c424fb2668..b8fdb9c9f8 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -827,6 +827,9 @@ static void qsg_wipeBuffer(Buffer *buffer, QOpenGLFunctions *funcs) static void qsg_wipeBatch(Batch *batch, QOpenGLFunctions *funcs) { qsg_wipeBuffer(&batch->vbo, funcs); +#ifdef QSG_SEPARATE_INDEX_BUFFER + qsg_wipeBuffer(&batch->ibo, funcs); +#endif delete batch; } @@ -879,12 +882,13 @@ void Renderer::map(Buffer *buffer, int byteSize) } } -void Renderer::unmap(Buffer *buffer) +void Renderer::unmap(Buffer *buffer, bool isIndexBuf) { if (buffer->id == 0) glGenBuffers(1, &buffer->id); - glBindBuffer(GL_ARRAY_BUFFER, buffer->id); - glBufferData(GL_ARRAY_BUFFER, buffer->size, buffer->data, m_bufferStrategy); + GLenum target = isIndexBuf ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER; + glBindBuffer(target, buffer->id); + glBufferData(target, buffer->size, buffer->data, m_bufferStrategy); } BatchRootInfo *Renderer::batchRootInfo(Node *node) @@ -1753,10 +1757,19 @@ void Renderer::uploadBatch(Batch *b) non-merged. */ int bufferSize = b->vertexCount * g->sizeOfVertex(); - if (b->merged) - bufferSize += b->vertexCount * sizeof(float) + b->indexCount * sizeof(quint16); - else - bufferSize += unmergedIndexSize; + int ibufferSize = 0; + if (b->merged) { + bufferSize += b->vertexCount * sizeof(float); + ibufferSize = b->indexCount * sizeof(quint16); + } else { + ibufferSize = unmergedIndexSize; + } + +#ifdef QSG_SEPARATE_INDEX_BUFFER + map(&b->ibo, ibufferSize); +#else + bufferSize += ibufferSize; +#endif map(&b->vbo, bufferSize); if (Q_UNLIKELY(debug_upload)) qDebug() << " - batch" << b << " first:" << b->first << " root:" @@ -1766,21 +1779,35 @@ void Renderer::uploadBatch(Batch *b) if (b->merged) { char *vertexData = b->vbo.data; char *zData = vertexData + b->vertexCount * g->sizeOfVertex(); +#ifdef QSG_SEPARATE_INDEX_BUFFER + char *indexData = b->ibo.data; +#else char *indexData = zData + b->vertexCount * sizeof(float); +#endif quint16 iOffset = 0; e = b->first; int verticesInSet = 0; int indicesInSet = 0; b->drawSets.reset(); - b->drawSets << DrawSet(0, zData - vertexData, indexData - vertexData); +#ifdef QSG_SEPARATE_INDEX_BUFFER + int drawSetIndices = 0; +#else + int drawSetIndices = indexData - vertexData; +#endif + b->drawSets << DrawSet(0, zData - vertexData, drawSetIndices); while (e) { verticesInSet += e->node->geometry()->vertexCount(); if (verticesInSet > 0xffff) { b->drawSets.last().indexCount = indicesInSet; +#ifdef QSG_SEPARATE_INDEX_BUFFER + drawSetIndices = indexData - b->ibo.data; +#else + drawSetIndices = indexData - b->vbo.data; +#endif b->drawSets << DrawSet(vertexData - b->vbo.data, zData - b->vbo.data, - indexData - b->vbo.data); + drawSetIndices); iOffset = 0; verticesInSet = e->node->geometry()->vertexCount(); indicesInSet = 0; @@ -1791,7 +1818,11 @@ void Renderer::uploadBatch(Batch *b) b->drawSets.last().indexCount = indicesInSet; } else { char *vboData = b->vbo.data; +#ifdef QSG_SEPARATE_INDEX_BUFFER + char *iboData = b->ibo.data; +#else char *iboData = vboData + b->vertexCount * g->sizeOfVertex(); +#endif Element *e = b->first; while (e) { QSGGeometry *g = e->node->geometry(); @@ -1858,6 +1889,9 @@ void Renderer::uploadBatch(Batch *b) } unmap(&b->vbo); +#ifdef QSG_SEPARATE_INDEX_BUFFER + unmap(&b->ibo, true); +#endif if (Q_UNLIKELY(debug_upload)) qDebug() << " --- vertex/index buffers unmapped, batch upload completed..."; @@ -1982,11 +2016,16 @@ void Renderer::renderMergedBatch(const Batch *batch) glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id); char *indexBase = 0; +#ifdef QSG_SEPARATE_INDEX_BUFFER + const Buffer *indexBuf = &batch->ibo; +#else + const Buffer *indexBuf = &batch->vbo; +#endif if (m_context->hasBrokenIndexBufferObjects()) { - indexBase = batch->vbo.data; + indexBase = indexBuf->data; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } else { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch->vbo.id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf->id); } @@ -2056,12 +2095,17 @@ void Renderer::renderUnmergedBatch(const Batch *batch) glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id); char *indexBase = 0; +#ifdef QSG_SEPARATE_INDEX_BUFFER + const Buffer *indexBuf = &batch->ibo; +#else + const Buffer *indexBuf = &batch->vbo; +#endif if (batch->indexCount) { if (m_context->hasBrokenIndexBufferObjects()) { - indexBase = batch->vbo.data; + indexBase = indexBuf->data; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } else { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch->vbo.id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf->id); } } @@ -2082,7 +2126,11 @@ void Renderer::renderUnmergedBatch(const Batch *batch) } int vOffset = 0; +#ifdef QSG_SEPARATE_INDEX_BUFFER + char *iOffset = indexBase; +#else char *iOffset = indexBase + batch->vertexCount * gn->geometry()->sizeOfVertex(); +#endif QMatrix4x4 rootMatrix = batch->root ? matrixForRoot(batch->root) : QMatrix4x4(); diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index 5404b669a0..001c3b21ab 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -276,6 +276,9 @@ struct Batch mutable uint uploadedThisFrame : 1; // solely for debugging purposes Buffer vbo; +#ifdef QSG_SEPARATE_INDEX_BUFFER + Buffer ibo; +#endif QDataBuffer drawSets; }; @@ -411,7 +414,7 @@ private: void map(Buffer *buffer, int size); - void unmap(Buffer *buffer); + void unmap(Buffer *buffer, bool isIndexBuf = false); void buildRenderListsFromScratch(); void buildRenderListsForTaggedRoots(); @@ -495,6 +498,9 @@ Batch *Renderer::newBatch() } else { b = new Batch(); memset(&b->vbo, 0, sizeof(Buffer)); +#ifdef QSG_SEPARATE_INDEX_BUFFER + memset(&b->ibo, 0, sizeof(Buffer)); +#endif } b->init(); return b; diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri index 6f64c881a8..6868e10b90 100644 --- a/src/quick/scenegraph/scenegraph.pri +++ b/src/quick/scenegraph/scenegraph.pri @@ -1,5 +1,7 @@ !contains(QT_CONFIG, egl):DEFINES += QT_NO_EGL +# DEFINES += QSG_SEPARATE_INDEX_BUFFER + # Core API HEADERS += \ $$PWD/coreapi/qsgbatchrenderer_p.h \ -- cgit v1.2.3 From 019598f57e892feacfb43b1095b3ccf5cec4d4ee Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 15 Jan 2014 12:30:36 +0100 Subject: Make sure that profiling can only be started if debugging is enabled. Enabling the profiler doesn't make much sense if there is no debug service as the messages can't be sent anywhere then. Furthermore, the profiler instance is only properly initialized if debugging is enabled and thus enabling profiling without debugging being enabled can cause problems. Change-Id: I784a110126d45a9a2bc9d9e14d9a22e2980c3a42 Reviewed-by: Kai Koehne --- src/qml/debugger/qqmlprofilerservice.cpp | 2 +- src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 4 +- .../qqmlprofilerservice/data/controlFromJS.qml | 68 ++++++++++++++++++++++ .../qqmlprofilerservice/qqmlprofilerservice.pro | 3 +- .../tst_qqmlprofilerservice.cpp | 19 ++++++ tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp | 4 +- 6 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml diff --git a/src/qml/debugger/qqmlprofilerservice.cpp b/src/qml/debugger/qqmlprofilerservice.cpp index 3c066bd380..af2aea21ae 100644 --- a/src/qml/debugger/qqmlprofilerservice.cpp +++ b/src/qml/debugger/qqmlprofilerservice.cpp @@ -178,7 +178,7 @@ void QQmlProfilerService::sendProfilingData() bool QQmlProfilerService::startProfilingImpl() { bool success = false; - if (!profilingEnabled()) { + if (QQmlDebugService::isDebuggingEnabled() && !profilingEnabled()) { setProfilingEnabled(true); sendStartedProfilingMessageImpl(); success = true; diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 0409b92e89..67b7e789bd 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -1432,7 +1432,9 @@ QV4::ReturnedValue ConsoleObject::method_profile(CallContext *ctx) const QByteArray baSource = frame.source.toUtf8(); const QByteArray baFunction = frame.function.toUtf8(); QMessageLogger logger(baSource.constData(), frame.line, baFunction.constData()); - if (QQmlProfilerService::startProfiling()) { + if (!QQmlDebugService::isDebuggingEnabled()) { + logger.warning("Cannot start profiling because debug service is disabled. Start with -qmljsdebugger=port:XXXXX."); + } else if (QQmlProfilerService::startProfiling()) { QV8ProfilerService::instance()->startProfiling(title); logger.debug("Profiling started."); diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml new file mode 100644 index 0000000000..7bcabc33ac --- /dev/null +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + Timer { + running: true + interval: 1 + onTriggered: { + console.profile(); + stopTimer.start(); + } + } + + Timer { + id: stopTimer + interval: 1000 + onTriggered: { + console.profileEnd(); + endTimer.start(); + } + } + + Timer { + id: endTimer + interval: 1000 + onTriggered: Qt.quit(); + } +} diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro index b2b325dc72..a83927e720 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro +++ b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro @@ -14,4 +14,5 @@ QT += core qml testlib gui-private DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 OTHER_FILES += \ - data/pixmapCacheTest.qml + data/pixmapCacheTest.qml \ + data/controlFromJS.qml diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index 929b079a51..acbc62807b 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -180,6 +180,7 @@ private slots: void pixmapCacheData(); void scenegraphData(); void profileOnExit(); + void controlFromJS(); }; void QQmlProfilerClient::messageReceived(const QByteArray &message) @@ -494,6 +495,24 @@ void tst_QQmlProfilerService::profileOnExit() QCOMPARE(m_client->traceMessages.last().detailType, (int)QQmlProfilerClient::EndTrace); } +void tst_QQmlProfilerService::controlFromJS() +{ + connect(true, "controlFromJS.qml"); + QVERIFY(m_client); + QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled); + + m_client->setTraceState(false); + QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time."); + + // must start with "StartTrace" + QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event); + QCOMPARE(m_client->traceMessages.first().detailType, (int)QQmlProfilerClient::StartTrace); + + // must end with "EndTrace" + QCOMPARE(m_client->traceMessages.last().messageType, (int)QQmlProfilerClient::Event); + QCOMPARE(m_client->traceMessages.last().detailType, (int)QQmlProfilerClient::EndTrace); +} + QTEST_MAIN(tst_QQmlProfilerService) #include "tst_qqmlprofilerservice.moc" diff --git a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp index e6f31dcb83..a37d705284 100644 --- a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp +++ b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp @@ -115,8 +115,8 @@ void tst_qqmlconsole::profiling() QUrl testUrl = testFileUrl("profiling.qml"); // profiling() - QTest::ignoreMessage(QtDebugMsg, "Profiling started."); - QTest::ignoreMessage(QtDebugMsg, "Profiling ended."); + QTest::ignoreMessage(QtWarningMsg, "Cannot start profiling because debug service is disabled. Start with -qmljsdebugger=port:XXXXX."); + QTest::ignoreMessage(QtWarningMsg, "Profiling was not started."); QQmlComponent component(&engine, testUrl); QObject *object = component.create(); -- cgit v1.2.3 From d574ccdd4ddd4d8c949ab5aa9f3a6baec25d9b81 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 15 Jan 2014 08:54:04 +0100 Subject: Remove the two default role names listed in cppmodels documentation. The list is incomplete, and they are now fully documented under QAbstractItemModel::roleNames(). This saves us maintaining two lists that can easily get out of sync. Change-Id: I4895a8ba19a4f48c26b4077e8bf2eba8c4c8407c Reviewed-by: Stephen Kelly --- src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc index abef6b765b..f1e13e127c 100644 --- a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc +++ b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc @@ -110,20 +110,7 @@ by the other approaches. A QAbstractItemModel can also automatically notify a QML view when the model data changes. The roles of a QAbstractItemModel subclass can be exposed to QML by -reimplementing QAbstractItemModel::roleNames(). The default role names -set by Qt are: - -\table -\header -\li Qt Role -\li QML Role Name -\row -\li Qt::DisplayRole -\li display -\row -\li Qt::DecorationRole -\li decoration -\endtable +reimplementing QAbstractItemModel::roleNames(). Here is an application with a QAbstractListModel subclass named \c AnimalModel, which exposes the \e type and \e sizes roles. It reimplements -- cgit v1.2.3 From 1ac728b7601dd5fee2fee7ea714f0626055384df Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 15 Jan 2014 14:36:37 +0100 Subject: V4: remove unnecessary spills and order them correctly. When doing edge resolving, too many spills were generated, and the dependency tracking of moves was not complete. Now we only insert spills that are caused by phi-nodes (because any other spill would be generated at the point a variable was defined). However, there can still be multiple dependencies between the moves generated by the edge resolving. Instead of only checking the first dependency, all of them are tracked. The bug report was a case where an unneccesary spill was generated, that got tracked, but "suppressed" the other (valid!) dependent move. The randomness was caused by the hash seeding of QHash. Task-number: QTBUG-35840 Change-Id: Ifbc3c8fc13de53c46a8b5859721b2497189921a3 Reviewed-by: Fawzi Mohamed Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4regalloc.cpp | 25 +++++++++++++++---------- src/qml/compiler/qv4ssa.cpp | 22 +++++++++++++--------- src/qml/compiler/qv4ssa_p.h | 5 +++-- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp index 93ecdb2602..5597759ee1 100644 --- a/src/qml/compiler/qv4regalloc.cpp +++ b/src/qml/compiler/qv4regalloc.cpp @@ -817,19 +817,15 @@ private: void resolve() { foreach (BasicBlock *bb, _function->basicBlocks) { - foreach (BasicBlock *bbOut, bb->out) { -#ifdef DEBUG_REGALLOC - Optimizer::showMeTheCode(_function); -#endif // DEBUG_REGALLOC - + foreach (BasicBlock *bbOut, bb->out) resolveEdge(bb, bbOut); - } } } void resolveEdge(BasicBlock *predecessor, BasicBlock *successor) { #ifdef DEBUG_REGALLOC + Optimizer::showMeTheCode(_function); qDebug() << "Resolving edge" << predecessor->index << "->" << successor->index; #endif // DEBUG_REGALLOC @@ -849,16 +845,20 @@ private: Q_ASSERT(successorStart > 0); foreach (const LifeTimeInterval &it, _liveAtStart[successor]) { - bool lifeTimeHole = false; if (it.end() < successorStart) continue; + + bool lifeTimeHole = false; + bool isPhiTarget = false; Expr *moveFrom = 0; + if (it.start() == successorStart) { foreach (Stmt *s, successor->statements) { if (!s || s->id < 1) continue; if (Phi *phi = s->asPhi()) { if (*phi->targetTemp == it.temp()) { + isPhiTarget = true; Expr *opd = phi->d->incoming[successor->in.indexOf(predecessor)]; if (opd->asConst()) { moveFrom = opd; @@ -939,12 +939,17 @@ private: Temp *moveTo; if (it.reg() == LifeTimeInterval::Invalid || !it.covers(successorStart)) { - int spillSlot = _assignedSpillSlots.value(it.temp(), -1); + if (!isPhiTarget) // if it.temp() is a phi target, skip it. + continue; + const int spillSlot = _assignedSpillSlots.value(it.temp(), -1); if (spillSlot == -1) continue; // it has a life-time hole here. moveTo = createTemp(Temp::StackSlot, spillSlot, it.temp().type); } else { moveTo = createTemp(Temp::PhysicalRegister, platformRegister(it), it.temp().type); + const int spillSlot = _assignedSpillSlots.value(it.temp(), -1); + if (isPhiTarget && spillSlot != -1) + mapping.add(moveFrom, createTemp(Temp::StackSlot, spillSlot, it.temp().type)); } // add move to mapping @@ -1078,7 +1083,7 @@ void RegisterAllocator::run(Function *function, const Optimizer &opt) { QTextStream qout(stdout, QIODevice::WriteOnly); qout << "Ranges:" << endl; - QList intervals = _unhandled; + QVector intervals = _unhandled; std::sort(intervals.begin(), intervals.end(), LifeTimeInterval::lessThanForTemp); foreach (const LifeTimeInterval &r, intervals) { r.dump(qout); @@ -1585,7 +1590,7 @@ void RegisterAllocator::dump() const { qout << "Ranges:" << endl; - QList handled = _handled; + QVector handled = _handled; std::sort(handled.begin(), handled.end(), LifeTimeInterval::lessThanForTemp); foreach (const LifeTimeInterval &r, handled) { r.dump(qout); diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 31a1e4cdc4..a668375da0 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -3837,15 +3837,20 @@ static inline bool overlappingStorage(const Temp &t1, const Temp &t2) || (t1.type != DoubleType && t2.type != DoubleType); } -int MoveMapping::isUsedAsSource(Expr *e) const +MoveMapping::Moves MoveMapping::sourceUsages(Expr *e, const Moves &moves) { - if (Temp *t = e->asTemp()) - for (int i = 0, ei = _moves.size(); i != ei; ++i) - if (Temp *from = _moves[i].from->asTemp()) + Moves usages; + + if (Temp *t = e->asTemp()) { + for (int i = 0, ei = moves.size(); i != ei; ++i) { + const Move &move = moves[i]; + if (Temp *from = move.from->asTemp()) if (overlappingStorage(*from, *t)) - return i; + usages.append(move); + } + } - return -1; + return usages; } void MoveMapping::add(Expr *from, Temp *to, int id) { @@ -3924,9 +3929,8 @@ void MoveMapping::dump() const MoveMapping::Action MoveMapping::schedule(const Move &m, QList &todo, QList &delayed, QList &output, QList &swaps) const { - int useIdx = isUsedAsSource(m.to); - if (useIdx != -1) { - const Move &dependency = _moves[useIdx]; + Moves usages = sourceUsages(m.to, todo) + sourceUsages(m.to, delayed); + foreach (const Move &dependency, usages) { if (!output.contains(dependency)) { if (delayed.contains(dependency)) { // We have a cycle! Break it by swapping instead of assigning. diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h index dcbc83ae65..2c61a2fe1a 100644 --- a/src/qml/compiler/qv4ssa_p.h +++ b/src/qml/compiler/qv4ssa_p.h @@ -165,10 +165,11 @@ class MoveMapping bool operator==(const Move &other) const { return from == other.from && to == other.to; } }; + typedef QList Moves; - QList _moves; + Moves _moves; - int isUsedAsSource(Expr *e) const; + static Moves sourceUsages(Expr *e, const Moves &moves); public: void add(Expr *from, Temp *to, int id = 0); -- cgit v1.2.3 From c4b4324596302b6c630187388b18dbdedaaaf7e1 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Mon, 13 Jan 2014 08:56:09 +0100 Subject: Revert "Support batching of rotated antialiased elements." This patch broke scaled text rendering This reverts commit 6acaa1c42936f89d74324be9c0cce4873a9a565b. Change-Id: I1f7a3ba0556f6d59bc1e28946631be2d9fc2b67d Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index c424fb2668..b1464a26cc 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -106,8 +106,7 @@ bool qsg_sort_batch_is_valid(Batch *a, Batch *b) { return a->first && !b->first; bool qsg_sort_batch_increasing_order(Batch *a, Batch *b) { return a->first->order < b->first->order; } bool qsg_sort_batch_decreasing_order(Batch *a, Batch *b) { return a->first->order > b->first->order; } -QSGMaterial::Flag QSGMaterial_FullMatrix = (QSGMaterial::Flag) (QSGMaterial::RequiresFullMatrix & ~QSGMaterial::RequiresFullMatrixExceptTranslate); -QSGMaterial::Flag QSGMaterial_FullExceptTranslate = (QSGMaterial::Flag) (QSGMaterial::RequiresFullMatrixExceptTranslate & ~QSGMaterial::RequiresDeterminant); +QSGMaterial::Flag QSGMaterial_RequiresFullMatrixBit = (QSGMaterial::Flag) (QSGMaterial::RequiresFullMatrix & ~QSGMaterial::RequiresFullMatrixExceptTranslate); struct QMatrix4x4_Accessor { @@ -1700,12 +1699,14 @@ void Renderer::uploadBatch(Batch *b) QSGGeometryNode *gn = b->first->node; QSGGeometry *g = gn->geometry(); - QSGMaterial::Flags flags = gn->activeMaterial()->flags(); + bool canMerge = (g->drawingMode() == GL_TRIANGLES || g->drawingMode() == GL_TRIANGLE_STRIP) && b->positionAttribute >= 0 && g->indexType() == GL_UNSIGNED_SHORT - && (flags & (QSGMaterial::CustomCompileStep | QSGMaterial_FullMatrix)) == 0 - && ((flags & QSGMaterial_FullExceptTranslate) == 0 || b->isTranslateOnlyToRoot()) + && (gn->activeMaterial()->flags() & QSGMaterial::CustomCompileStep) == 0 + && (((gn->activeMaterial()->flags() & QSGMaterial::RequiresDeterminant) == 0) + || (((gn->activeMaterial()->flags() & QSGMaterial_RequiresFullMatrixBit) == 0) && b->isTranslateOnlyToRoot()) + ) && b->isSafeToBatch(); b->merged = canMerge; -- cgit v1.2.3 From acd0baf6428601b7eab9f96eff559c27909f073e Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 16 Jan 2014 14:54:33 +0100 Subject: Increase the timeout for QPacketProtocol tests Recent failures when testing a completely unrelated one-line commit (https://codereview.qt-project.org/74584) suggest that the timeout is actually too small. Change-Id: I9c3fd0b09c6be2d42f92485c3c223fe88bb8328e Reviewed-by: Michael Brasser --- tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp b/tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp index 8dfd25b58b..7fd1f47838 100644 --- a/tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp +++ b/tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp @@ -87,7 +87,7 @@ void tst_QPacketProtocol::init() m_client->connectToHost(m_server->serverAddress(), m_server->serverPort()); QVERIFY(m_client->waitForConnected()); - QVERIFY(m_server->waitForNewConnection(5000)); + QVERIFY(m_server->waitForNewConnection(10000)); m_serverConn = m_server->nextPendingConnection(); } -- cgit v1.2.3 From 05b6dc8d4d4e8f8e8c8d578d8ae4432e6d736445 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 16 Jan 2014 11:55:54 +0100 Subject: Make sure the test window has focus Some setups like xvfb-run under Linux do not focus windows after showing them, this means that any focus based test will fail since the windows itself is unfocused. This makes sure the test window will be shown and focused. Change-Id: I1903b7cdf88b772e1ca15acd4899695b49615712 Reviewed-by: Friedemann Kleint Reviewed-by: Simon Hausmann --- src/qmltest/quicktest.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp index c210c21288..bb6eec3706 100644 --- a/src/qmltest/quicktest.cpp +++ b/src/qmltest/quicktest.cpp @@ -365,7 +365,8 @@ int quick_test_main(int argc, char **argv, const char *name, const char *sourceD view->resize(200, 200); } view->show(); - QTest::qWaitForWindowExposed(view); + view->requestActivate(); + QTest::qWaitForWindowActive(view); if (view->isExposed()) QTestRootObject::instance()->setWindowShown(true); if (!QTestRootObject::instance()->hasQuit && QTestRootObject::instance()->hasTestCase()) -- cgit v1.2.3 From 6f0f73e63182afc92cb1b8255b114fb8f8232f22 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 15 Jan 2014 10:46:08 +0100 Subject: V4 IR: update immediate dominators when purging unreachable basic-blocks The basic block scheduling uses this information to place loops. When the immediate dominator information is invalid, the scheduling can be sub-optimal, or will sometimes forget to schedule some blocks. Change-Id: Iaeb45f2b757b676310be25a658ceadc07d5722ec Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4ssa.cpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index a668375da0..c2889a2b9a 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -695,10 +695,6 @@ public: computeDF(); } -// QSet operator[](BasicBlock *n) const { -// return DF[n->index]; -// } - const BasicBlockSet &dominatorFrontier(BasicBlock *n) const { return DF[n->index]; } @@ -707,6 +703,11 @@ public: return nodes[idom[bb->index]]; } + void updateImmediateDominator(BasicBlock *bb, BasicBlock *newDominator) + { + idom[bb->index] = newDominator->index; + } + bool dominates(BasicBlock *dominator, BasicBlock *dominated) const { // The index of the basic blocks might have changed, or the nodes array might have changed, // or the block got deleted, so get the index from our copy of the array. @@ -2895,7 +2896,8 @@ namespace { /// and removes unreachable staements from the worklist, so that optimiseSSA won't consider them /// anymore. /// Important: this assumes that there are no critical edges in the control-flow graph! -void purgeBB(BasicBlock *bb, Function *func, DefUsesCalculator &defUses, QVector &W) +void purgeBB(BasicBlock *bb, Function *func, DefUsesCalculator &defUses, QVector &W, + DominatorTree &df) { // TODO: change this to mark the block as deleted, but leave it alone so that other references // won't be dangling pointers. @@ -2945,11 +2947,15 @@ void purgeBB(BasicBlock *bb, Function *func, DefUsesCalculator &defUses, QVector } } - // if a successor has no incoming edges after unlinking the current basic block, then - // it is unreachable, and can be purged too - if (out->in.isEmpty()) + if (out->in.isEmpty()) { + // if a successor has no incoming edges after unlinking the current basic block, then + // it is unreachable, and can be purged too toPurge.append(out); - + } else if (out->in.size() == 1) { + // if the successor now has only one incoming edge, we that edge is the new + // immediate dominator + df.updateImmediateDominator(out, out->in.first()); + } } // unlink all defs/uses from the statements in the basic block @@ -3032,7 +3038,7 @@ bool tryOptimizingComparison(Expr *&expr) } } // anonymous namespace -void optimizeSSA(Function *function, DefUsesCalculator &defUses) +void optimizeSSA(Function *function, DefUsesCalculator &defUses, DominatorTree &df) { const bool variablesCanEscape = function->variablesCanEscape(); @@ -3298,10 +3304,10 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses) Jump *jump = function->New(); if (convertToValue(constantCondition).toBoolean()) { jump->target = cjump->iftrue; - purgeBB(cjump->iffalse, function, defUses, W); + purgeBB(cjump->iffalse, function, defUses, W, df); } else { jump->target = cjump->iffalse; - purgeBB(cjump->iftrue, function, defUses, W); + purgeBB(cjump->iftrue, function, defUses, W, df); } *ref[s] = jump; @@ -3681,7 +3687,7 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine) static bool doOpt = qgetenv("QV4_NO_OPT").isEmpty(); if (doOpt) { // qout << "Running SSA optimization..." << endl; - optimizeSSA(function, defUses); + optimizeSSA(function, defUses, df); // showMeTheCode(function); } -- cgit v1.2.3 From a03a6499ab64da2003d2d8a4691ea89606af1f8b Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 16 Jan 2014 14:55:41 +0100 Subject: V4: lower memory allocator pressure. Changes to datastructures and more re-using of locally used temporary vectors. For the test regress-74474-002.js this lowers the total allocated memory from 1.98GB to 158MB. Thse peak memory usage stays at 75MB. There is no functional change. This should give a modest performance improvement which mainly depends on the speed of malloc()/free(). Change-Id: I1877c1903e59a33ee79ff2b801ef6f2c1cee30a6 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4regalloc.cpp | 141 +++++++++++++++++++++------------------ src/qml/compiler/qv4ssa.cpp | 30 +++++---- src/qml/compiler/qv4ssa_p.h | 1 + 3 files changed, 95 insertions(+), 77 deletions(-) diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp index 5597759ee1..df1687f267 100644 --- a/src/qml/compiler/qv4regalloc.cpp +++ b/src/qml/compiler/qv4regalloc.cpp @@ -124,7 +124,7 @@ public: return _defs[t].isPhiTarget; } - QList calls() const { return _calls; } + const QList &calls() const { return _calls; } QList hints(const Temp &t) const { return _hints[t]; } void addHint(const Temp &t, int physicalRegister) { @@ -658,13 +658,14 @@ using namespace QT_PREPEND_NAMESPACE(QQmlJS); namespace { class ResolutionPhase: protected StmtVisitor, protected ExprVisitor { - QVector _intervals; + const QVector &_intervals; + QVector _unprocessed; Function *_function; #if !defined(QT_NO_DEBUG) RegAllocInfo *_info; #endif const QHash &_assignedSpillSlots; - QHash _intervalForTemp; + QHash _intervalForTemp; const QVector &_intRegs; const QVector &_fpRegs; @@ -672,8 +673,8 @@ class ResolutionPhase: protected StmtVisitor, protected ExprVisitor { QVector _loads; QVector _stores; - QHash > _liveAtStart; - QHash > _liveAtEnd; + QHash > _liveAtStart; + QHash > _liveAtEnd; public: ResolutionPhase(const QVector &intervals, Function *function, RegAllocInfo *info, @@ -691,6 +692,13 @@ public: #if defined(QT_NO_DEBUG) Q_UNUSED(info) #endif + + _unprocessed.resize(_intervals.size()); + for (int i = 0, ei = _intervals.size(); i != ei; ++i) + _unprocessed[i] = &_intervals[i]; + + _liveAtStart.reserve(function->basicBlocks.size()); + _liveAtEnd.reserve(function->basicBlocks.size()); } void run() { @@ -704,6 +712,7 @@ private: { foreach (BasicBlock *bb, _function->basicBlocks) { QVector newStatements; + newStatements.reserve(bb->statements.size() + 7); bool seenFirstNonPhiStmt = false; for (int i = 0, ei = bb->statements.size(); i != ei; ++i) { @@ -754,22 +763,22 @@ private: } - void activate(const LifeTimeInterval &i) + void activate(const LifeTimeInterval *i) { - Q_ASSERT(!i.isFixedInterval()); - _intervalForTemp[i.temp()] = i; + Q_ASSERT(!i->isFixedInterval()); + _intervalForTemp[i->temp()] = i; - if (i.reg() != LifeTimeInterval::Invalid) { + if (i->reg() != LifeTimeInterval::Invalid) { // check if we need to generate spill/unspill instructions - if (i.start() == _currentStmt->id) { - if (i.isSplitFromInterval()) { - int pReg = platformRegister(i); - _loads.append(generateUnspill(i.temp(), pReg)); + if (i->start() == _currentStmt->id) { + if (i->isSplitFromInterval()) { + int pReg = platformRegister(*i); + _loads.append(generateUnspill(i->temp(), pReg)); } else { - int pReg = platformRegister(i); - int spillSlot = _assignedSpillSlots.value(i.temp(), -1); + int pReg = platformRegister(*i); + int spillSlot = _assignedSpillSlots.value(i->temp(), -1); if (spillSlot != -1) - _stores.append(generateSpill(spillSlot, i.temp().type, pReg)); + _stores.append(generateSpill(spillSlot, i->temp().type, pReg)); } } } @@ -779,37 +788,37 @@ private: { if (Phi *phi = _currentStmt->asPhi()) { // for phi nodes, only activate the range belonging to that node - for (int it = 0, eit = _intervals.size(); it != eit; ++it) { - const LifeTimeInterval &i = _intervals.at(it); - if (i.start() > _currentStmt->id) + for (int it = 0, eit = _unprocessed.size(); it != eit; ++it) { + const LifeTimeInterval *i = _unprocessed.at(it); + if (i->start() > _currentStmt->id) break; - if (i.temp() == *phi->targetTemp) { + if (i->temp() == *phi->targetTemp) { activate(i); - _intervals.remove(it); + _unprocessed.remove(it); break; } } return; } - while (!_intervals.isEmpty()) { - const LifeTimeInterval &i = _intervals.first(); - if (i.start() > _currentStmt->id) + while (!_unprocessed.isEmpty()) { + const LifeTimeInterval *i = _unprocessed.first(); + if (i->start() > _currentStmt->id) break; activate(i); - _intervals.removeFirst(); + _unprocessed.removeFirst(); } } void cleanOldIntervals() { const int id = _currentStmt->id; - QMutableHashIterator it(_intervalForTemp); + QMutableHashIterator it(_intervalForTemp); while (it.hasNext()) { - const LifeTimeInterval &i = it.next().value(); - if (i.end() < id || i.isFixedInterval()) + const LifeTimeInterval *i = it.next().value(); + if (i->end() < id || i->isFixedInterval()) it.remove(); } } @@ -844,20 +853,20 @@ private: Q_ASSERT(successorStart > 0); - foreach (const LifeTimeInterval &it, _liveAtStart[successor]) { - if (it.end() < successorStart) + foreach (const LifeTimeInterval *it, _liveAtStart[successor]) { + if (it->end() < successorStart) continue; bool lifeTimeHole = false; bool isPhiTarget = false; Expr *moveFrom = 0; - if (it.start() == successorStart) { + if (it->start() == successorStart) { foreach (Stmt *s, successor->statements) { if (!s || s->id < 1) continue; if (Phi *phi = s->asPhi()) { - if (*phi->targetTemp == it.temp()) { + if (*phi->targetTemp == it->temp()) { isPhiTarget = true; Expr *opd = phi->d->incoming[successor->in.indexOf(predecessor)]; if (opd->asConst()) { @@ -866,12 +875,12 @@ private: Temp *t = opd->asTemp(); Q_ASSERT(t); - foreach (const LifeTimeInterval &it2, _liveAtEnd[predecessor]) { - if (it2.temp() == *t - && it2.reg() != LifeTimeInterval::Invalid - && it2.covers(predecessorEnd)) { + foreach (const LifeTimeInterval *it2, _liveAtEnd[predecessor]) { + if (it2->temp() == *t + && it2->reg() != LifeTimeInterval::Invalid + && it2->covers(predecessorEnd)) { moveFrom = createTemp(Temp::PhysicalRegister, - platformRegister(it2), t->type); + platformRegister(*it2), t->type); break; } } @@ -886,18 +895,18 @@ private: } } } else { - foreach (const LifeTimeInterval &predIt, _liveAtEnd[predecessor]) { - if (predIt.temp() == it.temp()) { - if (predIt.reg() != LifeTimeInterval::Invalid - && predIt.covers(predecessorEnd)) { - moveFrom = createTemp(Temp::PhysicalRegister, platformRegister(predIt), - predIt.temp().type); + foreach (const LifeTimeInterval *predIt, _liveAtEnd[predecessor]) { + if (predIt->temp() == it->temp()) { + if (predIt->reg() != LifeTimeInterval::Invalid + && predIt->covers(predecessorEnd)) { + moveFrom = createTemp(Temp::PhysicalRegister, platformRegister(*predIt), + predIt->temp().type); } else { - int spillSlot = _assignedSpillSlots.value(predIt.temp(), -1); + int spillSlot = _assignedSpillSlots.value(predIt->temp(), -1); if (spillSlot == -1) lifeTimeHole = true; else - moveFrom = createTemp(Temp::StackSlot, spillSlot, predIt.temp().type); + moveFrom = createTemp(Temp::StackSlot, spillSlot, predIt->temp().type); } break; } @@ -906,20 +915,20 @@ private: if (!moveFrom) { Q_UNUSED(lifeTimeHole); #if !defined(QT_NO_DEBUG) - Q_ASSERT(!_info->isPhiTarget(it.temp()) || it.isSplitFromInterval() || lifeTimeHole); - if (_info->def(it.temp()) != successorStart && !it.isSplitFromInterval()) { + Q_ASSERT(!_info->isPhiTarget(it->temp()) || it->isSplitFromInterval() || lifeTimeHole); + if (_info->def(it->temp()) != successorStart && !it->isSplitFromInterval()) { const int successorEnd = successor->statements.last()->id; const int idx = successor->in.indexOf(predecessor); - foreach (const Use &use, _info->uses(it.temp())) { + foreach (const Use &use, _info->uses(it->temp())) { if (use.pos == static_cast(successorStart)) { // only check the current edge, not all other possible ones. This is // important for phi nodes: they have uses that are only valid when // coming in over a specific edge. foreach (Stmt *s, successor->statements) { if (Phi *phi = s->asPhi()) { - Q_ASSERT(it.temp().index != phi->targetTemp->index); + Q_ASSERT(it->temp().index != phi->targetTemp->index); Q_ASSERT(phi->d->incoming[idx]->asTemp() == 0 - || it.temp().index != phi->d->incoming[idx]->asTemp()->index); + || it->temp().index != phi->d->incoming[idx]->asTemp()->index); } else { // TODO: check that the first non-phi statement does not use // the temp. @@ -938,18 +947,18 @@ private: } Temp *moveTo; - if (it.reg() == LifeTimeInterval::Invalid || !it.covers(successorStart)) { - if (!isPhiTarget) // if it.temp() is a phi target, skip it. + if (it->reg() == LifeTimeInterval::Invalid || !it->covers(successorStart)) { + if (!isPhiTarget) // if it->temp() is a phi target, skip it. continue; - const int spillSlot = _assignedSpillSlots.value(it.temp(), -1); + const int spillSlot = _assignedSpillSlots.value(it->temp(), -1); if (spillSlot == -1) continue; // it has a life-time hole here. - moveTo = createTemp(Temp::StackSlot, spillSlot, it.temp().type); + moveTo = createTemp(Temp::StackSlot, spillSlot, it->temp().type); } else { - moveTo = createTemp(Temp::PhysicalRegister, platformRegister(it), it.temp().type); - const int spillSlot = _assignedSpillSlots.value(it.temp(), -1); + moveTo = createTemp(Temp::PhysicalRegister, platformRegister(*it), it->temp().type); + const int spillSlot = _assignedSpillSlots.value(it->temp(), -1); if (isPhiTarget && spillSlot != -1) - mapping.add(moveFrom, createTemp(Temp::StackSlot, spillSlot, it.temp().type)); + mapping.add(moveFrom, createTemp(Temp::StackSlot, spillSlot, it->temp().type)); } // add move to mapping @@ -1010,10 +1019,10 @@ protected: if (t->kind != Temp::VirtualRegister) return; - const LifeTimeInterval &i = _intervalForTemp[*t]; - Q_ASSERT(i.isValid()); - if (i.reg() != LifeTimeInterval::Invalid && i.covers(_currentStmt->id)) { - int pReg = platformRegister(i); + const LifeTimeInterval *i = _intervalForTemp[*t]; + Q_ASSERT(i->isValid()); + if (i->reg() != LifeTimeInterval::Invalid && i->covers(_currentStmt->id)) { + int pReg = platformRegister(*i); t->kind = Temp::PhysicalRegister; t->index = pReg; } else { @@ -1119,7 +1128,7 @@ void RegisterAllocator::run(Function *function, const Optimizer &opt) #endif // DEBUG_REGALLOC } -static inline LifeTimeInterval createFixedInterval(int reg, bool isFP) +static inline LifeTimeInterval createFixedInterval(int reg, bool isFP, int rangeCount) { Temp t; t.init(Temp::PhysicalRegister, reg, 0); @@ -1128,6 +1137,7 @@ static inline LifeTimeInterval createFixedInterval(int reg, bool isFP) i.setTemp(t); i.setReg(reg); i.setFixedInterval(true); + i.reserveRanges(rangeCount); return i; } @@ -1136,12 +1146,13 @@ void RegisterAllocator::prepareRanges() const int regCount = _normalRegisters.size(); _fixedRegisterRanges.resize(regCount); for (int reg = 0; reg < regCount; ++reg) - _fixedRegisterRanges[reg] = createFixedInterval(reg, false); + _fixedRegisterRanges[reg] = createFixedInterval(reg, false, _info->calls().size()); const int fpRegCount = _fpRegisters.size(); _fixedFPRegisterRanges.resize(fpRegCount); - for (int fpReg = 0; fpReg < fpRegCount; ++fpReg) - _fixedFPRegisterRanges[fpReg] = createFixedInterval(fpReg, true); + for (int fpReg = 0; fpReg < fpRegCount; ++fpReg) { + _fixedFPRegisterRanges[fpReg] = createFixedInterval(fpReg, true, _info->calls().size()); + } foreach (int callPosition, _info->calls()) { for (int reg = 0; reg < regCount; ++reg) diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index c2889a2b9a..f14205519d 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -308,9 +308,9 @@ public: BasicBlock *operator*() const { if (set.blockNumbers) - return set.allBlocks[*numberIt]; + return set.allBlocks.at(*numberIt); else - return set.allBlocks[flagIt]; + return set.allBlocks.at(flagIt); } bool operator==(const const_iterator &other) const @@ -472,9 +472,8 @@ class DominatorTree { #endif // SHOW_SSA } - BasicBlockIndex ancestorWithLowestSemi(BasicBlockIndex v) { - std::vector worklist; - worklist.reserve(vertex.capacity() / 2); + BasicBlockIndex ancestorWithLowestSemi(BasicBlockIndex v, std::vector &worklist) { + worklist.clear(); for (BasicBlockIndex it = v; it != InvalidBasicBlockIndex; it = ancestor[it]) worklist.push_back(it); @@ -517,6 +516,9 @@ class DominatorTree { DFS(nodes.first()->index); Q_ASSERT(N == nodes.size()); // fails with unreachable nodes, but those should have been removed before. + std::vector worklist; + worklist.reserve(vertex.capacity() / 2); + for (int i = N - 1; i > 0; --i) { BasicBlockIndex n = vertex[i]; BasicBlockIndex p = parent[n]; @@ -527,7 +529,7 @@ class DominatorTree { if (dfnum[v->index] <= dfnum[n]) ss = v->index; else - ss = semi[ancestorWithLowestSemi(v->index)]; + ss = semi[ancestorWithLowestSemi(v->index, worklist)]; if (dfnum[ss] < dfnum[s]) s = ss; } @@ -536,7 +538,7 @@ class DominatorTree { link(p, n); if (bucket.contains(p)) { foreach (BasicBlockIndex v, bucket[p]) { - BasicBlockIndex y = ancestorWithLowestSemi(v); + BasicBlockIndex y = ancestorWithLowestSemi(v, worklist); BasicBlockIndex semi_v = semi[v]; if (semi[y] == semi_v) idom[v] = semi_v; @@ -602,7 +604,7 @@ class DominatorTree { std::vector worklist; worklist.reserve(nodes.size() * 2); for (int i = 0, ei = nodes.size(); i != ei; ++i) { - BasicBlockIndex nodeIndex = nodes[i]->index; + BasicBlockIndex nodeIndex = nodes.at(i)->index; worklist.push_back(nodeIndex); NodeProgress &np = nodeStatus[nodeIndex]; np.children = children[nodeIndex]; @@ -633,7 +635,7 @@ class DominatorTree { if (np.todo.empty()) { BasicBlockSet &S = DF[node]; S.init(nodes); - foreach (BasicBlock *y, nodes[node]->out) + foreach (BasicBlock *y, nodes.at(node)->out) if (idom[y->index] != node) S.insert(y); foreach (BasicBlockIndex child, np.children) { @@ -755,6 +757,8 @@ public: VariableCollector(Function *function) : variablesCanEscape(function->variablesCanEscape()) { + _defsites.reserve(function->tempCount); + #if defined(SHOW_SSA) qout << "Variables collected:" << endl; #endif // SHOW_SSA @@ -1019,6 +1023,9 @@ public: , tempCount(0) , processed(f->basicBlocks) { + localMapping.reserve(f->tempCount); + vregMapping.reserve(f->tempCount); + todo.reserve(f->basicBlocks.size()); } void run() { @@ -2466,9 +2473,8 @@ protected: void splitCriticalEdges(Function *f) { - const QVector oldBBs = f->basicBlocks; - - foreach (BasicBlock *bb, oldBBs) { + for (int i = 0, ei = f->basicBlocks.size(); i != ei; ++i) { + BasicBlock *bb = f->basicBlocks[i]; if (bb->in.size() > 1) { for (int inIdx = 0, eInIdx = bb->in.size(); inIdx != eInIdx; ++inIdx) { BasicBlock *inBB = bb->in[inIdx]; diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h index 2c61a2fe1a..f90fc5b05b 100644 --- a/src/qml/compiler/qv4ssa_p.h +++ b/src/qml/compiler/qv4ssa_p.h @@ -93,6 +93,7 @@ public: void setFrom(Stmt *from); void addRange(int from, int to); Ranges ranges() const { return _ranges; } + void reserveRanges(int capacity) { _ranges.reserve(capacity); } int start() const { return _ranges.first().start; } int end() const { return _end; } -- cgit v1.2.3 From 73f4fdbef816ff623142bee6c235f06c4bdf58d3 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 15 Jan 2014 10:45:28 +0100 Subject: V4 IR: do edge splitting after SSA transformation This reduces the work for the dominator tree/frontier calculations, because there are less blocks to consider. All blocks inserted by splitting the critical edges, have (by definition) no effect on the dominator calculations. However, the immediate dominators for all new blocks needs to be added, because this information is used by the block scheduling. This change reduces memory/time usage during optimization passes, especially when processing excessively big switch statements. Change-Id: Ia69882e9dabdddffa1c98b1079012d8d988e1e8f Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4ssa.cpp | 66 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index f14205519d..7113dc7c26 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -409,7 +409,7 @@ class DominatorTree { typedef int BasicBlockIndex; enum { InvalidBasicBlockIndex = -1 }; - const QVector nodes; + QVector nodes; int N; std::vector dfnum; // BasicBlock index -> dfnum std::vector vertex; @@ -705,19 +705,57 @@ public: return nodes[idom[bb->index]]; } + void dumpImmediateDominators() const + { + qDebug() << "Immediate dominators for" << idom.size() << "nodes:"; + for (size_t i = 0, ei = idom.size(); i != ei; ++i) + if (idom[i] == InvalidBasicBlockIndex) + qDebug("\tnone -> L%d", int(i)); + else + qDebug("\tL%d -> L%d", idom[i], int(i)); + } + void updateImmediateDominator(BasicBlock *bb, BasicBlock *newDominator) { - idom[bb->index] = newDominator->index; + Q_ASSERT(bb->index >= 0); + + int blockIndex; + if (static_cast::size_type>(bb->index) >= idom.size()) { + // This is a new block, probably introduced by edge splitting. So, we'll have to grow + // the array before inserting the immediate dominator. + nodes.append(bb); + idom.resize(nodes.size(), InvalidBasicBlockIndex); + blockIndex = nodes.size() - 1; + } else { + blockIndex = getBlockIndex(bb); + } + + idom[blockIndex] = getBlockIndex(newDominator); } bool dominates(BasicBlock *dominator, BasicBlock *dominated) const { // The index of the basic blocks might have changed, or the nodes array might have changed, - // or the block got deleted, so get the index from our copy of the array. - return dominates(nodes.indexOf(dominator), nodes.indexOf(dominated)); + // so get the index from our copy of the array. + return dominates(getBlockIndex(dominator), getBlockIndex(dominated)); } private: + int getBlockIndex(BasicBlock *bb) const { + if (!bb) + return InvalidBasicBlockIndex; + + if (bb->index >= 0 && bb->index < nodes.size()) { + if (nodes.at(bb->index) == bb) + return bb->index; + } + + return nodes.indexOf(bb); + } + bool dominates(BasicBlockIndex dominator, BasicBlockIndex dominated) const { + // dominator can be Invalid when the dominated block has no dominator (i.e. the start node) + Q_ASSERT(dominated != InvalidBasicBlockIndex); + for (BasicBlockIndex it = dominated; it != InvalidBasicBlockIndex; it = idom[it]) { if (it == dominator) return true; @@ -2471,7 +2509,7 @@ protected: } }; -void splitCriticalEdges(Function *f) +void splitCriticalEdges(Function *f, DominatorTree &df) { for (int i = 0, ei = f->basicBlocks.size(); i != ei; ++i) { BasicBlock *bb = f->basicBlocks[i]; @@ -2518,6 +2556,9 @@ void splitCriticalEdges(Function *f) } else { Q_ASSERT(!"Unknown terminator!"); } + + // Set the immediate dominator of the new block to inBB + df.updateImmediateDominator(newBB, inBB); } } } @@ -2667,6 +2708,12 @@ public: showMeTheCode(function); schedule(function->basicBlocks.first()); +#if defined(SHOW_SSA) + qDebug() << "Block sequence:"; + foreach (BasicBlock *bb, sequence) + qDebug("\tL%d", bb->index); +#endif // SHOW_SSA + Q_ASSERT(function->basicBlocks.size() == sequence.size()); function->basicBlocks = sequence; return loopsStartEnd; @@ -3660,9 +3707,6 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine) if (!function->hasTry && !function->hasWith && !function->module->debugMode && doSSA) { // qout << "SSA for " << (function->name ? qPrintable(*function->name) : "") << endl; -// qout << "Starting edge splitting..." << endl; - splitCriticalEdges(function); -// showMeTheCode(function); // Calculate the dominator tree: DominatorTree df(function->basicBlocks); @@ -3690,6 +3734,11 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine) TypePropagation(defUses).run(function); // showMeTheCode(function); + // Transform the CFG into edge-split SSA. +// qout << "Starting edge splitting..." << endl; + splitCriticalEdges(function, df); +// showMeTheCode(function); + static bool doOpt = qgetenv("QV4_NO_OPT").isEmpty(); if (doOpt) { // qout << "Running SSA optimization..." << endl; @@ -3709,6 +3758,7 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine) // showMeTheCode(function); // qout << "Doing block scheduling..." << endl; +// df.dumpImmediateDominators(); startEndLoops = BlockScheduler(function, df).go(); // showMeTheCode(function); -- cgit v1.2.3 From 5d15f9704783e5eafc9ba77740aae85aeac01d24 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 16 Jan 2014 13:08:37 +0100 Subject: Fix failing context->next != 0x1 assertion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After commit bf173fe5da381c88343296ca33ef6b06389c6d20 context objects are always on the GC heap and no more in that special linked list or stack allocated, so the next pointer became dangling/uninitialized and asserting on it was bound to fail randomly. Since we no more allocate contexts on the stack, we can safely remove the assertion. Task-number: QTBUG-35917 Change-Id: I104bd129c6c32f46a6302052f563abdf926cb879 Reviewed-by: Albert Astals Cid Reviewed-by: Jan Arve Sæther --- src/qml/jsruntime/qv4context.cpp | 6 ------ src/qml/jsruntime/qv4context_p.h | 1 - src/qml/jsruntime/qv4functionobject.cpp | 3 --- 3 files changed, 10 deletions(-) diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 05a0e66e09..c2c9aefd5f 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -83,9 +83,6 @@ CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData c->strictMode = function->strictMode; c->outer = function->scope; -#ifndef QT_NO_DEBUG - assert(c->outer->next != (ExecutionContext *)0x1); -#endif c->activation = 0; @@ -229,9 +226,6 @@ CallContext::CallContext(ExecutionEngine *engine, ObjectRef qml, FunctionObject strictMode = true; outer = function->scope; -#ifndef QT_NO_DEBUG - assert(outer->next != (ExecutionContext *)0x1); -#endif activation = qml.getPointer(); diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 4eb89ad905..334d033193 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -106,7 +106,6 @@ struct Q_QML_EXPORT ExecutionContext : public Managed ExecutionContext *outer; Lookup *lookups; CompiledData::CompilationUnit *compilationUnit; - ExecutionContext *next; // used in the GC struct EvalCode { diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 6e5c137e0b..ce81282aa3 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -133,9 +133,6 @@ void FunctionObject::init(const StringRef n, bool createProto) type = Type_FunctionObject; needsActivation = true; strictMode = false; -#ifndef QT_NO_DEBUG - assert(scope->next != (ExecutionContext *)0x1); -#endif if (createProto) { Scoped proto(s, scope->engine->newObject(scope->engine->protoClass)); -- cgit v1.2.3 From cf2b04f6da6fb4d6a7da924a0796bfa8fda25398 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 13 Jan 2014 15:16:01 +0100 Subject: QtQuick.Dialogs FileDialog: don't go astray into qrc:/ on Android Was due to string->URL conversion when setting FolderListModel.folder. Task-number: QTBUG-36006 Change-Id: Ia768d8a5473b3d4c22ef9be7c8b3cf28d3956f6f Reviewed-by: Liang Qi --- src/imports/dialogs/DefaultFileDialog.qml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/imports/dialogs/DefaultFileDialog.qml b/src/imports/dialogs/DefaultFileDialog.qml index 0a5eabddf2..627a719f60 100644 --- a/src/imports/dialogs/DefaultFileDialog.qml +++ b/src/imports/dialogs/DefaultFileDialog.qml @@ -53,7 +53,13 @@ AbstractFileDialog { currentPathField.visible = false } } - onFolderChanged: view.model.folder = folder + onFolderChanged: { + var str = new String(folder) + if (str.indexOf("qrc:") === 0) + folder = "file:" + str.slice(4) + if (view.model.folder != folder) + view.model.folder = folder + } property real __textX: titleBar.height property SystemPalette __palette @@ -61,12 +67,15 @@ AbstractFileDialog { property int __lastClickedIdx: -1 function __dirDown(path) { - view.model.folder = path + view.model.folder = "file://" + path __lastClickedIdx = -1 __selectedIndices = [] } function __dirUp() { - view.model.folder = view.model.parentFolder + if (view.model.parentFolder == "") + view.model.folder = "file:///" + else + view.model.folder = view.model.parentFolder __lastClickedIdx = -1 __selectedIndices = [] } -- cgit v1.2.3 From d7ea71586c550c2c98f4ebb1caed83f69dc21e6f Mon Sep 17 00:00:00 2001 From: Tobias Koenig Date: Mon, 6 Jan 2014 09:45:37 +0100 Subject: Fix usage of FileDialog.folder property in QtQuick The content of the FileDialog.folder property has not been applied to the native QFileDialog, so it was not possible to pre-select a folder for the file dialog. Change-Id: Iaadd6aa71bc37739c16a2e7c5bff2d0050f15f3a Task-number: QTBUG-35973 Reviewed-by: Tobias Koenig Reviewed-by: Liang Qi --- src/imports/widgets/qquickqfiledialog.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/imports/widgets/qquickqfiledialog.cpp b/src/imports/widgets/qquickqfiledialog.cpp index c3991b4f3c..403577fabe 100644 --- a/src/imports/widgets/qquickqfiledialog.cpp +++ b/src/imports/widgets/qquickqfiledialog.cpp @@ -172,6 +172,10 @@ void QFileDialogHelper::setFilter() { m_dialog.setFileMode(QFileDialog::FileMode(QPlatformFileDialogHelper::options()->fileMode())); m_dialog.setOptions((QFileDialog::Options)((int)(QPlatformFileDialogHelper::options()->options()))); m_dialog.setAcceptMode(QFileDialog::AcceptMode(QPlatformFileDialogHelper::options()->acceptMode())); + + const QUrl initialDirectory = QPlatformFileDialogHelper::options()->initialDirectory(); + if (initialDirectory.isValid() && initialDirectory.isLocalFile()) + m_dialog.setDirectory(initialDirectory.toLocalFile()); } bool QFileDialogHelper::show(Qt::WindowFlags f, Qt::WindowModality m, QWindow *parent) { -- cgit v1.2.3 From 6ccb9f8f04ea257520e518b25999907c6a8421e1 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 16 Jan 2014 15:39:00 +0100 Subject: V4: relieve more memory allocator pressure. For _ZN13BenchmarkDemo11initPhysicsEv from the Octane testsuite, the total allocated memory drops from 1.5GB to 51MB. Peak memory usage stays at 29MB. Again, slow implementations of malloc()/free() will see a performance improvement. Change-Id: I21bc2f0d3735de0980fc9b3745906016e2e48a61 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4regalloc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp index df1687f267..3521d0c27a 100644 --- a/src/qml/compiler/qv4regalloc.cpp +++ b/src/qml/compiler/qv4regalloc.cpp @@ -1464,9 +1464,9 @@ int RegisterAllocator::nextIntersection(const LifeTimeInterval ¤t, return -1; for (int currentEnd = currentRanges.size(); currentIt < currentEnd; ++currentIt) { - const LifeTimeInterval::Range ¤tRange = currentRanges[currentIt]; + const LifeTimeInterval::Range currentRange = currentRanges.at(currentIt); for (int anotherIt = anotherItStart, anotherEnd = anotherRanges.size(); anotherIt < anotherEnd; ++anotherIt) { - const LifeTimeInterval::Range &anotherRange = anotherRanges[anotherIt]; + const LifeTimeInterval::Range anotherRange = anotherRanges.at(anotherIt); if (anotherRange.start > currentRange.end) break; int intersectPos = intersectionPosition(currentRange, anotherRange); -- cgit v1.2.3 From cc811f77fc4f48fb696784f0a51042bb736d7071 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Mon, 16 Dec 2013 10:40:04 -0800 Subject: Re-enable mac tests Task-number: QTBUG-35344 Change-Id: Ifc4d5420c95a615b35f02ec585c324b2cc93c5e0 Reviewed-by: Gunnar Sletta --- tests/auto/auto.pro | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 8809693647..30bc175346 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -8,13 +8,6 @@ SUBDIRS=\ qmldevtools.CONFIG = host_build -!mac { -SUBDIRS += \ - quick \ - particles \ - qmltest -} - installed_cmake.depends = cmake testcocoon: SUBDIRS -= headersclean -- cgit v1.2.3 From 5ba070d305572a7e427a62042967d737bd4791ac Mon Sep 17 00:00:00 2001 From: Sergio Ahumada Date: Wed, 15 Jan 2014 22:58:28 +0100 Subject: Bump MODULE_VERSION to 5.2.2 Change-Id: Id20a6043ba142c14cd2b1062181a399e93782179 Reviewed-by: Thiago Macieira --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index a0d132328a..bb65e47d07 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -2,5 +2,5 @@ load(qt_build_config) CONFIG += qt_example_installs CONFIG += warning_clean -MODULE_VERSION = 5.2.1 +MODULE_VERSION = 5.2.2 -- cgit v1.2.3