From a6eac7e299016c9ee8742abffd780683adac3066 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Mon, 22 May 2017 11:00:52 +0200 Subject: Repeater: Clarify documentation a little Change-Id: I4544dafd4d641728394de9a97e7ae9dd029e91a4 Task-number: QTBUG-57155 Reviewed-by: Shawn Rutledge --- src/quick/items/qquickrepeater.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickrepeater.cpp b/src/quick/items/qquickrepeater.cpp index 9ad7d27b18..6fc4c0553a 100644 --- a/src/quick/items/qquickrepeater.cpp +++ b/src/quick/items/qquickrepeater.cpp @@ -314,7 +314,11 @@ void QQuickRepeater::setDelegate(QQmlComponent *delegate) /*! \qmlproperty int QtQuick::Repeater::count - This property holds the number of items in the repeater. + This property holds the number of items in the model. + + \note The number of items in the model as reported by count may differ from + the number of created delegates if the Repeater is in the process of + instantiating delegates or is incorrectly set up. */ int QQuickRepeater::count() const { -- cgit v1.2.3 From d2c09b41ddc82dda5c5228b1f295850bb1c58f4c Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 7 Jun 2017 11:35:20 +0200 Subject: Jit: fix unary minus for integers Change-Id: Ib2cdfe6f09528d169e9ea6f8b872de875317c9c9 Reviewed-by: Simon Hausmann --- src/qml/jit/qv4unop.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/qml/jit/qv4unop.cpp b/src/qml/jit/qv4unop.cpp index 896be07ed5..78546e1509 100644 --- a/src/qml/jit/qv4unop.cpp +++ b/src/qml/jit/qv4unop.cpp @@ -83,6 +83,15 @@ template void Unop::generateUMinus(IR::Expr *source, IR::Expr *target) { IR::Temp *targetTemp = target->asTemp(); + + if (IR::Const *c = source->asConst()) { + if (c->value == 0 && source->type == IR::SInt32Type) { + // special case: minus integer 0 is 0, which is not what JS expects it to be, so always + // do a runtime call + generateRuntimeCall(_as, target, uMinus, PointerToValue(source)); + return; + } + } if (source->type == IR::SInt32Type) { typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister; if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) -- cgit v1.2.3 From e1bd2860cb7ac7e0c7e52a39aeae23882c260112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Mon, 5 Jun 2017 14:20:28 +0100 Subject: Don't detach temporary container Change-Id: I3edebdd149d901992b7db5410bb871ba1bcd454e Reviewed-by: Laszlo Agocs --- .../scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp index ce08d18057..e5b9430236 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp @@ -232,8 +232,8 @@ void QSGSoftwareRenderableNode::update() m_boundingRectMin = QRect(); m_boundingRectMax = QRect(); } else { - m_boundingRectMin = m_boundingRectMin.intersected(m_clipRegion.rects().first()); - m_boundingRectMax = m_boundingRectMax.intersected(m_clipRegion.rects().first()); + m_boundingRectMin = m_boundingRectMin.intersected(m_clipRegion.rects().constFirst()); + m_boundingRectMax = m_boundingRectMax.intersected(m_clipRegion.rects().constFirst()); } } -- cgit v1.2.3 From 0a34deef4d824884e73a93400b854399f7fde4ba Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 7 Jun 2017 12:57:01 +0200 Subject: Fix integer division 0/-1 == -0.0 in JS, which cannot be encoded in an int. Change-Id: Ice5b09fa3d42dc24d543d4581d77c6bfa743b2ca Reviewed-by: Simon Hausmann Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4runtime.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 37a2bfdf90..ecf2fd8b11 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1706,7 +1706,9 @@ ReturnedValue Runtime::method_div(const Value &left, const Value &right) if (Value::integerCompatible(left, right)) { int lval = left.integerValue(); int rval = right.integerValue(); - if (rval != 0 && (lval % rval == 0)) + if (rval != 0 // division by zero should result in a NaN + && (lval % rval == 0) // fractions can't be stored in an int + && !(lval == 0 && rval < 0)) // 0 / -something results in -0.0 return Encode(int(lval / rval)); else return Encode(double(lval) / rval); -- cgit v1.2.3 From 55d2d4cfc0b5c64b0fd8a80b868673971200f7c4 Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Wed, 7 Jun 2017 17:14:03 +0300 Subject: Fix gcc5 miscompile of qle_bitfield Task-number: QTBUG-61123 Change-Id: I124d925846a2f485f7b69870c5eebc7f7f6b50f7 Reviewed-by: Friedemann Kleint Reviewed-by: Lars Knoll --- src/qml/compiler/compiler.pri | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri index 60f548a2b0..d9b985e33b 100644 --- a/src/qml/compiler/compiler.pri +++ b/src/qml/compiler/compiler.pri @@ -52,3 +52,7 @@ qmldevtools_build|qtConfig(qml-interpreter) { $$PWD/qv4instr_moth.cpp \ $$PWD/qv4isel_moth.cpp } + +gcc { + equals(QT_GCC_MAJOR_VERSION, 5): QMAKE_CXXFLAGS += -fno-strict-aliasing +} -- cgit v1.2.3 From 4ea6d985fa76786a965443f814f3f9b59620e056 Mon Sep 17 00:00:00 2001 From: Venugopal Shivashankar Date: Tue, 7 Feb 2017 15:25:08 +0100 Subject: Doc: Simplify documentation about integrating QML and C++ Change-Id: If110d02aad991646054ee6e522549c07f00946e1 Reviewed-by: Mitch Curtis --- src/qml/doc/images/cppintegration-ex.png | Bin 0 -> 1777 bytes src/qml/doc/snippets/code/backend/backend.cpp | 70 +++++++++++++++++++++++ src/qml/doc/snippets/code/backend/backend.h | 75 ++++++++++++++++++++++++ src/qml/doc/snippets/code/backend/main.cpp | 66 +++++++++++++++++++++ src/qml/doc/snippets/code/backend/main.qml | 79 ++++++++++++++++++++++++++ src/qml/doc/src/cppintegration/topic.qdoc | 63 +++++++++++++++++++- 6 files changed, 352 insertions(+), 1 deletion(-) create mode 100644 src/qml/doc/images/cppintegration-ex.png create mode 100644 src/qml/doc/snippets/code/backend/backend.cpp create mode 100644 src/qml/doc/snippets/code/backend/backend.h create mode 100644 src/qml/doc/snippets/code/backend/main.cpp create mode 100644 src/qml/doc/snippets/code/backend/main.qml (limited to 'src') diff --git a/src/qml/doc/images/cppintegration-ex.png b/src/qml/doc/images/cppintegration-ex.png new file mode 100644 index 0000000000..0b476ccb93 Binary files /dev/null and b/src/qml/doc/images/cppintegration-ex.png differ diff --git a/src/qml/doc/snippets/code/backend/backend.cpp b/src/qml/doc/snippets/code/backend/backend.cpp new file mode 100644 index 0000000000..4a7ee89cec --- /dev/null +++ b/src/qml/doc/snippets/code/backend/backend.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "backend.h" + +BackEnd::BackEnd(QObject *parent) : + QObject(parent) +{ +} + +QString BackEnd::userName() +{ + return m_userName; +} + +void BackEnd::setUserName(const QString &userName) +{ + if (userName == m_userName) + return; + + m_userName = userName; + emit userNameChanged(); +} diff --git a/src/qml/doc/snippets/code/backend/backend.h b/src/qml/doc/snippets/code/backend/backend.h new file mode 100644 index 0000000000..91bb766e1f --- /dev/null +++ b/src/qml/doc/snippets/code/backend/backend.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BACKEND_H +#define BACKEND_H + +#include +#include + +class BackEnd : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged) + +public: + explicit BackEnd(QObject *parent = nullptr); + + QString userName(); + void setUserName(const QString &userName); + +signals: + void userNameChanged(); + +private: + QString m_userName; +}; + +#endif // BACKEND_H diff --git a/src/qml/doc/snippets/code/backend/main.cpp b/src/qml/doc/snippets/code/backend/main.cpp new file mode 100644 index 0000000000..d7a1bcbd4f --- /dev/null +++ b/src/qml/doc/snippets/code/backend/main.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "backend.h" + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + qmlRegisterType("io.qt.examples.backend", 1, 0, "BackEnd"); + + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + + return app.exec(); +} diff --git a/src/qml/doc/snippets/code/backend/main.qml b/src/qml/doc/snippets/code/backend/main.qml new file mode 100644 index 0000000000..3720da8412 --- /dev/null +++ b/src/qml/doc/snippets/code/backend/main.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.0 +//![import] +import io.qt.examples.backend 1.0 +//![import] + +ApplicationWindow { + id: root + width: 300 + height: 480 + visible: true + +//![backend] + BackEnd { + id: backend + } +//![backend] + +//![username_input] + TextField { + text: backend.userName + placeholderText: qsTr("User name") + anchors.centerIn: parent + + onTextChanged: backend.userName = text + } +//![username_input] +} + diff --git a/src/qml/doc/src/cppintegration/topic.qdoc b/src/qml/doc/src/cppintegration/topic.qdoc index 1aa3bb6ab5..22115395b1 100644 --- a/src/qml/doc/src/cppintegration/topic.qdoc +++ b/src/qml/doc/src/cppintegration/topic.qdoc @@ -27,7 +27,68 @@ /*! \page qtqml-cppintegration-topic.html \title Integrating QML and C++ -\brief Description of how to integrate QML and C++ code +\brief Provides instruction to integrate QML and C++ + +QML applications often need to handle more advanced and performance-intensive +tasks in C++. The most common and quickest way to do this is to expose the C++ +class to the QML runtime, provided the C++ implementation is derived from +QObject. Assuming that you have Qt 5.7 or later installed, the following +step-by-step instructions guide you through the process of using the C++ class, +BackEnd, in a QML application: + +\list 1 + +\li Create a new project using the "Qt Quick Application" template in Qt Creator + +\note Uncheck the \uicontrol {With ui.qml file} option in the +\uicontrol {Define Project Details} section of \uicontrol {New Project Wizard}. + +\li Add a new C++ class called \c BackEnd to the project and replace its header +file contents with: + +\quotefile code/backend/backend.h + +The \c Q_PROPERTY macro declares a property that could be accessed from QML. + +\li Replace its C++ file contents with: + +\quotefile code/backend/backend.cpp + +The \c setUserName function emits the \c userNameChanged signal every time +\c m_userName value changes. The signal can be handled from QML using the +\c onUserNameChanged handler. + +\li Include \c "backend.h" in \c main.cpp and register the class as a QML type +under a import URL as shown below: + +\quotefile code/backend/main.cpp + +The BackEnd class is registered as a type, which is accessible from QML by +importing the URL, "\c{io.qt.examples.backend 1.0}". + +\li Replace the contents of \c main.qml with the following code: + +\quotefile code/backend/main.qml + +The \c BackEnd instance lets you access the \c userName property, which +is updated when the TextField's \c text property changes. + +\endlist + +Now the application can be run. + +\borderedimage cppintegration-ex.png +\caption Application running on Ubuntu + +Qt offers several methods to integrate C++ with QML, and the method discussed +in this tutorial is just one of them. For more details about these methods, +refer to \l{Overview - QML and C++ Integration}. +*/ + +/*! +\page qtqml-cppintegration-overview.html +\title Overview - QML and C++ Integration +\brief Highlights important points about integrating C++ with QML. QML is designed to be easily extensible through C++ code. The classes in the \l {Qt QML} module enable QML objects to be loaded and manipulated from C++, and the nature of QML engine's -- cgit v1.2.3 From 5efbd7165d6867aa376f23c20edcfe49e80518c6 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 11 May 2017 10:09:12 +0200 Subject: Change temp allocation when generating IR For functions that won't get optimized, it's useful to limit the number of temporaries as much as possible. Change-Id: I6e9be3129c064fdc4c01e1ec6f1617e901c05935 Reviewed-by: Erik Verbruggen Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmlirbuilder.cpp | 3 +- src/qml/compiler/qv4codegen.cpp | 172 ++++++++++++++++++++++++++----------- src/qml/compiler/qv4codegen_p.h | 12 ++- src/qml/compiler/qv4jsir_p.h | 18 +++- src/qml/compiler/qv4ssa.cpp | 6 +- 5 files changed, 155 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 16eee50cf9..57cb4c607c 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1948,7 +1948,8 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int QQmlTypeNameCache::Result r = imports->query(name); if (r.isValid()) { if (r.scriptIndex != -1) { - return subscript(_block->TEMP(_importedScriptsTemp), _block->CONST(QV4::IR::SInt32Type, r.scriptIndex)); + return _block->SUBSCRIPT(_block->TEMP(_importedScriptsTemp), + _block->CONST(QV4::IR::SInt32Type, r.scriptIndex)); } else if (r.type) { QV4::IR::Name *typeName = _block->NAME(name, line, col); // Make sure the run-time loads this through the more efficient singleton getter. diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index fcfbdfa74b..1e98d1167b 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -113,6 +113,18 @@ static inline void setJumpOutLocation(IR::Stmt *s, const Statement *body, } } +static inline bool isSimpleExpr(IR::Expr *e) +{ + switch (e->exprKind) { + case IR::Expr::TempExpr: + case IR::Expr::ArgLocalExpr: + case IR::Expr::ConstExpr: + return true; + default: + return false; + } +} + Codegen::ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode) : _cg(cg) , _sourceCode(sourceCode) @@ -561,28 +573,6 @@ IR::Expr *Codegen::member(IR::Expr *base, const QString *name) } } -IR::Expr *Codegen::subscript(IR::Expr *base, IR::Expr *index) -{ - if (hasError) - return 0; - - if (! base->asTemp() && !base->asArgLocal()) { - const unsigned t = _block->newTemp(); - move(_block->TEMP(t), base); - base = _block->TEMP(t); - } - - if (! index->asTemp() && !index->asArgLocal() && !index->asConst()) { - const unsigned t = _block->newTemp(); - move(_block->TEMP(t), index); - index = _block->TEMP(t); - } - - Q_ASSERT(base->asTemp() || base->asArgLocal()); - Q_ASSERT(index->asTemp() || index->asArgLocal() || index->asConst()); - return _block->SUBSCRIPT(base, index); -} - IR::Expr *Codegen::argument(IR::Expr *expr) { if (expr && !expr->asTemp()) { @@ -635,12 +625,14 @@ IR::Expr *Codegen::unop(IR::AluOp op, IR::Expr *expr, const SourceLocation &loc) } } } - if (!expr->asTemp() && !expr->asArgLocal()) { - const unsigned t = _block->newTemp(); - setLocation(move(_block->TEMP(t), expr), loc); - expr = _block->TEMP(t); - } - Q_ASSERT(expr->asTemp() || expr->asArgLocal()); + + TempScope scope(_function); + if (isSimpleExpr(expr)) + return _block->UNOP(op, expr); + + const unsigned t = _block->newTemp(); + setLocation(move(_block->TEMP(t), expr), loc); + expr = _block->TEMP(t); return _block->UNOP(op, expr); } @@ -649,6 +641,8 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right, const AS if (hasError) return 0; + TempScope scope(_function); + if (IR::Const *c1 = left->asConst()) { if (IR::Const *c2 = right->asConst()) { if ((c1->type & IR::NumberType) && (c2->type & IR::NumberType)) { @@ -736,6 +730,8 @@ IR::Stmt *Codegen::move(IR::Expr *target, IR::Expr *source, IR::AluOp op) return move(target, binop(op, target, source)); } + TempScope scope(_function); + if (!source->asTemp() && !source->asConst() && !target->asTemp() && !source->asArgLocal() && !target->asArgLocal()) { unsigned t = _block->newTemp(); _block->MOVE(_block->TEMP(t), source); @@ -755,6 +751,8 @@ IR::Stmt *Codegen::cjump(IR::Expr *cond, IR::BasicBlock *iftrue, IR::BasicBlock if (hasError) return 0; + TempScope scope(_function); + if (! (cond->asTemp() || (cond->asBinop() && cjumpCanHandle(cond->asBinop()->op)) )) { const unsigned t = _block->newTemp(); move(_block->TEMP(t), cond); @@ -774,12 +772,16 @@ void Codegen::accept(Node *node) void Codegen::statement(Statement *ast) { + TempScope scope(_function); + _block->nextLocation = ast->firstSourceLocation(); accept(ast); } void Codegen::statement(ExpressionNode *ast) { + TempScope scope(_function); + if (! ast) { return; } else { @@ -888,6 +890,7 @@ void Codegen::variableDeclaration(VariableDeclaration *ast) if (lhs->asArgLocal()) { move(lhs, initializer); } else { + TempScope scope(_function); int initialized = _block->newTemp(); move(_block->TEMP(initialized), initializer); move(lhs, _block->TEMP(initialized)); @@ -1091,6 +1094,10 @@ bool Codegen::visit(ArrayLiteral *ast) if (hasError) return false; + const unsigned t = _block->newTemp(); + + TempScope scope(_function); + IR::ExprList *args = 0; IR::ExprList *current = 0; for (ElementList *it = ast->elements; it; it = it->next) { @@ -1136,7 +1143,6 @@ bool Codegen::visit(ArrayLiteral *ast) current->expr = _block->CONST(IR::MissingType, 0); } - const unsigned t = _block->newTemp(); move(_block->TEMP(t), _block->CALL(_block->NAME(IR::Name::builtin_define_array, 0, 0), args)); _expr.code = _block->TEMP(t); return false; @@ -1147,11 +1153,25 @@ bool Codegen::visit(ArrayMemberExpression *ast) if (hasError) return false; - Result base = expression(ast->base); - Result index = expression(ast->expression); + IR::Expr *base = *expression(ast->base); + if (hasError) + return false; + if (!isSimpleExpr(base)) { + const unsigned t = _block->newTemp(); + move(_block->TEMP(t), base); + base = _block->TEMP(t); + } + + IR::Expr *index = *expression(ast->expression); if (hasError) return false; - _expr.code = subscript(*base, *index); + if (!isSimpleExpr(index)) { + const unsigned t = _block->newTemp(); + move(_block->TEMP(t), index); + index = _block->TEMP(t); + } + + _expr.code = _block->SUBSCRIPT(base, index); return false; } @@ -1287,14 +1307,12 @@ bool Codegen::visit(BinaryExpression *ast) return false; } - if (_expr.accept(nx)) { - move(left, *right, baseOp(ast->op)); - } else { - const unsigned t = _block->newTemp(); - move(_block->TEMP(t), *right); - move(left, _block->TEMP(t), baseOp(ast->op)); + TempScope scope(_function); + const unsigned t = _block->newTemp(); + move(_block->TEMP(t), *right); + move(left, _block->TEMP(t), baseOp(ast->op)); + if (!_expr.accept(nx)) _expr.code = left; - } break; } @@ -1308,6 +1326,7 @@ bool Codegen::visit(BinaryExpression *ast) case QSOperator::Lt: case QSOperator::StrictEqual: case QSOperator::StrictNotEqual: { + TempScope scope(_function); if (!left->asTemp() && !left->asArgLocal() && !left->asConst()) { const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), left), ast->operatorToken); @@ -1337,6 +1356,7 @@ bool Codegen::visit(BinaryExpression *ast) case QSOperator::RShift: case QSOperator::Sub: case QSOperator::URShift: { + TempScope scope(_function); if (!left->asTemp() && !left->asArgLocal() && !left->asConst()) { const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), left), ast->operatorToken); @@ -1388,6 +1408,7 @@ bool Codegen::visit(ConditionalExpression *ast) IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler()); const unsigned t = _block->newTemp(); + TempScope scope(_function); condition(ast->expression, iftrue, iffalse); @@ -1491,6 +1512,8 @@ bool Codegen::visit(FunctionExpression *ast) if (hasError) return false; + TempScope scope(_function); + int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0); _expr.code = _block->CLOSURE(function); return false; @@ -1571,6 +1594,7 @@ bool Codegen::visit(NewExpression *ast) { if (hasError) return false; + TempScope scope(_function); Result base = expression(ast->expression); if (hasError) @@ -1590,6 +1614,10 @@ bool Codegen::visit(NewMemberExpression *ast) if (hasError) return false; + const unsigned t = _block->newTemp(); + + TempScope scope(_function); + Result base = expression(ast->base); if (hasError) return false; @@ -1610,7 +1638,6 @@ bool Codegen::visit(NewMemberExpression *ast) (*args_it)->init(actual); args_it = &(*args_it)->next; } - const unsigned t = _block->newTemp(); move(_block->TEMP(t), _block->NEW(expr, args)); _expr.code = _block->TEMP(t); return false; @@ -1621,10 +1648,12 @@ bool Codegen::visit(NotExpression *ast) if (hasError) return false; + const unsigned r = _block->newTemp(); + TempScope scope(_function); + Result expr = expression(ast->expression); if (hasError) return false; - const unsigned r = _block->newTemp(); setLocation(move(_block->TEMP(r), unop(IR::OpNot, *expr, ast->notToken)), ast->notToken); _expr.code = _block->TEMP(r); return false; @@ -1677,6 +1706,9 @@ bool Codegen::visit(ObjectLiteral *ast) QMap valueMap; + const unsigned t = _block->newTemp(); + TempScope scope(_function); + for (PropertyAssignmentList *it = ast->properties; it; it = it->next) { QString name = it->assignment->name->asString(); if (PropertyNameAndValue *nv = AST::cast(it->assignment)) { @@ -1690,7 +1722,13 @@ bool Codegen::visit(ObjectLiteral *ast) return false; } - valueMap[name].value = *value; + if (IR::Const *c = (*value)->asConst()) { + valueMap[name].value = c; + } else { + unsigned t = _block->newTemp(); + move(_block->TEMP(t), *value); + valueMap[name].value = _block->TEMP(t); + } } else if (PropertyGetterSetter *gs = AST::cast(it->assignment)) { const int function = defineFunction(name, gs, gs->formals, gs->functionBody ? gs->functionBody->elements : 0); ObjectPropertyValue &v = valueMap[name]; @@ -1761,12 +1799,9 @@ bool Codegen::visit(ObjectLiteral *ast) current = current->next; current->expr = _block->CONST(IR::BoolType, true); - unsigned value = _block->newTemp(); - move(_block->TEMP(value), it->value); - current->next = _function->New(); current = current->next; - current->expr = _block->TEMP(value); + current->expr = it->value; } else { current->next = _function->New(); current = current->next; @@ -1799,7 +1834,6 @@ bool Codegen::visit(ObjectLiteral *ast) args->next = arrayEntries; } - const unsigned t = _block->newTemp(); move(_block->TEMP(t), _block->CALL(_block->NAME(IR::Name::builtin_define_object_literal, ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn), args)); @@ -1825,6 +1859,7 @@ bool Codegen::visit(PostDecrementExpression *ast) const unsigned oldValue = _block->newTemp(); setLocation(move(_block->TEMP(oldValue), unop(IR::OpUPlus, *expr, ast->decrementToken)), ast->decrementToken); + TempScope scope(_function); const unsigned newValue = _block->newTemp(); setLocation(move(_block->TEMP(newValue), binop(IR::OpSub, _block->TEMP(oldValue), _block->CONST(IR::NumberType, 1), ast->decrementToken)), ast->decrementToken); setLocation(move(*expr, _block->TEMP(newValue)), ast->decrementToken); @@ -1853,6 +1888,7 @@ bool Codegen::visit(PostIncrementExpression *ast) const unsigned oldValue = _block->newTemp(); setLocation(move(_block->TEMP(oldValue), unop(IR::OpUPlus, *expr, ast->incrementToken)), ast->incrementToken); + TempScope scope(_function); const unsigned newValue = _block->newTemp(); setLocation(move(_block->TEMP(newValue), binop(IR::OpAdd, _block->TEMP(oldValue), _block->CONST(IR::NumberType, 1), ast->incrementToken)), ast->incrementToken); setLocation(move(*expr, _block->TEMP(newValue)), ast->incrementToken); @@ -1949,10 +1985,12 @@ bool Codegen::visit(TildeExpression *ast) if (hasError) return false; + const unsigned t = _block->newTemp(); + TempScope scope(_function); + Result expr = expression(ast->expression); if (hasError) return false; - const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), unop(IR::OpCompl, *expr, ast->tildeToken)), ast->tildeToken); _expr.code = _block->TEMP(t); return false; @@ -1976,6 +2014,8 @@ bool Codegen::visit(TypeOfExpression *ast) if (hasError) return false; + TempScope scope(_function); + Result expr = expression(ast->expression); if (hasError) return false; @@ -2018,6 +2058,8 @@ bool Codegen::visit(VoidExpression *ast) if (hasError) return false; + TempScope scope(_function); + statement(ast->expression); _expr.code = _block->CONST(IR::UndefinedType, 0); return false; @@ -2028,6 +2070,8 @@ bool Codegen::visit(FunctionDeclaration * ast) if (hasError) return false; + TempScope scope(_function); + if (_env->compilationMode == QmlBinding) move(_block->TEMP(_returnAddress), _block->NAME(ast->name.toString(), 0, 0)); _expr.accept(nx); @@ -2190,6 +2234,8 @@ bool Codegen::visit(Block *ast) if (hasError) return false; + TempScope scope(_function); + for (StatementList *it = ast->statements; it; it = it->next) { statement(it->statement); } @@ -2201,6 +2247,8 @@ bool Codegen::visit(BreakStatement *ast) if (hasError) return false; + TempScope scope(_function); + if (!_loop) { throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Break outside of loop")); return false; @@ -2228,6 +2276,8 @@ bool Codegen::visit(ContinueStatement *ast) if (hasError) return false; + TempScope scope(_function); + Loop *loop = 0; if (ast->label.isEmpty()) { for (loop = _loop; loop; loop = loop->parent) { @@ -2267,6 +2317,8 @@ bool Codegen::visit(DoWhileStatement *ast) if (hasError) return true; + TempScope scope(_function); + IR::BasicBlock *loopbody = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *loopcond = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *loopend = _function->newBasicBlock(exceptionHandler()); @@ -2302,6 +2354,8 @@ bool Codegen::visit(ExpressionStatement *ast) if (hasError) return true; + TempScope scope(_function); + if (_env->compilationMode == EvalCode || _env->compilationMode == QmlBinding) { Result e = expression(ast->expression); if (*e) @@ -2317,6 +2371,8 @@ bool Codegen::visit(ForEachStatement *ast) if (hasError) return true; + TempScope scope(_function); + IR::BasicBlock *foreachin = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *foreachbody = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *foreachend = _function->newBasicBlock(exceptionHandler()); @@ -2363,6 +2419,8 @@ bool Codegen::visit(ForStatement *ast) if (hasError) return true; + TempScope scope(_function); + IR::BasicBlock *forcond = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *forbody = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *forstep = _function->newBasicBlock(exceptionHandler()); @@ -2399,6 +2457,8 @@ bool Codegen::visit(IfStatement *ast) if (hasError) return true; + TempScope scope(_function); + IR::BasicBlock *iftrue = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *iffalse = ast->ko ? _function->newBasicBlock(exceptionHandler()) : 0; IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler()); @@ -2425,6 +2485,8 @@ bool Codegen::visit(LabelledStatement *ast) if (hasError) return true; + TempScope scope(_function); + // check that no outer loop contains the label Loop *l = _loop; while (l) { @@ -2462,6 +2524,8 @@ bool Codegen::visit(LocalForEachStatement *ast) if (hasError) return true; + TempScope scope(_function); + IR::BasicBlock *foreachin = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *foreachbody = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *foreachend = _function->newBasicBlock(exceptionHandler()); @@ -2502,6 +2566,8 @@ bool Codegen::visit(LocalForStatement *ast) if (hasError) return true; + TempScope scope(_function); + IR::BasicBlock *forcond = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *forbody = _function->newBasicBlock(exceptionHandler()); IR::BasicBlock *forstep = _function->newBasicBlock(exceptionHandler()); @@ -2564,6 +2630,8 @@ bool Codegen::visit(SwitchStatement *ast) if (hasError) return true; + TempScope scope(_function); + IR::BasicBlock *switchend = _function->newBasicBlock(exceptionHandler()); if (ast->block) { @@ -2659,6 +2727,8 @@ bool Codegen::visit(ThrowStatement *ast) if (hasError) return true; + TempScope scope(_function); + Result expr = expression(ast->expression); move(_block->TEMP(_returnAddress), *expr); IR::ExprList *throwArgs = _function->New(); @@ -2672,6 +2742,8 @@ bool Codegen::visit(TryStatement *ast) if (hasError) return true; + TempScope scope(_function); + _function->hasTry = true; if (_function->isStrict && ast->catchExpression && @@ -2750,6 +2822,8 @@ bool Codegen::visit(TryStatement *ast) _function->addBasicBlock(finallyBody); _block = finallyBody; + TempScope scope(_function); + int hasException = _block->newTemp(); move(_block->TEMP(hasException), _block->CALL(_block->NAME(IR::Name::builtin_unwind_exception, /*line*/0, /*column*/0), 0)); @@ -2834,6 +2908,8 @@ bool Codegen::visit(WithStatement *ast) if (hasError) return true; + TempScope scope(_function); + _function->hasWith = true; const int withObject = _block->newTemp(); diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 742ee79648..1cbe6949a1 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -231,6 +231,17 @@ protected: } }; + struct TempScope { + TempScope(QV4::IR::Function *f) + : function(f), + tempCountForScope(f->currentTemp) {} + ~TempScope() { + function->currentTemp = tempCountForScope; + } + QV4::IR::Function *function; + int tempCountForScope; + }; + Environment *newEnvironment(AST::Node *node, Environment *parent, CompilationMode compilationMode) { Environment *env = new Environment(parent, compilationMode); @@ -293,7 +304,6 @@ protected: } QV4::IR::Expr *member(QV4::IR::Expr *base, const QString *name); - QV4::IR::Expr *subscript(QV4::IR::Expr *base, QV4::IR::Expr *index); QV4::IR::Expr *argument(QV4::IR::Expr *expr); QV4::IR::Expr *reference(QV4::IR::Expr *expr); QV4::IR::Expr *unop(QV4::IR::AluOp op, QV4::IR::Expr *expr, const AST::SourceLocation &loc = AST::SourceLocation()); diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index caab9c0f9e..6f14e3dfaf 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -1113,7 +1113,11 @@ public: return false; } - unsigned newTemp(); + enum TempForWhom { + NewTempForCodegen, + NewTempForOptimizer + }; + unsigned newTemp(TempForWhom tfw = NewTempForCodegen); Temp *TEMP(unsigned kind); ArgLocal *ARG(unsigned index, unsigned scope); @@ -1278,6 +1282,7 @@ struct Function { Module *module; QQmlJS::MemoryPool *pool; const QString *name; + int currentTemp = 0; int tempCount; int maxNumberOfArguments; QSet strings; @@ -1485,10 +1490,17 @@ protected: BasicBlock *currentBB; }; -inline unsigned BasicBlock::newTemp() +inline unsigned BasicBlock::newTemp(TempForWhom tfw) { Q_ASSERT(!isRemoved()); - return function->tempCount++; + + if (tfw == NewTempForOptimizer) + return function->tempCount++; + + int t = function->currentTemp++; + if (function->tempCount < function->currentTemp) + function->tempCount = function->currentTemp; + return t; } inline Temp *BasicBlock::TEMP(unsigned index) diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index fc136b09ff..8cf5fac760 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -2770,7 +2770,7 @@ public: } else if (Const *c = (*conversion.expr)->asConst()) { convertConst(c, conversion.targetType); } else if (ArgLocal *al = (*conversion.expr)->asArgLocal()) { - Temp *target = bb->TEMP(bb->newTemp()); + Temp *target = bb->TEMP(bb->newTemp(BasicBlock::NewTempForOptimizer)); target->type = conversion.targetType; Expr *convert = bb->CONVERT(al, conversion.targetType); Move *convCall = f->NewStmt(); @@ -2791,7 +2791,7 @@ public: *conversion.expr = source; } else if (Temp *t = (*conversion.expr)->asTemp()) { - Temp *target = bb->TEMP(bb->newTemp()); + Temp *target = bb->TEMP(bb->newTemp(BasicBlock::NewTempForOptimizer)); target->type = conversion.targetType; Expr *convert = bb->CONVERT(t, conversion.targetType); Move *convCall = f->NewStmt(); @@ -2820,7 +2820,7 @@ public: // to: // double{%3} = double{-double{%1}}; // int32{%2} = int32{convert(double{%3})}; - Temp *tmp = bb->TEMP(bb->newTemp()); + Temp *tmp = bb->TEMP(bb->newTemp(BasicBlock::NewTempForOptimizer)); tmp->type = u->type; Move *extraMove = f->NewStmt(); worklist.registerNewStatement(extraMove); -- cgit v1.2.3 From 939f07695b853a4da2e237c5f1c3d50e34f9c45c Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Thu, 8 Jun 2017 13:48:59 +0300 Subject: Use pre-generated QML caches even if they are not writable For example, if they are installed into system paths. Change-Id: Id14ccfbe57c5bcf273c79510034dc20400073451 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4compileddata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index ac4192bc12..485a5e6fb7 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -82,7 +82,7 @@ static QString cacheFilePath(const QUrl &url) { const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url); const QString localCachePath = localSourcePath + QLatin1Char('c'); - if (QFileInfo(QFileInfo(localSourcePath).dir().absolutePath()).isWritable()) + if (QFile::exists(localCachePath) || QFileInfo(QFileInfo(localSourcePath).dir().absolutePath()).isWritable()) return localCachePath; QCryptographicHash fileNameHash(QCryptographicHash::Sha1); fileNameHash.addData(localSourcePath.toUtf8()); -- cgit v1.2.3 From db6f1440cbe78018e442c1fb961310a4e619e8fe Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 9 Jun 2017 23:36:49 +0200 Subject: QQuickItemView: fix releaseItem() loops Calling releaseItem() destroys the item, which emits childrenChanged for the contentItem, and if at that point anything calls setFooMargin(), setContentHeight(), returnToBounds(), or many other methods that indirectly access the visibleItems list, it leads to a crash due to read after free. Add a releaseVisibleItems() helper method that makes a copy, clears the original list first, and then releases the items. Task-number: QTBUG-48394 Task-number: QTBUG-61294 Change-Id: I29e4d3870d33549e8bf789de84c67ab1826fca7d Reviewed-by: Robin Burchell --- src/quick/items/qquickgridview.cpp | 4 +--- src/quick/items/qquickitemview.cpp | 8 ++------ src/quick/items/qquickitemview_p_p.h | 9 +++++++++ src/quick/items/qquicklistview.cpp | 4 +--- 4 files changed, 13 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp index fd78c46a16..c570b95a21 100644 --- a/src/quick/items/qquickgridview.cpp +++ b/src/quick/items/qquickgridview.cpp @@ -495,9 +495,7 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal // We've jumped more than a page. Estimate which items are now // visible and fill from there. int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns; - for (FxViewItem *item : qAsConst(visibleItems)) - releaseItem(item); - visibleItems.clear(); + releaseVisibleItems(); modelIndex += count; if (modelIndex >= model->count()) modelIndex = model->count() - 1; diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 555db03962..084b1f197a 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -380,9 +380,7 @@ void QQuickItemView::setDelegate(QQmlComponent *delegate) int oldCount = dataModel->count(); dataModel->setDelegate(delegate); if (isComponentComplete()) { - for (FxViewItem *item : qAsConst(d->visibleItems)) - d->releaseItem(item); - d->visibleItems.clear(); + d->releaseVisibleItems(); d->releaseItem(d->currentItem); d->currentItem = 0; d->updateSectionCriteria(); @@ -1743,9 +1741,7 @@ void QQuickItemViewPrivate::clear() currentChanges.reset(); timeline.clear(); - for (FxViewItem *item : qAsConst(visibleItems)) - releaseItem(item); - visibleItems.clear(); + releaseVisibleItems(); visibleIndex = 0; for (FxViewItem *item : qAsConst(releasePendingTransition)) { diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h index 3087682ac7..b6353246e8 100644 --- a/src/quick/items/qquickitemview_p_p.h +++ b/src/quick/items/qquickitemview_p_p.h @@ -269,6 +269,15 @@ public: q->polish(); } + void releaseVisibleItems() { + // make a copy and clear the visibleItems first to avoid destroyed + // items being accessed during the loop (QTBUG-61294) + const QList oldVisible = visibleItems; + visibleItems.clear(); + for (FxViewItem *item : oldVisible) + releaseItem(item); + } + QPointer model; QVariant modelVariant; int itemCount; diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index f739115e6b..18f9b8512d 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -660,9 +660,7 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal int newModelIdx = qBound(0, modelIndex + count, model->count()); count = newModelIdx - modelIndex; if (count) { - for (FxViewItem *item : qAsConst(visibleItems)) - releaseItem(item); - visibleItems.clear(); + releaseVisibleItems(); modelIndex = newModelIdx; visibleIndex = modelIndex; visiblePos = itemEnd + count * (averageSize + spacing); -- cgit v1.2.3 From 5f2ec1a8c73fc7b6c20595110c0e04af21469082 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Thu, 12 Jan 2017 12:45:58 +0100 Subject: Doc: add doc and examples to RegExpValidator QML type Change-Id: I0ebc06aec6d2392f613fb4c312c189cc1d90a184 Reviewed-by: Venugopal Shivashankar --- src/quick/doc/snippets/qml/regexp.qml | 46 +++++++++++++++++++++++++++++++++++ src/quick/util/qquickvalidator.cpp | 13 ++++++++++ 2 files changed, 59 insertions(+) create mode 100644 src/quick/doc/snippets/qml/regexp.qml (limited to 'src') diff --git a/src/quick/doc/snippets/qml/regexp.qml b/src/quick/doc/snippets/qml/regexp.qml new file mode 100644 index 0000000000..c30336d418 --- /dev/null +++ b/src/quick/doc/snippets/qml/regexp.qml @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +import QtQuick 2.0 +//![0] +TextInput { + id: hexNumber + validator: RegExpValidator { regExp: /[0-9A-F]+/ } +} +//![0] diff --git a/src/quick/util/qquickvalidator.cpp b/src/quick/util/qquickvalidator.cpp index a05117bd06..93f414fe80 100644 --- a/src/quick/util/qquickvalidator.cpp +++ b/src/quick/util/qquickvalidator.cpp @@ -219,6 +219,19 @@ void QQuickDoubleValidator::resetLocaleName() matching "a". By default, this property contains a regular expression with the pattern .* that matches any string. + + Below you can find an example of a \l TextInput object with a RegExpValidator specified: + + \snippet qml/regexp.qml 0 + + Some more examples of regular expressions: + + \list + \li A list of numbers with one to three positions separated by a comma: + /\d{1,3}(?:,\d{1,3})+$/ + \li An amount consisting of up to 3 numbers before the decimal point, and + 1 to 2 after the decimal point: \li /(\d{1,3})([.,]\d{1,2})?$/ + \endlist */ #endif // validator -- cgit v1.2.3 From 3479810d0eb44b8fdc1478af6510a7e15541e26e Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Thu, 30 Mar 2017 16:13:49 +0200 Subject: Doc: correct link issues qqmlengine.cpp:2182: warning: Can't link to 'LocalStorage.openDatabaseSync()' qqmlengine.cpp:451: warning: Can't link to 'Window.screen' Change-Id: Ib2a3548805125366d7a81982fa2039f6b9341d9b Reviewed-by: Venugopal Shivashankar --- src/qml/qml/qqmlengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 1f6d1f3b57..f0564e7b33 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -590,7 +590,7 @@ The following functions are also on the Qt object. \li application.font \endlist - \sa Screen, Window, Window.screen + \sa Screen, Window, {QtQuick::Window::screen}{Window.screen} */ /*! -- cgit v1.2.3 From 84275fda5eaf709043572d6bbd76d5714c517af7 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Fri, 13 Jan 2017 16:03:29 +0100 Subject: Doc: add doc and snippet to model/view documentation Change-Id: I64dd815ae377dced7022fed11ab1922c5913e65d Reviewed-by: Edward Welbourne Reviewed-by: Venugopal Shivashankar --- .../doc/src/concepts/modelviewsdata/modelview.qdoc | 59 +++++++++++++++++----- .../doc/src/concepts/positioning/layouts.qdoc | 3 +- 2 files changed, 46 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc b/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc index 324fc9750f..47dcd6d98c 100644 --- a/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc +++ b/src/quick/doc/src/concepts/modelviewsdata/modelview.qdoc @@ -87,6 +87,7 @@ To visualize data, bind the view's \c model property to a model and the The club may decorate the members list by binding visual objects to the \c header and \c footer properties. The visual object may be defined inline, in another file, or in a \l {Component} type. + \snippet qml/listview-decorations.qml decorations \image listview-decorations.png @@ -102,7 +103,6 @@ To visualize data, bind the view's \c model property to a model and the will always ensure that the \c currentIndex is within the highlight range specified. - \section2 ListView Sections \l {ListView} contents may be grouped into \e sections, where related list @@ -195,7 +195,7 @@ To visualize data, bind the view's \c model property to a model and the Positioning of items from a model can be achieved using a \l{Repeater}. - \section2 ListModel + \section2 List Model ListModel is a simple hierarchy of types specified in QML. The available roles are specified by the \l ListElement properties. @@ -222,7 +222,7 @@ To visualize data, bind the view's \c model property to a model and the using the model. To reset the roles available in the model, call ListModel::clear(). - \section2 XmlListModel + \section2 XML Model XmlListModel allows construction of a model from an XML data source. The roles are specified via the \l XmlRole type. The type needs to be imported. @@ -244,23 +244,44 @@ To visualize data, bind the view's \c model property to a model and the } \endqml + The \c query property specifies that the XmlListModel generates a model item + for each \c in the XML document. + The \l{Qt Quick Demo - RSS News}{RSS News demo} shows how XmlListModel can be used to display an RSS feed. - \section2 VisualItemModel + \section2 Object Model + + ObjectModel contains the visual items to be used in a view. When an ObjectModel + is used in a view, the view does not require a delegate because the ObjectModel + already contains the visual delegate (items). - VisualItemModel allows QML items to be provided as a model. + The example below places three colored rectangles in a ListView. - This model contains both the data and delegate; the child items of a - VisualItemModel provide the contents of the delegate. The model - does not provide any roles. + \code + import QtQuick 2.0 + import QtQml.Models 2.1 + + Rectangle { + ObjectModel { + id: itemModel + Rectangle { height: 30; width: 80; color: "red" } + Rectangle { height: 30; width: 80; color: "green" } + Rectangle { height: 30; width: 80; color: "blue" } + } - \snippet qml/models/visual-model-and-view.qml visual model and view + ListView { + anchors.fill: parent + model: itemModel + } + } + \endcode - Note that in the above example there is no delegate required. - The items of the model itself provide the visual types that - will be positioned by the view. + \note VisualItemModel can also be used, but it is only provided for compatibility + reasons. VisualItemModel allows a QML item to be provided as a model. This model + contains both the data and delegate; the child items of a VisualItemModel + provide the contents of the delegate. The model does not provide any roles. \section2 Integers as Models @@ -357,8 +378,18 @@ rectangles for the Grid item to position in a 5 by 5 arrangement. The number of items created by a Repeater is held by its \l{Repeater::}{count} property. It is not possible to set this property to determine the number of items to be created. Instead, as in the above example, we use an integer as -the model. This is explained in the \l{qtquick-modelviewsdata-modelview.html#integers-as-models}{QML Data Models} -document. +the model. + +For more details, see the \l{qtquick-modelviewsdata-modelview.html#integers-as-models}{QML Data Models} document. + +If the model is a string list, the delegate is also exposed to a read-only +\c modelData property that holds the string. For example: + +\table + \row + \li \snippet qml/repeaters/repeater.qml modeldata + \li \image repeater-modeldata.png +\endtable It is also possible to use a delegate as the template for the items created by a Repeater. This is specified using the \l{Repeater::}{delegate} property. diff --git a/src/quick/doc/src/concepts/positioning/layouts.qdoc b/src/quick/doc/src/concepts/positioning/layouts.qdoc index 47ed2563f8..3824d17559 100644 --- a/src/quick/doc/src/concepts/positioning/layouts.qdoc +++ b/src/quick/doc/src/concepts/positioning/layouts.qdoc @@ -133,6 +133,5 @@ control of spacing between items and between lines of items. There are several other ways to position items in a user interface. In addition to the basic technique of specifying their coordinates directly, they can be positioned relative to other items with \l{anchor-layout}{anchors}, or used -with \l{QML Data Models} such as -\l{QML Data Models#VisualItemModel}{VisualItemModel}. +with \l{QML Data Models} such as \l{QML Data Models#Object Model}{Object Model}. */ -- cgit v1.2.3 From 7c27955968bab135b0e0db3a5f707efa86e80464 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Tue, 13 Jun 2017 13:40:10 +0300 Subject: Fix loading QML caches for qrc:/// urls Running examples/quick/window/window produces debug messages: "QML source file has moved to a different location." This is because QQmlFile::urlToLocalFileOrQrc(const QString &) overload is incompatible with QQmlFile::urlToLocalFileOrQrc(const QUrl &) when it deals with qrc:/// urls. For example it returns ":///window/window.qml" while the QUrl overload returns ":/window/window.qml". Thus the comparison of source paths in CompilationUnit::loadFromDisk() fails. Fix the incompatibility and add a test. Change-Id: I20449b8cf13d715d88860f2cd413ab39c893f3ef Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlfile.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp index 4e4db086b0..93c3e8e00c 100644 --- a/src/qml/qml/qqmlfile.cpp +++ b/src/qml/qml/qqmlfile.cpp @@ -603,6 +603,12 @@ empty string. */ QString QQmlFile::urlToLocalFileOrQrc(const QString& url) { + if (url.startsWith(QLatin1String("qrc://"), Qt::CaseInsensitive)) { + if (url.length() > 6) + return QLatin1Char(':') + url.midRef(6); + return QString(); + } + if (url.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive)) { if (url.length() > 4) return QLatin1Char(':') + url.midRef(4); -- cgit v1.2.3 From 99651acdf7f34ad976522f12eb89ea8fc19ee0a5 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Tue, 13 Jun 2017 09:23:09 +0200 Subject: qmltest: fix compare() for urls url is object, but without any property. Task-number: QTBUG-61297 Change-Id: I68b0523be54e4d42f57267205ba8d66ff4ac4e30 Reviewed-by: Edward Welbourne --- src/imports/testlib/TestCase.qml | 4 ++++ src/qmltest/quicktestresult.cpp | 6 ++++++ 2 files changed, 10 insertions(+) (limited to 'src') diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml index 18c70e1169..82211b5192 100644 --- a/src/imports/testlib/TestCase.qml +++ b/src/imports/testlib/TestCase.qml @@ -753,6 +753,10 @@ Item { bProperties.push(i); // collect exp's properties } + if (aProperties.length == 0 && bProperties.length == 0) { // at least a special case for QUrl + return eq && (JSON.stringify(act) == JSON.stringify(exp)); + } + // Ensures identical properties name return eq && qtest_compareInternal(aProperties.sort(), bProperties.sort()); diff --git a/src/qmltest/quicktestresult.cpp b/src/qmltest/quicktestresult.cpp index dc6caf505b..c4fb2b0f5f 100644 --- a/src/qmltest/quicktestresult.cpp +++ b/src/qmltest/quicktestresult.cpp @@ -512,6 +512,12 @@ void QuickTestResult::stringify(QQmlV4Function *args) result = QString::fromLatin1("Qt.vector3d(%1, %2, %3)").arg(v3d.x()).arg(v3d.y()).arg(v3d.z()); break; } + case QVariant::Url: + { + QUrl url = v.value(); + result = QString::fromLatin1("Qt.url(%1)").arg(url.toString()); + break; + } default: result = v.toString(); } -- cgit v1.2.3 From d2bb2e202427ebae545a408f065c893f3d837061 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 13 Jun 2017 09:42:54 +0200 Subject: Prospective build fix for qml compiler on Windows Do not try to decorate the internal MoveMapping class with an export macro that becomes an import macro on usage, when using it in the context of QtQmlDevTools. Change-Id: Id5349763572a144ac7d51d0af1f07d6cc19d683d Reviewed-by: Lars Knoll --- src/qml/compiler/qv4ssa_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h index 24257e99e9..b9d8ae0a6c 100644 --- a/src/qml/compiler/qv4ssa_p.h +++ b/src/qml/compiler/qv4ssa_p.h @@ -265,7 +265,7 @@ private: QHash startEndLoops; }; -class Q_AUTOTEST_EXPORT MoveMapping +class Q_QML_AUTOTEST_EXPORT MoveMapping { #ifdef V4_AUTOTEST public: -- cgit v1.2.3