diff options
629 files changed, 83831 insertions, 4864 deletions
diff --git a/.qmake.conf b/.qmake.conf index 879fb0fd88..2f6f96de99 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,4 +1,7 @@ load(qt_build_config) CONFIG += warning_clean -MODULE_VERSION = 5.14.0 +DEFINES += QT_NO_LINKED_LIST +DEFINES += QT_NO_JAVA_STYLE_ITERATORS + +MODULE_VERSION = 6.0.0 diff --git a/dist/changes-5.12.4 b/dist/changes-5.12.4 new file mode 100644 index 0000000000..d963e44e67 --- /dev/null +++ b/dist/changes-5.12.4 @@ -0,0 +1,90 @@ +Qt 5.12.4 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.0 through 5.12.3. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** + + - [QTBUG-14769] TextEdit now uses the I-beam cursor by default, and the + pointing hand cursor for links. However in C++ it's still possible to + override with a custom cursor. + - [QTBUG-70826] The QML Runtime tool now has an updated application icon + and a default window icon. QtQuick applications can still use + QWindow::setIcon() to override the window icon. + +**************************************************************************** +* QtQml * +**************************************************************************** + + - [QTBUG-75880] An anonymous function's "name" now comes directly from the + surrounding object pattern if applicable. This fixes some ecmascript tests + where functions were assigned to the key "eval" in an object. + - [QTBUG-75896] Fixed lookups of properties in QML singletons. + - [QTBUG-48809] We now print a warning when encountering a non-relative URL + in a qmldir file. You should use relative paths. + - [QTBUG-75609] Improved the cache for looking up attached properties objects, + to fix a performance regression in Qt Quick Layouts. + - [QTBUG-75392] Fixed a crash caused by std::function. + - [QTBUG-74048] Fixed a crash in QJSEngine::evaluate. + - [QTBUG-75501] lupdate now works better with the Qt Quick compiler. + - [QTBUG-75393] Fixed debugging of named signal arguments in Connections. + - [QTBUG-75410] Fixed maximum call stack depth for clang ASAN builds. + - [QTBUG-74815] We now allow creation of variants from non-singleton + QQmlTypeWrappers. + - [QTBUG-74815] Unknown types are no longer mis-identified as "null". + - [QTBUG-75335] Fixed a crash related to optimized heap lookups. + - [QTBUG-73217] The "QML debugging is enabled" warning is printed + normally rather than via a log message, which works better with + static builds. + - [QTBUG-75176] Fixed a crash on exit related to attached properties + on static builds. + - [QTBUG-75203] Fixed a crash when accessing invalid properties through + QObjectWrapper + - [QTBUG-71116] Errors in fetchOrCreateTypeForUrl are no longer fatal. + - [QTBUG-75121] Fixed an invalid capture in ECMAScript + string.replace(RegExp, backref) + - [QTBUG-74876] Fixed a crash in LinkBuffer's performFinalization. + - [QTBUG-74876] Fixed a memory leak when emitting QImage or QPixmap + as a signal argument. + - [QDS-589] qmlscene now supports file selectors. + - [QTBUG-74867] We now detect and reject cyclic aliases to avoid + infinite recursion. + - [QTBUG-74884] Configuration with -no-feature-delegate-model now works. + - [QTBUG-75030] Fixed an arithmetic exception related to bindings. + +**************************************************************************** +* QtQuick * +**************************************************************************** + + - [QTBUG-73768] Fixed a failing assertion in BorderImage when any border size + exceeds source image size. + - [QTBUG-75770] MouseArea no longer mis-identifies fast drags as double clicks. + - [QTBUG-75002] Accessibility: StaticText nodes are now properly marked as + read-only. + - [QTBUG-70083] Replaced PinchHandler qCInfo messages with qCDebug. + - [QTBUG-70083] Fixed the "no points" warning when using native gestures. + - [QTBUG-73182] Fixed a memory leak by optimizing storage of + QQuickEventPoint instances. + - [QTBUG-65761] Fixed input handling in QWebEngineView on eglfs. + - [QTBUG-51993] Canvas3D now works properly inside QQuickWidget. + - [QTBUG-74966] DragHandler no longer makes its target jump if you + start dragging in the margin area. + - [QTBUG-74679] Touch cancel now results in an ungrab event, so that + any parent flickable can filter the event, reset its state and be ready + to scroll again. diff --git a/dist/changes-5.13.0 b/dist/changes-5.13.0 new file mode 100644 index 0000000000..67c5d90e16 --- /dev/null +++ b/dist/changes-5.13.0 @@ -0,0 +1,98 @@ +Qt 5.13 introduces many new features and improvements as well as bugfixes +over the 5.12.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + + https://doc.qt.io/qt-5/index.html + +The Qt version 5.13 series is binary compatible with the 5.12.x series. +Applications compiled for 5.12 will continue to run with 5.13. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** + + - [QTBUG-68278] The Canvas requestAnimationFrame callback now gets passed a + millisecond timestamp instead of seconds. + +**************************************************************************** +* QtQml * +**************************************************************************** + + - Nested arrays are not flattened anymore when printed through console.log() + and friends. + - [QTBUG-72098] Assigning JavaScript null to incompatibly typed properties + generates a compile warning now. In future versions of Qt this will + become an error. + - [QTBUG-60057] QVariant's debug stream operator is now used in console.log() + and friends. This often includes more information than before, and + works better for custom types. + - [QTBUG-74068] Qt.include() is deprecated in favor of ECMAScript modules. + - [QTBUG-60338] Added support for QSequentialIterable in QML, meaning + that the engine understands many sequential value types (such as lists + of Q_GADGETS) and is able to convert them to JS arrays. + - [QTBUG-66504] QmlDebug has new features to improve integration with + external tools and IDEs. + - [QTBUG-50061] Global exception handlers are now called reliably by + unwinding JIT-generated code via a function table. + - [QTBUG-72294] Fixed a function table error on WinRT. + - [QTBUG-72430] Added the QTQUICK_COMPILER_RETAINED_RESOURCES option to + retain sources when generating QML cache files. + - [QTBUG-72930] A Component can no longer be assigned to properties of other types. + - [QTBUG-71838] LocalStorage now returns the new database version + from changeVersion() without reopening the connection. + + - qml: + * [QTBUG-70826][QTBUG-74662] The QML Runtime tool now has an updated + application icon and a default window icon. QtQuick applications can + still use QWindow::setIcon() to override the window icon. + + - qmlscene: + * [QDS-589] qmlscene now supports file selectors. + +**************************************************************************** +* QtQuick * +**************************************************************************** + + - Item Views: + * Added itemAtIndex() to GridView, ListView and PathView to fetch a visible + delegate by index. + + - TableView: + * Added support for hiding rows and columns by setting their size to 0 from + the columnsWidthProvider/rowHeightProvider. + + - Text: + * [QTBUG-32525][QTBUG-70748] Inline images in a QTextDocumentLayout are + now displayed in Text and friends. + * [QTBUG-68711] Fixed Keys.onShortcutOverride for TextEdit + * [QTBUG-50587] Fixed persistentSelection for readonly TextEdit + * [QTBUG-72736] Text wrapping no longer breaks on the last line if right + elide is enabled + + - Window: + * [QTBUG-67903] Added the Window.transientParent property. QtQuick normally + guesses the transient parent relationship from the nesting of declarations, + but now you can override this "magic" by setting it explicitly. + * [QTBUG-73929] Fixed a race condition when closing windows. + +**************************************************************************** +* QtQuickTest * +**************************************************************************** + + - [QTBUG-71224] Added QQuickTest::qWaitForItemPolished() for verifying that + updatePolish() was called on an item. + - [QTBUG-71224] Added qIsPolishScheduled() function to allow checking if + updatePolish() has been called on an item since the last call to its + polish() function. This is useful to verify that a polish has been + scheduled. + - Added TestCase.isPolishScheduled() function to allow checking whether + updatePolish() has been called on an item since the last call to its polish() + function. This is useful to verify that a polish has been scheduled. diff --git a/examples/qml/referenceexamples/extended/lineedit.cpp b/examples/qml/referenceexamples/extended/lineedit.cpp index f2f5ec0efc..777e15db07 100644 --- a/examples/qml/referenceexamples/extended/lineedit.cpp +++ b/examples/qml/referenceexamples/extended/lineedit.cpp @@ -57,58 +57,50 @@ LineEditExtension::LineEditExtension(QObject *object) int LineEditExtension::leftMargin() const { - int l, r, t, b; - m_lineedit->getTextMargins(&l, &t, &r, &b); - return l; + return m_lineedit->textMargins().left(); } -void LineEditExtension::setLeftMargin(int m) +void LineEditExtension::setLeftMargin(int l) { - int l, r, t, b; - m_lineedit->getTextMargins(&l, &t, &r, &b); - m_lineedit->setTextMargins(m, t, r, b); + QMargins m = m_lineedit->textMargins(); + m.setLeft(l); + m_lineedit->setTextMargins(m); } int LineEditExtension::rightMargin() const { - int l, r, t, b; - m_lineedit->getTextMargins(&l, &t, &r, &b); - return r; + return m_lineedit->textMargins().right(); } -void LineEditExtension::setRightMargin(int m) +void LineEditExtension::setRightMargin(int r) { - int l, r, t, b; - m_lineedit->getTextMargins(&l, &t, &r, &b); - m_lineedit->setTextMargins(l, t, m, b); + QMargins m = m_lineedit->textMargins(); + m.setRight(r); + m_lineedit->setTextMargins(m); } int LineEditExtension::topMargin() const { - int l, r, t, b; - m_lineedit->getTextMargins(&l, &t, &r, &b); - return t; + return m_lineedit->textMargins().top(); } -void LineEditExtension::setTopMargin(int m) +void LineEditExtension::setTopMargin(int t) { - int l, r, t, b; - m_lineedit->getTextMargins(&l, &t, &r, &b); - m_lineedit->setTextMargins(l, m, r, b); + QMargins m = m_lineedit->textMargins(); + m.setTop(t); + m_lineedit->setTextMargins(m); } int LineEditExtension::bottomMargin() const { - int l, r, t, b; - m_lineedit->getTextMargins(&l, &t, &r, &b); - return b; + return m_lineedit->textMargins().bottom(); } -void LineEditExtension::setBottomMargin(int m) +void LineEditExtension::setBottomMargin(int b) { - int l, r, t, b; - m_lineedit->getTextMargins(&l, &t, &r, &b); - m_lineedit->setTextMargins(l, t, r, m); + QMargins m = m_lineedit->textMargins(); + m.setBottom(b); + m_lineedit->setTextMargins(m); } diff --git a/examples/quick/imageresponseprovider/imageresponseprovider.cpp b/examples/quick/imageresponseprovider/imageresponseprovider.cpp index 4f7c12b1d8..32510dbec8 100644 --- a/examples/quick/imageresponseprovider/imageresponseprovider.cpp +++ b/examples/quick/imageresponseprovider/imageresponseprovider.cpp @@ -57,40 +57,60 @@ #include <QImage> #include <QThreadPool> -class AsyncImageResponse : public QQuickImageResponse, public QRunnable +class AsyncImageResponseRunnable : public QObject, public QRunnable +{ + Q_OBJECT + +signals: + void done(QImage image); + +public: + AsyncImageResponseRunnable(const QString &id, const QSize &requestedSize) + : m_id(id), m_requestedSize(requestedSize) {} + + void run() override + { + auto image = QImage(50, 50, QImage::Format_RGB32); + if (m_id == QLatin1String("slow")) { + qDebug() << "Slow, red, sleeping for 5 seconds"; + QThread::sleep(5); + image.fill(Qt::red); + } else { + qDebug() << "Fast, blue, sleeping for 1 second"; + QThread::sleep(1); + image.fill(Qt::blue); + } + if (m_requestedSize.isValid()) + image = image.scaled(m_requestedSize); + + emit done(image); + } + +private: + QString m_id; + QSize m_requestedSize; +}; + +class AsyncImageResponse : public QQuickImageResponse { public: - AsyncImageResponse(const QString &id, const QSize &requestedSize) - : m_id(id), m_requestedSize(requestedSize) + AsyncImageResponse(const QString &id, const QSize &requestedSize, QThreadPool *pool) { - setAutoDelete(false); + auto runnable = new AsyncImageResponseRunnable(id, requestedSize); + connect(runnable, &AsyncImageResponseRunnable::done, this, &AsyncImageResponse::handleDone); + pool->start(runnable); } - QQuickTextureFactory *textureFactory() const override - { - return QQuickTextureFactory::textureFactoryForImage(m_image); + void handleDone(QImage image) { + m_image = image; + emit finished(); } - void run() override + QQuickTextureFactory *textureFactory() const override { - m_image = QImage(50, 50, QImage::Format_RGB32); - if (m_id == "slow") { - qDebug() << "Slow, red, sleeping for 5 seconds"; - QThread::sleep(5); - m_image.fill(Qt::red); - } else { - qDebug() << "Fast, blue, sleeping for 1 second"; - QThread::sleep(1); - m_image.fill(Qt::blue); - } - if (m_requestedSize.isValid()) - m_image = m_image.scaled(m_requestedSize); - - emit finished(); + return QQuickTextureFactory::textureFactoryForImage(m_image); } - QString m_id; - QSize m_requestedSize; QImage m_image; }; @@ -99,8 +119,7 @@ class AsyncImageProvider : public QQuickAsyncImageProvider public: QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override { - AsyncImageResponse *response = new AsyncImageResponse(id, requestedSize); - pool.start(response); + AsyncImageResponse *response = new AsyncImageResponse(id, requestedSize, &pool); return response; } diff --git a/examples/quick/localstorage/localstorage/Header.qml b/examples/quick/localstorage/localstorage/Header.qml index 18f51c1b6e..b3807f6e40 100644 --- a/examples/quick/localstorage/localstorage/Header.qml +++ b/examples/quick/localstorage/localstorage/Header.qml @@ -48,7 +48,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -import QtQuick 2.7 +import QtQuick 2.14 import QtQuick.Window 2.0 import QtQuick.LocalStorage 2.0 import "Database.js" as JS @@ -143,8 +143,8 @@ Item { font.pixelSize: 22 activeFocusOnPress: true activeFocusOnTab: true - validator: RegExpValidator { - regExp: /[0-9/,:.]+/ + validator: RegularExpressionValidator { + regularExpression: /[0-9/,:.]+/ } onEditingFinished: { if (dateInput.text == "") { @@ -174,8 +174,8 @@ Item { font.pixelSize: 22 activeFocusOnPress: true activeFocusOnTab: true - validator: RegExpValidator { - regExp: /\d{1,3}/ + validator: RegularExpressionValidator { + regularExpression: /\d{1,3}/ } onEditingFinished: { if (distInput.text == "") { diff --git a/examples/quick/scenegraph/d3d11underqml/d3d11squircle.cpp b/examples/quick/scenegraph/d3d11underqml/d3d11squircle.cpp new file mode 100644 index 0000000000..f05bf2f843 --- /dev/null +++ b/examples/quick/scenegraph/d3d11underqml/d3d11squircle.cpp @@ -0,0 +1,426 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the demonstration applications 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 "d3d11squircle.h" +#include <QtCore/QRunnable> +#include <QtQuick/QQuickWindow> + +#include <d3d11.h> +#include <d3dcompiler.h> + +class SquircleRenderer : public QObject +{ + Q_OBJECT +public: + SquircleRenderer(); + ~SquircleRenderer(); + + void setT(qreal t) { m_t = t; } + void setViewportSize(const QSize &size) { m_viewportSize = size; } + void setWindow(QQuickWindow *window) { m_window = window; } + +public slots: + void frameStart(); + void mainPassRecordingStart(); + +private: + enum Stage { + VertexStage, + FragmentStage + }; + void prepareShader(Stage stage); + QByteArray compileShader(Stage stage, + const QByteArray &source, + const QByteArray &entryPoint); + void init(); + + QSize m_viewportSize; + qreal m_t; + QQuickWindow *m_window; + + ID3D11Device *m_device = nullptr; + ID3D11DeviceContext *m_context = nullptr; + QByteArray m_vert; + QByteArray m_vertEntryPoint; + QByteArray m_frag; + QByteArray m_fragEntryPoint; + + bool m_initialized = false; + ID3D11Buffer *m_vbuf = nullptr; + ID3D11Buffer *m_cbuf = nullptr; + ID3D11VertexShader *m_vs = nullptr; + ID3D11PixelShader *m_ps = nullptr; + ID3D11InputLayout *m_inputLayout = nullptr; + ID3D11RasterizerState *m_rastState = nullptr; + ID3D11DepthStencilState *m_dsState = nullptr; + ID3D11BlendState *m_blendState = nullptr; +}; + +D3D11Squircle::D3D11Squircle() + : m_t(0) + , m_renderer(nullptr) +{ + connect(this, &QQuickItem::windowChanged, this, &D3D11Squircle::handleWindowChanged); +} + +void D3D11Squircle::setT(qreal t) +{ + if (t == m_t) + return; + m_t = t; + emit tChanged(); + if (window()) + window()->update(); +} + +void D3D11Squircle::handleWindowChanged(QQuickWindow *win) +{ + if (win) { + connect(win, &QQuickWindow::beforeSynchronizing, this, &D3D11Squircle::sync, Qt::DirectConnection); + connect(win, &QQuickWindow::sceneGraphInvalidated, this, &D3D11Squircle::cleanup, Qt::DirectConnection); + + // Ensure we start with cleared to black. The squircle's blend mode relies on this. + win->setColor(Qt::black); + } +} + +SquircleRenderer::SquircleRenderer() + : m_t(0) +{ +} + +// The safe way to release custom graphics resources it to both connect to +// sceneGraphInvalidated() and implement releaseResources(). To support +// threaded render loops the latter performs the SquircleRenderer destruction +// via scheduleRenderJob(). Note that the D3D11Squircle may be gone by the time +// the QRunnable is invoked. + +void D3D11Squircle::cleanup() +{ + delete m_renderer; + m_renderer = nullptr; +} + +class CleanupJob : public QRunnable +{ +public: + CleanupJob(SquircleRenderer *renderer) : m_renderer(renderer) { } + void run() override { delete m_renderer; } +private: + SquircleRenderer *m_renderer; +}; + +void D3D11Squircle::releaseResources() +{ + window()->scheduleRenderJob(new CleanupJob(m_renderer), QQuickWindow::BeforeSynchronizingStage); + m_renderer = nullptr; +} + +SquircleRenderer::~SquircleRenderer() +{ + qDebug("cleanup"); + + if (m_vs) + m_vs->Release(); + + if (m_ps) + m_ps->Release(); + + if (m_vbuf) + m_vbuf->Release(); + + if (m_cbuf) + m_cbuf->Release(); + + if (m_inputLayout) + m_inputLayout->Release(); + + if (m_rastState) + m_rastState->Release(); + + if (m_dsState) + m_dsState->Release(); + + if (m_blendState) + m_blendState->Release(); +} + +void D3D11Squircle::sync() +{ + if (!m_renderer) { + m_renderer = new SquircleRenderer; + connect(window(), &QQuickWindow::beforeRendering, m_renderer, &SquircleRenderer::frameStart, Qt::DirectConnection); + connect(window(), &QQuickWindow::beforeRenderPassRecording, m_renderer, &SquircleRenderer::mainPassRecordingStart, Qt::DirectConnection); + } + m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio()); + m_renderer->setT(m_t); + m_renderer->setWindow(window()); +} + +void SquircleRenderer::frameStart() +{ + QSGRendererInterface *rif = m_window->rendererInterface(); + + // We are not prepared for anything other than running with the RHI and its D3D11 backend. + Q_ASSERT(rif->graphicsApi() == QSGRendererInterface::Direct3D11Rhi); + + m_device = reinterpret_cast<ID3D11Device *>(rif->getResource(m_window, QSGRendererInterface::DeviceResource)); + Q_ASSERT(m_device); + m_context = reinterpret_cast<ID3D11DeviceContext *>(rif->getResource(m_window, QSGRendererInterface::DeviceContextResource)); + Q_ASSERT(m_context); + + if (m_vert.isEmpty()) + prepareShader(VertexStage); + if (m_frag.isEmpty()) + prepareShader(FragmentStage); + + if (!m_initialized) + init(); +} + +static const float vertices[] = { + -1, -1, + 1, -1, + -1, 1, + 1, 1 +}; + +void SquircleRenderer::mainPassRecordingStart() +{ + m_window->beginExternalCommands(); + + D3D11_MAPPED_SUBRESOURCE mp; + // will copy the entire constant buffer every time -> pass WRITE_DISCARD -> prevent pipeline stalls + HRESULT hr = m_context->Map(m_cbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &mp); + if (SUCCEEDED(hr)) { + float t = m_t; + memcpy(mp.pData, &t, 4); + m_context->Unmap(m_cbuf, 0); + } else { + qFatal("Failed to map constant buffer: 0x%x", hr); + } + + D3D11_VIEWPORT v; + v.TopLeftX = 0; + v.TopLeftY = 0; + v.Width = m_viewportSize.width(); + v.Height = m_viewportSize.height(); + v.MinDepth = 0; + v.MaxDepth = 1; + m_context->RSSetViewports(1, &v); + + m_context->VSSetShader(m_vs, nullptr, 0); + m_context->PSSetShader(m_ps, nullptr, 0); + m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + m_context->IASetInputLayout(m_inputLayout); + m_context->OMSetDepthStencilState(m_dsState, 0); + float blendConstants[] = { 1, 1, 1, 1 }; + m_context->OMSetBlendState(m_blendState, blendConstants, 0xFFFFFFFF); + m_context->RSSetState(m_rastState); + + const UINT stride = 2 * sizeof(float); // vec2 + const UINT offset = 0; + m_context->IASetVertexBuffers(0, 1, &m_vbuf, &stride, &offset); + m_context->PSSetConstantBuffers(0, 1, &m_cbuf); + + m_context->Draw(4, 0); + + m_window->endExternalCommands(); +} + +void SquircleRenderer::prepareShader(Stage stage) +{ + QString filename; + if (stage == VertexStage) { + filename = QLatin1String(":/scenegraph/d3d11underqml/squircle.vert"); + } else { + Q_ASSERT(stage == FragmentStage); + filename = QLatin1String(":/scenegraph/d3d11underqml/squircle.frag"); + } + QFile f(filename); + if (!f.open(QIODevice::ReadOnly)) + qFatal("Failed to read shader %s", qPrintable(filename)); + + const QByteArray contents = f.readAll(); + + if (stage == VertexStage) { + m_vert = contents; + Q_ASSERT(!m_vert.isEmpty()); + m_vertEntryPoint = QByteArrayLiteral("main"); + } else { + m_frag = contents; + Q_ASSERT(!m_frag.isEmpty()); + m_fragEntryPoint = QByteArrayLiteral("main"); + } +} + +QByteArray SquircleRenderer::compileShader(Stage stage, + const QByteArray &source, + const QByteArray &entryPoint) +{ + const char *target; + switch (stage) { + case VertexStage: + target = "vs_5_0"; + break; + case FragmentStage: + target = "ps_5_0"; + break; + default: + qFatal("Unknown shader stage %d", stage); + return QByteArray(); + } + + ID3DBlob *bytecode = nullptr; + ID3DBlob *errors = nullptr; + HRESULT hr = D3DCompile(source.constData(), source.size(), + nullptr, nullptr, nullptr, + entryPoint.constData(), target, 0, 0, &bytecode, &errors); + if (FAILED(hr) || !bytecode) { + qWarning("HLSL shader compilation failed: 0x%x", uint(hr)); + if (errors) { + const QByteArray msg(static_cast<const char *>(errors->GetBufferPointer()), + errors->GetBufferSize()); + errors->Release(); + qWarning("%s", msg.constData()); + } + return QByteArray(); + } + + QByteArray result; + result.resize(bytecode->GetBufferSize()); + memcpy(result.data(), bytecode->GetBufferPointer(), result.size()); + bytecode->Release(); + + return result; +} + +void SquircleRenderer::init() +{ + qDebug("init"); + m_initialized = true; + + const QByteArray vs = compileShader(VertexStage, m_vert, m_vertEntryPoint); + const QByteArray fs = compileShader(FragmentStage, m_frag, m_fragEntryPoint); + + HRESULT hr = m_device->CreateVertexShader(vs.constData(), vs.size(), nullptr, &m_vs); + if (FAILED(hr)) + qFatal("Failed to create vertex shader: 0x%x", hr); + + hr = m_device->CreatePixelShader(fs.constData(), fs.size(), nullptr, &m_ps); + if (FAILED(hr)) + qFatal("Failed to create pixel shader: 0x%x", hr); + + D3D11_BUFFER_DESC bufDesc; + memset(&bufDesc, 0, sizeof(bufDesc)); + bufDesc.ByteWidth = sizeof(vertices); + bufDesc.Usage = D3D11_USAGE_DEFAULT; + bufDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + hr = m_device->CreateBuffer(&bufDesc, nullptr, &m_vbuf); + if (FAILED(hr)) + qFatal("Failed to create buffer: 0x%x", hr); + + m_context->UpdateSubresource(m_vbuf, 0, nullptr, vertices, 0, 0); + + bufDesc.ByteWidth = 256; + bufDesc.Usage = D3D11_USAGE_DYNAMIC; + bufDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + bufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + hr = m_device->CreateBuffer(&bufDesc, nullptr, &m_cbuf); + if (FAILED(hr)) + qFatal("Failed to create buffer: 0x%x", hr); + + D3D11_INPUT_ELEMENT_DESC inputDesc; + memset(&inputDesc, 0, sizeof(inputDesc)); + // the output from SPIRV-Cross uses TEXCOORD<location> as the semantic + inputDesc.SemanticName = "TEXCOORD"; + inputDesc.SemanticIndex = 0; + inputDesc.Format = DXGI_FORMAT_R32G32_FLOAT; // vec2 + inputDesc.InputSlot = 0; + inputDesc.AlignedByteOffset = 0; + inputDesc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + hr = m_device->CreateInputLayout(&inputDesc, 1, vs.constData(), vs.size(), &m_inputLayout); + if (FAILED(hr)) + qFatal("Failed to create input layout: 0x%x", hr); + + D3D11_RASTERIZER_DESC rastDesc; + memset(&rastDesc, 0, sizeof(rastDesc)); + rastDesc.FillMode = D3D11_FILL_SOLID; + rastDesc.CullMode = D3D11_CULL_NONE; + hr = m_device->CreateRasterizerState(&rastDesc, &m_rastState); + if (FAILED(hr)) + qFatal("Failed to create rasterizer state: 0x%x", hr); + + D3D11_DEPTH_STENCIL_DESC dsDesc; + memset(&dsDesc, 0, sizeof(dsDesc)); + hr = m_device->CreateDepthStencilState(&dsDesc, &m_dsState); + if (FAILED(hr)) + qFatal("Failed to create depth/stencil state: 0x%x", hr); + + D3D11_BLEND_DESC blendDesc; + memset(&blendDesc, 0, sizeof(blendDesc)); + blendDesc.IndependentBlendEnable = true; + D3D11_RENDER_TARGET_BLEND_DESC blend; + memset(&blend, 0, sizeof(blend)); + blend.BlendEnable = true; + blend.SrcBlend = D3D11_BLEND_SRC_ALPHA; + blend.DestBlend = D3D11_BLEND_ONE; + blend.BlendOp = D3D11_BLEND_OP_ADD; + blend.SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; + blend.DestBlendAlpha = D3D11_BLEND_ONE; + blend.BlendOpAlpha = D3D11_BLEND_OP_ADD; + blend.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + blendDesc.RenderTarget[0] = blend; + hr = m_device->CreateBlendState(&blendDesc, &m_blendState); + if (FAILED(hr)) + qFatal("Failed to create blend state: 0x%x", hr); +} + +#include "d3d11squircle.moc" diff --git a/examples/quick/scenegraph/d3d11underqml/d3d11squircle.h b/examples/quick/scenegraph/d3d11underqml/d3d11squircle.h new file mode 100644 index 0000000000..be9aadc43b --- /dev/null +++ b/examples/quick/scenegraph/d3d11underqml/d3d11squircle.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the demonstration applications 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 D3D11SQUIRCLE_H +#define D3D11SQUIRCLE_H + +#include <QtQuick/QQuickItem> + +class SquircleRenderer; + +class D3D11Squircle : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged) + +public: + D3D11Squircle(); + + qreal t() const { return m_t; } + void setT(qreal t); + +signals: + void tChanged(); + +public slots: + void sync(); + void cleanup(); + +private slots: + void handleWindowChanged(QQuickWindow *win); + +private: + void releaseResources() override; + + qreal m_t; + SquircleRenderer *m_renderer = nullptr; +}; + +#endif diff --git a/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro b/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro new file mode 100644 index 0000000000..3c94d48ac4 --- /dev/null +++ b/examples/quick/scenegraph/d3d11underqml/d3d11underqml.pro @@ -0,0 +1,10 @@ +QT += qml quick + +HEADERS += d3d11squircle.h +SOURCES += d3d11squircle.cpp main.cpp +RESOURCES += d3d11underqml.qrc + +LIBS += -ld3d11 -ld3dcompiler + +target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/d3d11underqml +INSTALLS += target diff --git a/examples/quick/scenegraph/d3d11underqml/d3d11underqml.qrc b/examples/quick/scenegraph/d3d11underqml/d3d11underqml.qrc new file mode 100644 index 0000000000..fa16b88279 --- /dev/null +++ b/examples/quick/scenegraph/d3d11underqml/d3d11underqml.qrc @@ -0,0 +1,7 @@ +<RCC> + <qresource prefix="/scenegraph/d3d11underqml"> + <file>main.qml</file> + <file>squircle.vert</file> + <file>squircle.frag</file> + </qresource> +</RCC> diff --git a/examples/quick/scenegraph/d3d11underqml/main.cpp b/examples/quick/scenegraph/d3d11underqml/main.cpp new file mode 100644 index 0000000000..d26de1144a --- /dev/null +++ b/examples/quick/scenegraph/d3d11underqml/main.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the demonstration applications 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 <QGuiApplication> +#include <QtQuick/QQuickView> +#include "d3d11squircle.h" + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + qmlRegisterType<D3D11Squircle>("D3D11UnderQML", 1, 0, "D3D11Squircle"); + + QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Direct3D11Rhi); + + QQuickView view; + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl("qrc:///scenegraph/d3d11underqml/main.qml")); + view.show(); + + return app.exec(); +} diff --git a/examples/quick/scenegraph/d3d11underqml/main.qml b/examples/quick/scenegraph/d3d11underqml/main.qml new file mode 100644 index 0000000000..da128bead6 --- /dev/null +++ b/examples/quick/scenegraph/d3d11underqml/main.qml @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the demonstration applications 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$ +** +****************************************************************************/ + +//! [1] +import QtQuick 2.0 +import D3D11UnderQML 1.0 + +Item { + + width: 320 + height: 480 + + D3D11Squircle { + SequentialAnimation on t { + NumberAnimation { to: 1; duration: 2500; easing.type: Easing.InQuad } + NumberAnimation { to: 0; duration: 2500; easing.type: Easing.OutQuad } + loops: Animation.Infinite + running: true + } + } +//! [1] //! [2] + Rectangle { + color: Qt.rgba(1, 1, 1, 0.7) + radius: 10 + border.width: 1 + border.color: "white" + anchors.fill: label + anchors.margins: -10 + } + + Text { + id: label + color: "black" + wrapMode: Text.WordWrap + text: "The background here is a squircle rendered with raw Direct3D 11 using the beforeRendering() and beforeRenderPassRecording() signals in QQuickWindow. This text label and its border is rendered using QML" + anchors.right: parent.right + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.margins: 20 + } +} +//! [2] diff --git a/examples/quick/scenegraph/d3d11underqml/squircle.frag b/examples/quick/scenegraph/d3d11underqml/squircle.frag new file mode 100644 index 0000000000..a907c84e58 --- /dev/null +++ b/examples/quick/scenegraph/d3d11underqml/squircle.frag @@ -0,0 +1,35 @@ +cbuffer buf : register(b0) +{ + float ubuf_t : packoffset(c0); +}; + + +static float2 coords; +static float4 fragColor; + +struct SPIRV_Cross_Input +{ + float2 coords : TEXCOORD0; +}; + +struct SPIRV_Cross_Output +{ + float4 fragColor : SV_Target0; +}; + +void frag_main() +{ + float i = 1.0f - (pow(abs(coords.x), 4.0f) + pow(abs(coords.y), 4.0f)); + i = smoothstep(ubuf_t - 0.800000011920928955078125f, ubuf_t + 0.800000011920928955078125f, i); + i = floor(i * 20.0f) / 20.0f; + fragColor = float4((coords * 0.5f) + 0.5f.xx, i, i); +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + coords = stage_input.coords; + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.fragColor = fragColor; + return stage_output; +} diff --git a/examples/quick/scenegraph/d3d11underqml/squircle.vert b/examples/quick/scenegraph/d3d11underqml/squircle.vert new file mode 100644 index 0000000000..077a1ad096 --- /dev/null +++ b/examples/quick/scenegraph/d3d11underqml/squircle.vert @@ -0,0 +1,30 @@ +static float4 gl_Position; +static float4 vertices; +static float2 coords; + +struct SPIRV_Cross_Input +{ + float4 vertices : TEXCOORD0; +}; + +struct SPIRV_Cross_Output +{ + float2 coords : TEXCOORD0; + float4 gl_Position : SV_Position; +}; + +void vert_main() +{ + gl_Position = vertices; + coords = vertices.xy; +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + vertices = stage_input.vertices; + vert_main(); + SPIRV_Cross_Output stage_output; + stage_output.gl_Position = gl_Position; + stage_output.coords = coords; + return stage_output; +} diff --git a/examples/quick/scenegraph/metalunderqml/main.cpp b/examples/quick/scenegraph/metalunderqml/main.cpp new file mode 100644 index 0000000000..5ad337abb1 --- /dev/null +++ b/examples/quick/scenegraph/metalunderqml/main.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the demonstration applications 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 <QGuiApplication> +#include <QtQuick/QQuickView> +#include "metalsquircle.h" + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + qmlRegisterType<MetalSquircle>("MetalUnderQML", 1, 0, "MetalSquircle"); + + QQuickWindow::setSceneGraphBackend(QSGRendererInterface::MetalRhi); + + QQuickView view; + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl("qrc:///scenegraph/metalunderqml/main.qml")); + view.show(); + + return app.exec(); +} diff --git a/examples/quick/scenegraph/metalunderqml/main.qml b/examples/quick/scenegraph/metalunderqml/main.qml new file mode 100644 index 0000000000..d41a0b8e81 --- /dev/null +++ b/examples/quick/scenegraph/metalunderqml/main.qml @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the demonstration applications 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$ +** +****************************************************************************/ + +//! [1] +import QtQuick 2.0 +import MetalUnderQML 1.0 + +Item { + + width: 320 + height: 480 + + MetalSquircle { + SequentialAnimation on t { + NumberAnimation { to: 1; duration: 2500; easing.type: Easing.InQuad } + NumberAnimation { to: 0; duration: 2500; easing.type: Easing.OutQuad } + loops: Animation.Infinite + running: true + } + } +//! [1] //! [2] + Rectangle { + color: Qt.rgba(1, 1, 1, 0.7) + radius: 10 + border.width: 1 + border.color: "white" + anchors.fill: label + anchors.margins: -10 + } + + Text { + id: label + color: "black" + wrapMode: Text.WordWrap + text: "The background here is a squircle rendered with raw Metal using the beforeRendering() and beforeRenderPassRecording() signals in QQuickWindow. This text label and its border is rendered using QML" + anchors.right: parent.right + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.margins: 20 + } +} +//! [2] diff --git a/examples/quick/scenegraph/metalunderqml/metalsquircle.h b/examples/quick/scenegraph/metalunderqml/metalsquircle.h new file mode 100644 index 0000000000..43c4afad21 --- /dev/null +++ b/examples/quick/scenegraph/metalunderqml/metalsquircle.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the demonstration applications 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 METALSQUIRCLE_H +#define METALSQUIRCLE_H + +#include <QtQuick/QQuickItem> + +class SquircleRenderer; + +class MetalSquircle : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged) + +public: + MetalSquircle(); + + qreal t() const { return m_t; } + void setT(qreal t); + +signals: + void tChanged(); + +public slots: + void sync(); + void cleanup(); + +private slots: + void handleWindowChanged(QQuickWindow *win); + +private: + void releaseResources() override; + + qreal m_t; + SquircleRenderer *m_renderer = nullptr; +}; + +#endif diff --git a/examples/quick/scenegraph/metalunderqml/metalsquircle.mm b/examples/quick/scenegraph/metalunderqml/metalsquircle.mm new file mode 100644 index 0000000000..92aceeb433 --- /dev/null +++ b/examples/quick/scenegraph/metalunderqml/metalsquircle.mm @@ -0,0 +1,364 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the demonstration applications 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 "metalsquircle.h" +#include <QtCore/QRunnable> +#include <QtQuick/QQuickWindow> + +#include <Metal/Metal.h> + +class SquircleRenderer : public QObject +{ + Q_OBJECT +public: + SquircleRenderer(); + ~SquircleRenderer(); + + void setT(qreal t) { m_t = t; } + void setViewportSize(const QSize &size) { m_viewportSize = size; } + void setWindow(QQuickWindow *window) { m_window = window; } + +public slots: + void frameStart(); + void mainPassRecordingStart(); + +private: + enum Stage { + VertexStage, + FragmentStage + }; + void prepareShader(Stage stage); + using FuncAndLib = QPair<id<MTLFunction>, id<MTLLibrary> >; + FuncAndLib compileShaderFromSource(const QByteArray &src, const QByteArray &entryPoint); + void init(int framesInFlight); + + QSize m_viewportSize; + qreal m_t; + QQuickWindow *m_window; + + QByteArray m_vert; + QByteArray m_vertEntryPoint; + QByteArray m_frag; + QByteArray m_fragEntryPoint; + + bool m_initialized = false; + id<MTLDevice> m_device; + id<MTLBuffer> m_vbuf; + id<MTLBuffer> m_ubuf[3]; + FuncAndLib m_vs; + FuncAndLib m_fs; + id<MTLRenderPipelineState> m_pipeline; +}; + +MetalSquircle::MetalSquircle() + : m_t(0) + , m_renderer(nullptr) +{ + connect(this, &QQuickItem::windowChanged, this, &MetalSquircle::handleWindowChanged); +} + +void MetalSquircle::setT(qreal t) +{ + if (t == m_t) + return; + m_t = t; + emit tChanged(); + if (window()) + window()->update(); +} + +void MetalSquircle::handleWindowChanged(QQuickWindow *win) +{ + if (win) { + connect(win, &QQuickWindow::beforeSynchronizing, this, &MetalSquircle::sync, Qt::DirectConnection); + connect(win, &QQuickWindow::sceneGraphInvalidated, this, &MetalSquircle::cleanup, Qt::DirectConnection); + + // Ensure we start with cleared to black. The squircle's blend mode relies on this. + win->setColor(Qt::black); + } +} + +SquircleRenderer::SquircleRenderer() + : m_t(0) +{ + m_vbuf = nil; + + for (int i = 0; i < 3; ++i) + m_ubuf[i] = nil; + + m_vs.first = nil; + m_vs.second = nil; + + m_fs.first = nil; + m_fs.second = nil; +} + +// The safe way to release custom graphics resources is to both connect to +// sceneGraphInvalidated() and implement releaseResources(). To support +// threaded render loops the latter performs the SquircleRenderer destruction +// via scheduleRenderJob(). Note that the MetalSquircle may be gone by the time +// the QRunnable is invoked. + +void MetalSquircle::cleanup() +{ + delete m_renderer; + m_renderer = nullptr; +} + +class CleanupJob : public QRunnable +{ +public: + CleanupJob(SquircleRenderer *renderer) : m_renderer(renderer) { } + void run() override { delete m_renderer; } +private: + SquircleRenderer *m_renderer; +}; + +void MetalSquircle::releaseResources() +{ + window()->scheduleRenderJob(new CleanupJob(m_renderer), QQuickWindow::BeforeSynchronizingStage); + m_renderer = nullptr; +} + +SquircleRenderer::~SquircleRenderer() +{ + qDebug("cleanup"); + + [m_vbuf release]; + for (int i = 0; i < 3; ++i) + [m_ubuf[i] release]; + + [m_vs.first release]; + [m_vs.second release]; + + [m_fs.first release]; + [m_fs.second release]; +} + +void MetalSquircle::sync() +{ + if (!m_renderer) { + m_renderer = new SquircleRenderer; + connect(window(), &QQuickWindow::beforeRendering, m_renderer, &SquircleRenderer::frameStart, Qt::DirectConnection); + connect(window(), &QQuickWindow::beforeRenderPassRecording, m_renderer, &SquircleRenderer::mainPassRecordingStart, Qt::DirectConnection); + } + m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio()); + m_renderer->setT(m_t); + m_renderer->setWindow(window()); +} + +void SquircleRenderer::frameStart() +{ + QSGRendererInterface *rif = m_window->rendererInterface(); + + // We are not prepared for anything other than running with the RHI and its Metal backend. + Q_ASSERT(rif->graphicsApi() == QSGRendererInterface::MetalRhi); + + m_device = (id<MTLDevice>) rif->getResource(m_window, QSGRendererInterface::DeviceResource); + Q_ASSERT(m_device); + + if (m_vert.isEmpty()) + prepareShader(VertexStage); + if (m_frag.isEmpty()) + prepareShader(FragmentStage); + + if (!m_initialized) + init(m_window->graphicsStateInfo()->framesInFlight); +} + +static const float vertices[] = { + -1, -1, + 1, -1, + -1, 1, + 1, 1 +}; + +const int UBUF_SIZE = 4; + +void SquircleRenderer::mainPassRecordingStart() +{ + // This example demonstrates the simple case: prepending some commands to + // the scenegraph's main renderpass. It does not create its own passes, + // rendertargets, etc. so no synchronization is needed. + + const QQuickWindow::GraphicsStateInfo *stateInfo = m_window->graphicsStateInfo(); + + QSGRendererInterface *rif = m_window->rendererInterface(); + id<MTLRenderCommandEncoder> encoder = (id<MTLRenderCommandEncoder>) rif->getResource( + m_window, QSGRendererInterface::CommandEncoderResource); + Q_ASSERT(encoder); + + m_window->beginExternalCommands(); + + void *p = [m_ubuf[stateInfo->currentFrameSlot] contents]; + float t = m_t; + memcpy(p, &t, 4); + + MTLViewport vp; + vp.originX = 0; + vp.originY = 0; + vp.width = m_viewportSize.width(); + vp.height = m_viewportSize.height(); + vp.znear = 0; + vp.zfar = 1; + [encoder setViewport: vp]; + + [encoder setFragmentBuffer: m_ubuf[stateInfo->currentFrameSlot] offset: 0 atIndex: 0]; + [encoder setVertexBuffer: m_vbuf offset: 0 atIndex: 1]; + [encoder setRenderPipelineState: m_pipeline]; + [encoder drawPrimitives: MTLPrimitiveTypeTriangleStrip vertexStart: 0 vertexCount: 4 instanceCount: 1 baseInstance: 0]; + + m_window->endExternalCommands(); +} + +void SquircleRenderer::prepareShader(Stage stage) +{ + QString filename; + if (stage == VertexStage) { + filename = QLatin1String(":/scenegraph/metalunderqml/squircle.vert"); + } else { + Q_ASSERT(stage == FragmentStage); + filename = QLatin1String(":/scenegraph/metalunderqml/squircle.frag"); + } + QFile f(filename); + if (!f.open(QIODevice::ReadOnly)) + qFatal("Failed to read shader %s", qPrintable(filename)); + + const QByteArray contents = f.readAll(); + + if (stage == VertexStage) { + m_vert = contents; + Q_ASSERT(!m_vert.isEmpty()); + m_vertEntryPoint = QByteArrayLiteral("main0"); + } else { + m_frag = contents; + Q_ASSERT(!m_frag.isEmpty()); + m_fragEntryPoint = QByteArrayLiteral("main0"); + } +} + +SquircleRenderer::FuncAndLib SquircleRenderer::compileShaderFromSource(const QByteArray &src, const QByteArray &entryPoint) +{ + FuncAndLib fl; + + NSString *srcstr = [NSString stringWithUTF8String: src.constData()]; + MTLCompileOptions *opts = [[MTLCompileOptions alloc] init]; + opts.languageVersion = MTLLanguageVersion1_2; + NSError *err = nil; + fl.second = [m_device newLibraryWithSource: srcstr options: opts error: &err]; + [opts release]; + // srcstr is autoreleased + + if (err) { + const QString msg = QString::fromNSString(err.localizedDescription); + qFatal("%s", qPrintable(msg)); + return fl; + } + + NSString *name = [NSString stringWithUTF8String: entryPoint.constData()]; + fl.first = [fl.second newFunctionWithName: name]; + [name release]; + + return fl; +} + +void SquircleRenderer::init(int framesInFlight) +{ + qDebug("init"); + + Q_ASSERT(framesInFlight <= 3); + m_initialized = true; + + m_vbuf = [m_device newBufferWithLength: sizeof(vertices) options: MTLResourceStorageModeShared]; + void *p = [m_vbuf contents]; + memcpy(p, vertices, sizeof(vertices)); + + for (int i = 0; i < framesInFlight; ++i) + m_ubuf[i] = [m_device newBufferWithLength: UBUF_SIZE options: MTLResourceStorageModeShared]; + + MTLVertexDescriptor *inputLayout = [MTLVertexDescriptor vertexDescriptor]; + inputLayout.attributes[0].format = MTLVertexFormatFloat2; + inputLayout.attributes[0].offset = 0; + inputLayout.attributes[0].bufferIndex = 1; // ubuf is 0, vbuf is 1 + inputLayout.layouts[1].stride = 2 * sizeof(float); + + MTLRenderPipelineDescriptor *rpDesc = [[MTLRenderPipelineDescriptor alloc] init]; + rpDesc.vertexDescriptor = inputLayout; + + m_vs = compileShaderFromSource(m_vert, m_vertEntryPoint); + rpDesc.vertexFunction = m_vs.first; + m_fs = compileShaderFromSource(m_frag, m_fragEntryPoint); + rpDesc.fragmentFunction = m_fs.first; + + rpDesc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm; + rpDesc.colorAttachments[0].blendingEnabled = true; + rpDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; + rpDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorSourceAlpha; + rpDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOne; + rpDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOne; + + if (m_device.depth24Stencil8PixelFormatSupported) { + rpDesc.depthAttachmentPixelFormat = MTLPixelFormatDepth24Unorm_Stencil8; + rpDesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth24Unorm_Stencil8; + } else { + rpDesc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8; + rpDesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8; + } + + NSError *err = nil; + m_pipeline = [m_device newRenderPipelineStateWithDescriptor: rpDesc error: &err]; + if (!m_pipeline) { + const QString msg = QString::fromNSString(err.localizedDescription); + qFatal("Failed to create render pipeline state: %s", qPrintable(msg)); + } + [rpDesc release]; +} + +#include "metalsquircle.moc" diff --git a/examples/quick/scenegraph/metalunderqml/metalunderqml.pro b/examples/quick/scenegraph/metalunderqml/metalunderqml.pro new file mode 100644 index 0000000000..9b27638a6d --- /dev/null +++ b/examples/quick/scenegraph/metalunderqml/metalunderqml.pro @@ -0,0 +1,10 @@ +QT += qml quick + +HEADERS += metalsquircle.h +SOURCES += metalsquircle.mm main.cpp +RESOURCES += metalunderqml.qrc + +LIBS += -framework Metal -framework AppKit + +target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/metalunderqml +INSTALLS += target diff --git a/examples/quick/scenegraph/metalunderqml/metalunderqml.qrc b/examples/quick/scenegraph/metalunderqml/metalunderqml.qrc new file mode 100644 index 0000000000..7172f1fcb7 --- /dev/null +++ b/examples/quick/scenegraph/metalunderqml/metalunderqml.qrc @@ -0,0 +1,7 @@ +<RCC> + <qresource prefix="/scenegraph/metalunderqml"> + <file>main.qml</file> + <file>squircle.vert</file> + <file>squircle.frag</file> + </qresource> +</RCC> diff --git a/examples/quick/scenegraph/metalunderqml/squircle.frag b/examples/quick/scenegraph/metalunderqml/squircle.frag new file mode 100644 index 0000000000..15f34624fe --- /dev/null +++ b/examples/quick/scenegraph/metalunderqml/squircle.frag @@ -0,0 +1,29 @@ +#include <metal_stdlib> +#include <simd/simd.h> + +using namespace metal; + +struct buf +{ + float t; +}; + +struct main0_out +{ + float4 fragColor [[color(0)]]; +}; + +struct main0_in +{ + float2 coords [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant buf& ubuf [[buffer(0)]]) +{ + main0_out out = {}; + float i = 1.0 - (pow(abs(in.coords.x), 4.0) + pow(abs(in.coords.y), 4.0)); + i = smoothstep(ubuf.t - 0.800000011920928955078125, ubuf.t + 0.800000011920928955078125, i); + i = floor(i * 20.0) / 20.0; + out.fragColor = float4((in.coords * 0.5) + float2(0.5), i, i); + return out; +} diff --git a/examples/quick/scenegraph/metalunderqml/squircle.vert b/examples/quick/scenegraph/metalunderqml/squircle.vert new file mode 100644 index 0000000000..a88c59f541 --- /dev/null +++ b/examples/quick/scenegraph/metalunderqml/squircle.vert @@ -0,0 +1,23 @@ +#include <metal_stdlib> +#include <simd/simd.h> + +using namespace metal; + +struct main0_out +{ + float2 coords [[user(locn0)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 vertices [[attribute(0)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + out.gl_Position = in.vertices; + out.coords = in.vertices.xy; + return out; +} diff --git a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc index 3d4f4443e9..69a9d2ce4b 100644 --- a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc +++ b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc @@ -94,17 +94,18 @@ \snippet scenegraph/openglunderqml/squircle.cpp 3 - The default behavior of the scene graph is to clear the - framebuffer before rendering. Since we render before the scene - graph, we need to turn this clearing off. This means that we need - to clear ourselves in the \c paint() function. + The default behavior of the scene graph is to clear the framebuffer before + rendering. This is fine since we will insert our own rendering code after + this clear is enqueued. Make sure however that we clear to the desired + color (black). \snippet scenegraph/openglunderqml/squircle.cpp 9 - We use the \c sync() function to initialize the renderer and to - copy the state in our item into the renderer. When the renderer is - created, we also connect the \l QQuickWindow::beforeRendering() to - the renderer's \c paint() slot. + We use the \c sync() function to initialize the renderer and to copy the + state in our item into the renderer. When the renderer is created, we also + connect the \l QQuickWindow::beforeRendering() and \l + QQuickWindow::beforeRenderPassRecording() to the renderer's \c init() and + \c paint() slots. \note The \l QQuickWindow::beforeSynchronizing() signal is emitted on the rendering thread while the GUI thread is blocked, so it is @@ -112,8 +113,11 @@ \snippet scenegraph/openglunderqml/squircle.cpp 6 - In the \c cleanup() function we delete the renderer which in turn - cleans up its own resources. + In the \c cleanup() function we delete the renderer which in turn cleans up + its own resources. This is complemented by reimplementing \l + QQuickWindow::releaseResources() since just connecting to the + sceneGraphInvalidated() signal is not sufficient on its own to handle all + cases. \snippet scenegraph/openglunderqml/squircle.cpp 8 @@ -124,22 +128,13 @@ \snippet scenegraph/openglunderqml/squircle.cpp 4 - In the SquircleRenderer's \c paint() function we start by - initializing the shader program. By initializing the shader - program here, we make sure that the OpenGL context is bound and - that we are on the correct thread. + In the SquircleRenderer's \c init() function we start by initializing the + shader program if not yet done. The OpenGL context is current on the thread + when the slot is invoked. \snippet scenegraph/openglunderqml/squircle.cpp 5 - We use the shader program to draw the squircle. At the end of the - \c paint function we release the program and disable the - attributes we used so that the OpenGL context is in a "clean" - state for the scene graph to pick it up. - - \note If tracking the changes in the OpenGL context's state is not - feasible, one can use the function \l - QQuickWindow::resetOpenGLState() which will reset all state that - the scene graph relies on. + We use the shader program to draw the squircle in \c paint(). \snippet scenegraph/openglunderqml/main.cpp 1 diff --git a/examples/quick/scenegraph/openglunderqml/squircle.cpp b/examples/quick/scenegraph/openglunderqml/squircle.cpp index d6f6b327f2..828857fe24 100644 --- a/examples/quick/scenegraph/openglunderqml/squircle.cpp +++ b/examples/quick/scenegraph/openglunderqml/squircle.cpp @@ -53,6 +53,7 @@ #include <QtQuick/qquickwindow.h> #include <QtGui/QOpenGLShaderProgram> #include <QtGui/QOpenGLContext> +#include <QtCore/QRunnable> //! [7] Squircle::Squircle() @@ -82,10 +83,9 @@ void Squircle::handleWindowChanged(QQuickWindow *win) connect(win, &QQuickWindow::beforeSynchronizing, this, &Squircle::sync, Qt::DirectConnection); connect(win, &QQuickWindow::sceneGraphInvalidated, this, &Squircle::cleanup, Qt::DirectConnection); //! [1] - // If we allow QML to do the clearing, they would clear what we paint - // and nothing would show. //! [3] - win->setClearBeforeRendering(false); + // Ensure we start with cleared to black. The squircle's blend mode relies on this. + win->setColor(Qt::black); } } //! [3] @@ -93,10 +93,23 @@ void Squircle::handleWindowChanged(QQuickWindow *win) //! [6] void Squircle::cleanup() { - if (m_renderer) { - delete m_renderer; - m_renderer = nullptr; - } + delete m_renderer; + m_renderer = nullptr; +} + +class CleanupJob : public QRunnable +{ +public: + CleanupJob(SquircleRenderer *renderer) : m_renderer(renderer) { } + void run() override { delete m_renderer; } +private: + SquircleRenderer *m_renderer; +}; + +void Squircle::releaseResources() +{ + window()->scheduleRenderJob(new CleanupJob(m_renderer), QQuickWindow::BeforeSynchronizingStage); + m_renderer = nullptr; } SquircleRenderer::~SquircleRenderer() @@ -110,7 +123,8 @@ void Squircle::sync() { if (!m_renderer) { m_renderer = new SquircleRenderer(); - connect(window(), &QQuickWindow::beforeRendering, m_renderer, &SquircleRenderer::paint, Qt::DirectConnection); + connect(window(), &QQuickWindow::beforeRendering, m_renderer, &SquircleRenderer::init, Qt::DirectConnection); + connect(window(), &QQuickWindow::beforeRenderPassRecording, m_renderer, &SquircleRenderer::paint, Qt::DirectConnection); } m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio()); m_renderer->setT(m_t); @@ -119,9 +133,12 @@ void Squircle::sync() //! [9] //! [4] -void SquircleRenderer::paint() +void SquircleRenderer::init() { if (!m_program) { + QSGRendererInterface *rif = m_window->rendererInterface(); + Q_ASSERT(rif->graphicsApi() == QSGRendererInterface::OpenGL || rif->graphicsApi() == QSGRendererInterface::OpenGLRhi); + initializeOpenGLFunctions(); m_program = new QOpenGLShaderProgram(); @@ -146,7 +163,15 @@ void SquircleRenderer::paint() m_program->link(); } +} + //! [4] //! [5] +void SquircleRenderer::paint() +{ + // Play nice with the RHI. Not strictly needed when the scenegraph uses + // OpenGL directly. + m_window->beginExternalCommands(); + m_program->bind(); m_program->enableAttributeArray(0); @@ -157,6 +182,11 @@ void SquircleRenderer::paint() -1, 1, 1, 1 }; + + // This example relies on (deprecated) client-side pointers for the vertex + // input. Therefore, we have to make sure no vertex buffer is bound. + glBindBuffer(GL_ARRAY_BUFFER, 0); + m_program->setAttributeArray(0, GL_FLOAT, values, 2); m_program->setUniformValue("t", (float) m_t); @@ -164,9 +194,6 @@ void SquircleRenderer::paint() glDisable(GL_DEPTH_TEST); - glClearColor(0, 0, 0, 1); - glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); @@ -178,5 +205,7 @@ void SquircleRenderer::paint() // Not strictly needed for this example, but generally useful for when // mixing with raw OpenGL. m_window->resetOpenGLState(); + + m_window->endExternalCommands(); } //! [5] diff --git a/examples/quick/scenegraph/openglunderqml/squircle.h b/examples/quick/scenegraph/openglunderqml/squircle.h index 652e679f81..1b9995bc1e 100644 --- a/examples/quick/scenegraph/openglunderqml/squircle.h +++ b/examples/quick/scenegraph/openglunderqml/squircle.h @@ -70,6 +70,7 @@ public: void setWindow(QQuickWindow *window) { m_window = window; } public slots: + void init(); void paint(); private: @@ -103,6 +104,8 @@ private slots: void handleWindowChanged(QQuickWindow *win); private: + void releaseResources() override; + qreal m_t; SquircleRenderer *m_renderer; }; diff --git a/examples/quick/scenegraph/scenegraph.pro b/examples/quick/scenegraph/scenegraph.pro index 2efeb5ed83..ac368c79a5 100644 --- a/examples/quick/scenegraph/scenegraph.pro +++ b/examples/quick/scenegraph/scenegraph.pro @@ -16,5 +16,13 @@ SUBDIRS += \ rendernode \ threadedanimation +macos { + SUBDIRS += metalunderqml +} + +win32 { + SUBDIRS += d3d11underqml +} + EXAMPLE_FILES += \ shared diff --git a/examples/quick/scenegraph/shared/squircle_rhi.frag b/examples/quick/scenegraph/shared/squircle_rhi.frag new file mode 100644 index 0000000000..8da62b93e6 --- /dev/null +++ b/examples/quick/scenegraph/shared/squircle_rhi.frag @@ -0,0 +1,16 @@ +#version 440 + +layout(location = 0) in vec2 coords; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + float t; +} ubuf; + +void main() +{ + float i = 1. - (pow(abs(coords.x), 4.) + pow(abs(coords.y), 4.)); + i = smoothstep(ubuf.t - 0.8, ubuf.t + 0.8, i); + i = floor(i * 20.) / 20.; + fragColor = vec4(coords * .5 + .5, i, i); +} diff --git a/examples/quick/scenegraph/shared/squircle_rhi.vert b/examples/quick/scenegraph/shared/squircle_rhi.vert new file mode 100644 index 0000000000..b57dfdfe10 --- /dev/null +++ b/examples/quick/scenegraph/shared/squircle_rhi.vert @@ -0,0 +1,13 @@ +#version 440 + +layout(location = 0) in vec4 vertices; + +layout(location = 0) out vec2 coords; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + gl_Position = vertices; + coords = vertices.xy; +} diff --git a/examples/quick/shadereffects/content/shaders/+qsb/blur.frag b/examples/quick/shadereffects/content/shaders/+qsb/blur.frag Binary files differnew file mode 100644 index 0000000000..1c79359297 --- /dev/null +++ b/examples/quick/shadereffects/content/shaders/+qsb/blur.frag diff --git a/examples/quick/shadereffects/content/shaders/+qsb/colorize.frag b/examples/quick/shadereffects/content/shaders/+qsb/colorize.frag Binary files differnew file mode 100644 index 0000000000..45c5301f31 --- /dev/null +++ b/examples/quick/shadereffects/content/shaders/+qsb/colorize.frag diff --git a/examples/quick/shadereffects/content/shaders/+qsb/genie.vert b/examples/quick/shadereffects/content/shaders/+qsb/genie.vert Binary files differnew file mode 100644 index 0000000000..dd94129cf7 --- /dev/null +++ b/examples/quick/shadereffects/content/shaders/+qsb/genie.vert diff --git a/examples/quick/shadereffects/content/shaders/+qsb/outline.frag b/examples/quick/shadereffects/content/shaders/+qsb/outline.frag Binary files differnew file mode 100644 index 0000000000..470e2bd6e6 --- /dev/null +++ b/examples/quick/shadereffects/content/shaders/+qsb/outline.frag diff --git a/examples/quick/shadereffects/content/shaders/+qsb/shadow.frag b/examples/quick/shadereffects/content/shaders/+qsb/shadow.frag Binary files differnew file mode 100644 index 0000000000..128af21daa --- /dev/null +++ b/examples/quick/shadereffects/content/shaders/+qsb/shadow.frag diff --git a/examples/quick/shadereffects/content/shaders/+qsb/wobble.frag b/examples/quick/shadereffects/content/shaders/+qsb/wobble.frag Binary files differnew file mode 100644 index 0000000000..9b27ae87cb --- /dev/null +++ b/examples/quick/shadereffects/content/shaders/+qsb/wobble.frag diff --git a/examples/quick/shadereffects/content/shaders/rhi/blur.frag b/examples/quick/shadereffects/content/shaders/rhi/blur.frag new file mode 100644 index 0000000000..0c914d4244 --- /dev/null +++ b/examples/quick/shadereffects/content/shaders/rhi/blur.frag @@ -0,0 +1,21 @@ +#version 440 + +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D source; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + vec2 delta; +} ubuf; + +void main() +{ + fragColor =(0.0538 * texture(source, qt_TexCoord0 - 3.182 * ubuf.delta) + + 0.3229 * texture(source, qt_TexCoord0 - 1.364 * ubuf.delta) + + 0.2466 * texture(source, qt_TexCoord0) + + 0.3229 * texture(source, qt_TexCoord0 + 1.364 * ubuf.delta) + + 0.0538 * texture(source, qt_TexCoord0 + 3.182 * ubuf.delta)) * ubuf.qt_Opacity; +} diff --git a/examples/quick/shadereffects/content/shaders/rhi/colorize.frag b/examples/quick/shadereffects/content/shaders/rhi/colorize.frag new file mode 100644 index 0000000000..bc8067cc8c --- /dev/null +++ b/examples/quick/shadereffects/content/shaders/rhi/colorize.frag @@ -0,0 +1,20 @@ +#version 440 + +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D source; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + vec4 tint; +} ubuf; + +void main() +{ + vec4 c = texture(source, qt_TexCoord0); + float lo = min(min(c.x, c.y), c.z); + float hi = max(max(c.x, c.y), c.z); + fragColor = ubuf.qt_Opacity * vec4(mix(vec3(lo), vec3(hi), ubuf.tint.xyz), c.w); +} diff --git a/examples/quick/shadereffects/content/shaders/rhi/compile.bat b/examples/quick/shadereffects/content/shaders/rhi/compile.bat new file mode 100755 index 0000000000..93dfb7b2a9 --- /dev/null +++ b/examples/quick/shadereffects/content/shaders/rhi/compile.bat @@ -0,0 +1,56 @@ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: Copyright (C) 2019 The Qt Company Ltd. +:: Contact: https://www.qt.io/licensing/ +:: +:: This file is part of the examples 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$ +:: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o ../+qsb/blur.frag blur.frag +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o ../+qsb/colorize.frag colorize.frag +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o ../+qsb/outline.frag outline.frag +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o ../+qsb/shadow.frag shadow.frag +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o ../+qsb/wobble.frag wobble.frag +qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o ../+qsb/genie.vert genie.vert diff --git a/examples/quick/shadereffects/content/shaders/rhi/genie.vert b/examples/quick/shadereffects/content/shaders/rhi/genie.vert new file mode 100644 index 0000000000..2cb1e71046 --- /dev/null +++ b/examples/quick/shadereffects/content/shaders/rhi/genie.vert @@ -0,0 +1,29 @@ +#version 440 + +layout(location = 0) in vec4 qt_Vertex; +layout(location = 1) in vec2 qt_MultiTexCoord0; + +layout(location = 0) out vec2 qt_TexCoord0; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + float bend; + float minimize; + float side; + float width; + float height; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + qt_TexCoord0 = qt_MultiTexCoord0; + vec4 pos = qt_Vertex; + pos.y = mix(qt_Vertex.y, ubuf.height, ubuf.minimize); + float t = pos.y / ubuf.height; + t = (3. - 2. * t) * t * t; + pos.x = mix(qt_Vertex.x, ubuf.side * ubuf.width, t * ubuf.bend); + gl_Position = ubuf.qt_Matrix * pos; +} diff --git a/examples/quick/shadereffects/content/shaders/rhi/outline.frag b/examples/quick/shadereffects/content/shaders/rhi/outline.frag new file mode 100644 index 0000000000..26df69c5fe --- /dev/null +++ b/examples/quick/shadereffects/content/shaders/rhi/outline.frag @@ -0,0 +1,24 @@ +#version 440 + +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D source; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + vec2 delta; +} ubuf; + +void main() +{ + vec4 tl = texture(source, qt_TexCoord0 - ubuf.delta); + vec4 tr = texture(source, qt_TexCoord0 + vec2(ubuf.delta.x, -ubuf.delta.y)); + vec4 bl = texture(source, qt_TexCoord0 - vec2(ubuf.delta.x, -ubuf.delta.y)); + vec4 br = texture(source, qt_TexCoord0 + ubuf.delta); + vec4 gx = (tl + bl) - (tr + br); + vec4 gy = (tl + tr) - (bl + br); + fragColor.xyz = vec3(0.); + fragColor.w = clamp(dot(sqrt(gx * gx + gy * gy), vec4(1.)), 0., 1.) * ubuf.qt_Opacity; +} diff --git a/examples/quick/shadereffects/content/shaders/rhi/shadow.frag b/examples/quick/shadereffects/content/shaders/rhi/shadow.frag new file mode 100644 index 0000000000..8247517b6d --- /dev/null +++ b/examples/quick/shadereffects/content/shaders/rhi/shadow.frag @@ -0,0 +1,21 @@ +#version 440 + +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D source; +layout(binding = 2) uniform sampler2D shadow; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + float darkness; + vec2 delta; +} ubuf; + +void main() +{ + vec4 fg = texture(source, qt_TexCoord0); + vec4 bg = texture(shadow, qt_TexCoord0 + ubuf.delta); + fragColor = (fg + vec4(0., 0., 0., ubuf.darkness * bg.a) * (1. - fg.a)) * ubuf.qt_Opacity; +} diff --git a/examples/quick/shadereffects/content/shaders/rhi/wobble.frag b/examples/quick/shadereffects/content/shaders/rhi/wobble.frag new file mode 100644 index 0000000000..a34481c2f2 --- /dev/null +++ b/examples/quick/shadereffects/content/shaders/rhi/wobble.frag @@ -0,0 +1,20 @@ +#version 440 + +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D source; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + float amplitude; + float frequency; + float time; +} ubuf; + +void main() +{ + vec2 p = sin(ubuf.time + ubuf.frequency * qt_TexCoord0); + fragColor = texture(source, qt_TexCoord0 + ubuf.amplitude * vec2(p.y, -p.x)) * ubuf.qt_Opacity; +} diff --git a/examples/quick/shadereffects/doc/src/shadereffects.qdoc b/examples/quick/shadereffects/doc/src/shadereffects.qdoc index 8cb4024da2..d35989c262 100644 --- a/examples/quick/shadereffects/doc/src/shadereffects.qdoc +++ b/examples/quick/shadereffects/doc/src/shadereffects.qdoc @@ -52,10 +52,18 @@ \snippet shadereffects/shadereffects.qml fragment In order to support multiple graphics APIs, not just OpenGL, the shader - source is not embedded into QML. Instead, file selectors are used to select - the correct variant at runtime. Based on the Qt Quick backend in use, Qt - will automatically select either \c{shaders/wobble.frag} with the GLSL - source code or \c{shaders/+hlsl/wobble.frag} with the HLSL source code. + source is not embedded into QML. When running with the graphics API + independent scene graph, the actual file in use is a pre-generated shader + pack containing multiple variants of the shader code. The appropriate + shader is then chosen by Qt Quick, regardless of running on Vulkan, Metal, + Direct 3D, or OpenGL. Qt automatically selects the file under the \c qsb + selector, for example \c{shaders/+qsb/wobble.frag}, when present. + + On the traditional code path, which can mean using OpenGL or Direct3D 12, + file selectors are used to select the correct variant at runtime. Based on + the Qt Quick backend in use, Qt will automatically select either + \c{shaders/wobble.frag} with the GLSL source code or + \c{shaders/+hlsl/wobble.frag} with the HLSL source code. \note For simplicity shader source code is used in all variants of the files. However, with the Direct3D backend of Qt Quick pre-compiled shaders diff --git a/examples/quick/shadereffects/shadereffects.qrc b/examples/quick/shadereffects/shadereffects.qrc index e66b98a6df..762ad0d037 100644 --- a/examples/quick/shadereffects/shadereffects.qrc +++ b/examples/quick/shadereffects/shadereffects.qrc @@ -6,15 +6,21 @@ <file>content/Slider.qml</file> <file>content/shaders/wobble.frag</file> <file>content/shaders/+hlsl/wobble.frag</file> + <file>content/shaders/+qsb/wobble.frag</file> <file>content/shaders/blur.frag</file> <file>content/shaders/+hlsl/blur.frag</file> + <file>content/shaders/+qsb/blur.frag</file> <file>content/shaders/shadow.frag</file> <file>content/shaders/+hlsl/shadow.frag</file> + <file>content/shaders/+qsb/shadow.frag</file> <file>content/shaders/outline.frag</file> <file>content/shaders/+hlsl/outline.frag</file> + <file>content/shaders/+qsb/outline.frag</file> <file>content/shaders/colorize.frag</file> <file>content/shaders/+hlsl/colorize.frag</file> + <file>content/shaders/+qsb/colorize.frag</file> <file>content/shaders/genie.vert</file> <file>content/shaders/+hlsl/genie.vert</file> + <file>content/shaders/+qsb/genie.vert</file> </qresource> </RCC> diff --git a/src/3rdparty/masm/assembler/ARMv7Assembler.h b/src/3rdparty/masm/assembler/ARMv7Assembler.h index f2e8dc1a1b..03cb9f42f8 100644 --- a/src/3rdparty/masm/assembler/ARMv7Assembler.h +++ b/src/3rdparty/masm/assembler/ARMv7Assembler.h @@ -40,6 +40,10 @@ #include <libkern/OSCacheControl.h> #endif +#if OS(RTEMS) +#include <rtems/rtems/cache.h> +#endif + namespace JSC { namespace ARMRegisters { @@ -2359,6 +2363,8 @@ public: #elif OS(QNX) #if !ENABLE(ASSEMBLER_WX_EXCLUSIVE) msync(code, size, MS_INVALIDATE_ICACHE); +#elif OS(RTEMS) + rtems_cache_flush_multiple_data_lines(code, size); #else UNUSED_PARAM(code); UNUSED_PARAM(size); diff --git a/src/3rdparty/masm/masm.pri b/src/3rdparty/masm/masm.pri index 4d15abcba0..1df4585aae 100644 --- a/src/3rdparty/masm/masm.pri +++ b/src/3rdparty/masm/masm.pri @@ -126,8 +126,3 @@ QMAKE_EXTRA_COMPILERS += retgen } } } - -linux { - requires(qtConfig(dlopen)) - QMAKE_USE_PRIVATE += libdl -} diff --git a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp index 3b2a73a39a..d59fdcd675 100644 --- a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp +++ b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp @@ -74,21 +74,9 @@ static int memfdForUsage(size_t bytes, OSAllocator::Usage usage) break; } - // try to get our own library name by giving dladdr a pointer pointing to - // something we know to be in it (using a pointer to string data) - static const char *libname = [=]() { - Dl_info info; - if (dladdr(type, &info) == 0) - info.dli_fname = nullptr; - return info.dli_fname; - }(); - char buf[PATH_MAX]; strcpy(buf, type); - if (libname) - strcat(buf, libname); - else - strcat(buf, "QtQml"); + strcat(buf, "QtQml"); int fd = syscall(SYS_memfd_create, buf, MFD_CLOEXEC); if (fd != -1) { diff --git a/src/3rdparty/masm/wtf/Platform.h b/src/3rdparty/masm/wtf/Platform.h index bd66af7fe6..ab1da2198a 100644 --- a/src/3rdparty/masm/wtf/Platform.h +++ b/src/3rdparty/masm/wtf/Platform.h @@ -438,6 +438,10 @@ #define WTF_OS_WINDOWS 1 #endif +#ifdef __rtems__ +#define WTF_OS_RTEMS 1 +#endif + #define WTF_OS_WIN ERROR "USE WINDOWS WITH OS NOT WIN" #define WTF_OS_MAC ERROR "USE MAC_OS_X WITH OS NOT MAC" @@ -451,6 +455,7 @@ || OS(NETBSD) \ || OS(OPENBSD) \ || OS(QNX) \ + || OS(RTEMS) \ || OS(SOLARIS) \ || defined(unix) \ || defined(__unix) \ diff --git a/src/imports/folderlistmodel/fileinfothread.cpp b/src/imports/folderlistmodel/fileinfothread.cpp index a006f659c9..a93edd3b1b 100644 --- a/src/imports/folderlistmodel/fileinfothread.cpp +++ b/src/imports/folderlistmodel/fileinfothread.cpp @@ -39,6 +39,8 @@ #include "fileinfothread_p.h" #include <qdiriterator.h> +#include <qpointer.h> +#include <qtimer.h> #include <QDebug> @@ -46,6 +48,7 @@ FileInfoThread::FileInfoThread(QObject *parent) : QThread(parent), abort(false), + scanPending(false), #if QT_CONFIG(filesystemwatcher) watcher(nullptr), #endif @@ -109,7 +112,7 @@ void FileInfoThread::setPath(const QString &path) #endif currentPath = path; needUpdate = true; - condition.wakeAll(); + initiateScan(); } void FileInfoThread::setRootPath(const QString &path) @@ -126,7 +129,7 @@ void FileInfoThread::dirChanged(const QString &directoryPath) Q_UNUSED(directoryPath); QMutexLocker locker(&mutex); folderUpdate = true; - condition.wakeAll(); + initiateScan(); } #endif @@ -136,7 +139,7 @@ void FileInfoThread::setSortFlags(QDir::SortFlags flags) sortFlags = flags; sortUpdate = true; needUpdate = true; - condition.wakeAll(); + initiateScan(); } void FileInfoThread::setNameFilters(const QStringList & filters) @@ -144,7 +147,7 @@ void FileInfoThread::setNameFilters(const QStringList & filters) QMutexLocker locker(&mutex); nameFilters = filters; folderUpdate = true; - condition.wakeAll(); + initiateScan(); } void FileInfoThread::setShowFiles(bool show) @@ -152,7 +155,7 @@ void FileInfoThread::setShowFiles(bool show) QMutexLocker locker(&mutex); showFiles = show; folderUpdate = true; - condition.wakeAll(); + initiateScan(); } void FileInfoThread::setShowDirs(bool showFolders) @@ -160,7 +163,7 @@ void FileInfoThread::setShowDirs(bool showFolders) QMutexLocker locker(&mutex); showDirs = showFolders; folderUpdate = true; - condition.wakeAll(); + initiateScan(); } void FileInfoThread::setShowDirsFirst(bool show) @@ -168,7 +171,7 @@ void FileInfoThread::setShowDirsFirst(bool show) QMutexLocker locker(&mutex); showDirsFirst = show; folderUpdate = true; - condition.wakeAll(); + initiateScan(); } void FileInfoThread::setShowDotAndDotDot(bool on) @@ -177,7 +180,7 @@ void FileInfoThread::setShowDotAndDotDot(bool on) showDotAndDotDot = on; folderUpdate = true; needUpdate = true; - condition.wakeAll(); + initiateScan(); } void FileInfoThread::setShowHidden(bool on) @@ -186,7 +189,7 @@ void FileInfoThread::setShowHidden(bool on) showHidden = on; folderUpdate = true; needUpdate = true; - condition.wakeAll(); + initiateScan(); } void FileInfoThread::setShowOnlyReadable(bool on) @@ -194,7 +197,7 @@ void FileInfoThread::setShowOnlyReadable(bool on) QMutexLocker locker(&mutex); showOnlyReadable = on; folderUpdate = true; - condition.wakeAll(); + initiateScan(); } void FileInfoThread::setCaseSensitive(bool on) @@ -202,7 +205,7 @@ void FileInfoThread::setCaseSensitive(bool on) QMutexLocker locker(&mutex); caseSensitive = on; folderUpdate = true; - condition.wakeAll(); + initiateScan(); } #if QT_CONFIG(filesystemwatcher) @@ -211,7 +214,7 @@ void FileInfoThread::updateFile(const QString &path) Q_UNUSED(path); QMutexLocker locker(&mutex); folderUpdate = true; - condition.wakeAll(); + initiateScan(); } #endif @@ -242,6 +245,37 @@ void FileInfoThread::run() } } +void FileInfoThread::runOnce() +{ + if (scanPending) + return; + scanPending = true; + QPointer<FileInfoThread> guardedThis(this); + + auto getFileInfosAsync = [guardedThis](){ + if (!guardedThis) + return; + guardedThis->scanPending = false; + if (guardedThis->currentPath.isEmpty()) { + emit guardedThis->statusChanged(QQuickFolderListModel::Null); + return; + } + emit guardedThis->statusChanged(QQuickFolderListModel::Loading); + guardedThis->getFileInfos(guardedThis->currentPath); + emit guardedThis->statusChanged(QQuickFolderListModel::Ready); + }; + + QTimer::singleShot(0, getFileInfosAsync); +} + +void FileInfoThread::initiateScan() +{ +#if QT_CONFIG(thread) + condition.wakeAll(); +#else + runOnce(); +#endif +} void FileInfoThread::getFileInfos(const QString &path) { diff --git a/src/imports/folderlistmodel/fileinfothread_p.h b/src/imports/folderlistmodel/fileinfothread_p.h index 438dea6faa..923cb29e03 100644 --- a/src/imports/folderlistmodel/fileinfothread_p.h +++ b/src/imports/folderlistmodel/fileinfothread_p.h @@ -99,6 +99,8 @@ public Q_SLOTS: protected: void run() override; + void runOnce(); + void initiateScan(); void getFileInfos(const QString &path); void findChangeRange(const QList<FileProperty> &list, int &fromIndex, int &toIndex); @@ -106,6 +108,7 @@ private: QMutex mutex; QWaitCondition condition; volatile bool abort; + bool scanPending; #if QT_CONFIG(filesystemwatcher) QFileSystemWatcher *watcher; diff --git a/src/imports/imports.pro b/src/imports/imports.pro index 6b31dfc65d..2ed839a6e0 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -5,10 +5,10 @@ SUBDIRS += \ builtins \ qtqml \ models \ - labsmodels + labsmodels \ + folderlistmodel qtConfig(qml-worker-script): SUBDIRS += workerscript -qtConfig(thread): SUBDIRS += folderlistmodel qtHaveModule(sql): SUBDIRS += localstorage qtConfig(settings): SUBDIRS += settings qtConfig(statemachine): SUBDIRS += statemachine diff --git a/src/imports/qtquick2/plugin.cpp b/src/imports/qtquick2/plugin.cpp index efa05c349c..6b44f782bd 100644 --- a/src/imports/qtquick2/plugin.cpp +++ b/src/imports/qtquick2/plugin.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include <QtQml/qqmlextensionplugin.h> +#include <QtQml/QQmlEngine> #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #include <QtQml/private/qqmlengine_p.h> diff --git a/src/imports/shapes/plugin.cpp b/src/imports/shapes/plugin.cpp index e3a9017681..0679a70630 100644 --- a/src/imports/shapes/plugin.cpp +++ b/src/imports/shapes/plugin.cpp @@ -69,6 +69,9 @@ public: // revision in Qt 5.11: added containsMode property qmlRegisterType<QQuickShape, 11>(uri, 1, 11, "Shape"); + + // revision in Qt 5.14: added scale property + qmlRegisterType<QQuickShapePath, 14>(uri, 1, 14, "ShapePath"); // QTBUG-61942 } }; diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index 0b1de08ea3..ae1ef80026 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -52,7 +52,7 @@ #include <QOpenGLFunctions> #include <QSGRendererInterface> #include <QtQuick/private/qsgshadersourcebuilder_p.h> -#include <QtQuick/private/qsgtexture_p.h> +#include <QtQuick/private/qsgplaintexture_p.h> #include <private/qqmlglobal_p.h> #include <QtQml/qqmlinfo.h> #include <cmath> diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp index 4c104f01de..d0f9833c2e 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp @@ -233,11 +233,9 @@ QVariant QQmlEngineDebugServiceImpl::valueContents(QVariant value) const if (value.type() == QVariant::Map) { QVariantMap contents; - QMapIterator<QString, QVariant> i(value.toMap()); - while (i.hasNext()) { - i.next(); + const auto map = value.toMap(); + for (auto i = map.cbegin(), end = map.cend(); i != end; ++i) contents.insert(i.key(), valueContents(i.value())); - } return contents; } diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp index 9b88af995d..f9bd04aa54 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp @@ -61,8 +61,9 @@ QSGInternalRectangleNode *QSGD3D12Context::createInternalRectangleNode() return new QSGD3D12InternalRectangleNode; } -QSGInternalImageNode *QSGD3D12Context::createInternalImageNode() +QSGInternalImageNode *QSGD3D12Context::createInternalImageNode(QSGRenderContext *renderContext) { + Q_UNUSED(renderContext); return new QSGD3D12InternalImageNode; } diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h index 70cc606b52..382183fef6 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h +++ b/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h @@ -62,7 +62,7 @@ public: QSGRenderContext *createRenderContext() override; QSGInternalRectangleNode *createInternalRectangleNode() override; - QSGInternalImageNode *createInternalImageNode() override; + QSGInternalImageNode *createInternalImageNode(QSGRenderContext *renderContext) override; QSGPainterNode *createPainterNode(QQuickPaintedItem *item) override; QSGGlyphNode *createGlyphNode(QSGRenderContext *renderContext, bool preferNativeGlyphNode) override; QSGLayer *createLayer(QSGRenderContext *renderContext) override; diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12layer.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12layer.cpp index faa6f7566a..b9d3a180cf 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12layer.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12layer.cpp @@ -53,7 +53,8 @@ QT_BEGIN_NAMESPACE DECLARE_DEBUG_VAR(render) QSGD3D12Layer::QSGD3D12Layer(QSGD3D12RenderContext *rc) - : m_rc(rc) + : QSGLayer(*(new QSGD3D12LayerPrivate)), + m_rc(rc) { if (Q_UNLIKELY(debug_render())) qDebug("new layer %p", this); @@ -74,6 +75,12 @@ int QSGD3D12Layer::textureId() const return m_rt; // not a texture id per se but will do } +int QSGD3D12LayerPrivate::comparisonKey() const +{ + Q_Q(const QSGD3D12Layer); + return q->m_rt; +} + QSize QSGD3D12Layer::textureSize() const { return m_size; diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12layer_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12layer_p.h index f828843227..42a56877cf 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12layer_p.h +++ b/src/plugins/scenegraph/d3d12/qsgd3d12layer_p.h @@ -52,13 +52,16 @@ // #include <private/qsgadaptationlayer_p.h> +#include <private/qsgtexture_p.h> QT_BEGIN_NAMESPACE class QSGD3D12RenderContext; +class QSGD3D12LayerPrivate; class QSGD3D12Layer : public QSGLayer { + Q_DECLARE_PRIVATE(QSGD3D12Layer) Q_OBJECT public: @@ -114,6 +117,13 @@ private: bool m_updateContentPending = false; }; +class QSGD3D12LayerPrivate : public QSGTexturePrivate +{ + Q_DECLARE_PUBLIC(QSGD3D12Layer) +public: + int comparisonKey() const override; +}; + QT_END_NAMESPACE #endif // QSGD3D12LAYER_P_H diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp index 4ee4656e63..48693207c6 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp @@ -64,7 +64,7 @@ bool QSGD3D12RenderContext::isValid() const return m_engine != nullptr; } -void QSGD3D12RenderContext::initialize(void *) +void QSGD3D12RenderContext::initialize(const InitParams *) { if (m_initialized) return; diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h index 35aca100f4..c555c0808e 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h +++ b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h @@ -63,7 +63,7 @@ class QSGD3D12RenderContext : public QSGRenderContext, public QSGRendererInterfa public: QSGD3D12RenderContext(QSGContext *ctx); bool isValid() const override; - void initialize(void *context) override; + void initialize(const InitParams *params) override; void invalidate() override; void renderNextFrame(QSGRenderer *renderer, uint fbo) override; QSGTexture *createTexture(const QImage &image, uint flags) const override; diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp index b4fb721a8b..1f574a9802 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode.cpp @@ -78,32 +78,6 @@ void QSGD3D12ShaderLinker::reset(const QByteArray &vertBlob, const QByteArray &f textureNameMap.clear(); } -void QSGD3D12ShaderLinker::feedVertexInput(const QSGShaderEffectNode::ShaderData &shader) -{ - bool foundPos = false, foundTexCoord = false; - - for (const auto &ip : qAsConst(shader.shaderInfo.inputParameters)) { - if (ip.semanticName == QByteArrayLiteral("POSITION")) - foundPos = true; - else if (ip.semanticName == QByteArrayLiteral("TEXCOORD")) - foundTexCoord = true; - } - - if (!foundPos) { - qWarning("ShaderEffect: No POSITION input found."); - error = true; - } - if (!foundTexCoord) { - qWarning("ShaderEffect: No TEXCOORD input found."); - error = true; - } - - // Nothing else to do here, the QSGGeometry::AttributeSet decides anyway - // and that is already generated by QQuickShaderEffectMesh via - // QSGGeometry::defaultAttributes_TexturedPoint2D() and has the semantics - // so it will just work. -} - void QSGD3D12ShaderLinker::feedConstants(const QSGShaderEffectNode::ShaderData &shader, const QSet<int> *dirtyIndices) { Q_ASSERT(shader.shaderInfo.variables.count() == shader.varData.count()); @@ -634,19 +608,12 @@ void QSGD3D12ShaderEffectNode::syncMaterial(SyncData *syncData) m_material.linker.reset(vertBlob, fragBlob); if (m_material.hasCustomVertexShader) { - m_material.linker.feedVertexInput(*syncData->vertex.shader); m_material.linker.feedConstants(*syncData->vertex.shader); } else { QSGShaderEffectNode::ShaderData defaultSD; defaultSD.shaderInfo.blob = vertBlob; defaultSD.shaderInfo.type = QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex; - QSGGuiThreadShaderEffectManager::ShaderInfo::InputParameter ip; - ip.semanticName = QByteArrayLiteral("POSITION"); - defaultSD.shaderInfo.inputParameters.append(ip); - ip.semanticName = QByteArrayLiteral("TEXCOORD"); - defaultSD.shaderInfo.inputParameters.append(ip); - // { float4x4 qt_Matrix; float qt_Opacity; } where only the matrix is used QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v; v.name = QByteArrayLiteral("qt_Matrix"); @@ -656,10 +623,7 @@ void QSGD3D12ShaderEffectNode::syncMaterial(SyncData *syncData) QSGShaderEffectNode::VariableData vd; vd.specialType = QSGShaderEffectNode::VariableData::Matrix; defaultSD.varData.append(vd); - defaultSD.shaderInfo.constantDataSize = (16 + 1) * sizeof(float); - - m_material.linker.feedVertexInput(defaultSD); m_material.linker.feedConstants(defaultSD); } @@ -943,20 +907,6 @@ bool QSGD3D12GuiThreadShaderEffectManager::reflect(ShaderInfo *result) qDebug("Shader reflection size %d type %d v%u.%u input elems %d cbuffers %d boundres %d", result->blob.size(), result->type, major, minor, ieCount, cbufferCount, boundResCount); - for (int i = 0; i < ieCount; ++i) { - D3D12_SIGNATURE_PARAMETER_DESC desc; - if (FAILED(reflector->GetInputParameterDesc(i, &desc))) { - qWarning("D3D reflection: Failed to query input parameter %d", i); - return false; - } - if (desc.SystemValueType != D3D_NAME_UNDEFINED) - continue; - ShaderInfo::InputParameter param; - param.semanticName = QByteArray(desc.SemanticName); - param.semanticIndex = desc.SemanticIndex; - result->inputParameters.append(param); - } - for (int i = 0; i < boundResCount; ++i) { D3D12_SHADER_INPUT_BIND_DESC desc; if (FAILED(reflector->GetResourceBindingDesc(i, &desc))) { @@ -1036,10 +986,8 @@ bool QSGD3D12GuiThreadShaderEffectManager::reflect(ShaderInfo *result) } } - if (Q_UNLIKELY(debug_shader())) { - qDebug() << "Input:" << result->inputParameters; + if (Q_UNLIKELY(debug_shader())) qDebug() << "Variables:" << result->variables << "cbuffer size" << result->constantDataSize; - } return true; } diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h index ee17e59130..dec85fd782 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h +++ b/src/plugins/scenegraph/d3d12/qsgd3d12shadereffectnode_p.h @@ -67,7 +67,6 @@ class QSGD3D12ShaderLinker public: void reset(const QByteArray &vertBlob, const QByteArray &fragBlob); - void feedVertexInput(const QSGShaderEffectNode::ShaderData &shader); void feedConstants(const QSGShaderEffectNode::ShaderData &shader, const QSet<int> *dirtyIndices = nullptr); void feedSamplers(const QSGShaderEffectNode::ShaderData &shader); void feedTextures(const QSGShaderEffectNode::ShaderData &shader, const QSet<int> *dirtyIndices = nullptr); diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12texture.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12texture.cpp index a5f3eb7a31..b49b851c23 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12texture.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12texture.cpp @@ -69,6 +69,12 @@ void QSGD3D12Texture::create(const QImage &image, uint flags) m_createPending = true; } +QSGD3D12Texture::QSGD3D12Texture(QSGD3D12Engine *engine) + : QSGTexture(*(new QSGD3D12TexturePrivate)), + m_engine(engine) +{ +} + QSGD3D12Texture::~QSGD3D12Texture() { if (m_id) @@ -80,6 +86,12 @@ int QSGD3D12Texture::textureId() const return m_id; } +int QSGD3D12TexturePrivate::comparisonKey() const +{ + Q_Q(const QSGD3D12Texture); + return q->m_id; +} + QSize QSGD3D12Texture::textureSize() const { return m_image.size(); diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12texture_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12texture_p.h index 3d0e226ddb..f6a5257773 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12texture_p.h +++ b/src/plugins/scenegraph/d3d12/qsgd3d12texture_p.h @@ -51,17 +51,19 @@ // We mean it. // -#include <qsgtexture.h> +#include <private/qsgtexture_p.h> #include <basetsd.h> QT_BEGIN_NAMESPACE class QSGD3D12Engine; +class QSGD3D12TexturePrivate; class QSGD3D12Texture : public QSGTexture { + Q_DECLARE_PRIVATE(QSGD3D12Texture) public: - QSGD3D12Texture(QSGD3D12Engine *engine) : m_engine(engine) { } + QSGD3D12Texture(QSGD3D12Engine *engine); ~QSGD3D12Texture(); void create(const QImage &image, uint flags); @@ -82,6 +84,13 @@ protected: bool m_alphaWanted = false; }; +class QSGD3D12TexturePrivate : public QSGTexturePrivate +{ + Q_DECLARE_PUBLIC(QSGD3D12Texture) +public: + int comparisonKey() const override; +}; + QT_END_NAMESPACE #endif diff --git a/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h b/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h index 107ec0c892..40d67761bf 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h +++ b/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h @@ -42,7 +42,6 @@ #include <QtGui/QGlyphRun> #include <QtCore/QSet> -#include <QtCore/QLinkedList> #include <VG/openvg.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/.prev_CMakeLists.txt b/src/qml/.prev_CMakeLists.txt index 077373f9ac..ca1e879b8f 100644 --- a/src/qml/.prev_CMakeLists.txt +++ b/src/qml/.prev_CMakeLists.txt @@ -65,13 +65,15 @@ add_qt_module(Qml ../3rdparty/masm/yarr/YarrPattern.cpp ../3rdparty/masm/yarr/YarrPattern.h ../3rdparty/masm/yarr/YarrSyntaxChecker.cpp ../3rdparty/masm/yarr/YarrSyntaxChecker.h ../3rdparty/masm/yarr/YarrUnicodeProperties.h + common/qqmlapiversion_p.h + common/qqmljsdiagnosticmessage_p.h compiler/qqmlirbuilder.cpp compiler/qqmlirbuilder_p.h compiler/qv4alloca_p.h compiler/qv4bytecodegenerator.cpp compiler/qv4bytecodegenerator_p.h compiler/qv4bytecodehandler.cpp compiler/qv4bytecodehandler_p.h compiler/qv4calldata_p.h compiler/qv4codegen.cpp compiler/qv4codegen_p.h - compiler/qv4compileddata.cpp compiler/qv4compileddata_p.h + compiler/qv4compileddata_p.h compiler/qv4compiler.cpp compiler/qv4compiler_p.h compiler/qv4compilercontext.cpp compiler/qv4compilercontext_p.h compiler/qv4compilercontrolflow_p.h @@ -84,7 +86,6 @@ add_qt_module(Qml debugger/qqmldebugconnector_p.h debugger/qqmldebugserviceinterfaces_p.h debugger/qqmldebugstatesdelegate_p.h - debugger/qqmlmemoryprofiler_p.h debugger/qqmlprofiler_p.h jsapi/qjsengine.cpp jsapi/qjsengine.h jsapi/qjsengine_p.h jsapi/qjsvalue.cpp jsapi/qjsvalue.h jsapi/qjsvalue_p.h @@ -207,6 +208,7 @@ add_qt_module(Qml qml/qqmlengine.cpp qml/qqmlengine.h qml/qqmlengine_p.h qml/qqmlenumdata_p.h qml/qqmlenumvalue_p.h + qml/qqmlerror.cpp qml/qqmlexpression.cpp qml/qqmlexpression.h qml/qqmlexpression_p.h qml/qqmlextensioninterface.h qml/qqmlextensionplugin.cpp qml/qqmlextensionplugin.h qml/qqmlextensionplugin_p.h @@ -246,6 +248,7 @@ add_qt_module(Qml qml/qqmlpropertyvaluesource.cpp qml/qqmlpropertyvaluesource.h qml/qqmlproxymetaobject.cpp qml/qqmlproxymetaobject_p.h qml/qqmlscriptstring.cpp qml/qqmlscriptstring.h qml/qqmlscriptstring_p.h + qml/qqmlsourcecoordinate_p.h qml/qqmlstaticmetaobject.cpp qml/qqmlstaticmetaobject_p.h qml/qqmlstringconverters.cpp qml/qqmlstringconverters_p.h qml/qqmltype.cpp qml/qqmltype_p.h @@ -267,8 +270,6 @@ add_qt_module(Qml qml/v8/qv4domerrors.cpp qml/v8/qv4domerrors_p.h qml/v8/qv4sqlerrors.cpp qml/v8/qv4sqlerrors_p.h qmldirparser/qqmldirparser.cpp qmldirparser/qqmldirparser_p.h - qmldirparser/qqmlerror.cpp qmldirparser/qqmlerror.h - qmldirparser/qqmlsourcecoordinate_p.h qtqmlglobal.h qtqmlglobal_p.h types/qqmlbind.cpp types/qqmlbind_p.h types/qqmlconnections.cpp types/qqmlconnections_p.h @@ -291,10 +292,10 @@ add_qt_module(Qml WTFReportBacktrace=qmlWTFReportBacktrace WTF_EXPORT_PRIVATE="" INCLUDE_DIRECTORIES - ${CMAKE_CURRENT_BUILD_DIR}/compiler - ${CMAKE_CURRENT_BUILD_DIR}/jsruntime - ${CMAKE_CURRENT_BUILD_DIR}/memory - ${CMAKE_CURRENT_BUILD_DIR}/qmldirparser + ${CMAKE_CURRENT_BINARY_DIR}/compiler + ${CMAKE_CURRENT_BINARY_DIR}/jsruntime + ${CMAKE_CURRENT_BINARY_DIR}/memory + ${CMAKE_CURRENT_BINARY_DIR}/qmldirparser ../3rdparty/llvm/include ../3rdparty/masm ../3rdparty/masm/assembler @@ -398,7 +399,7 @@ extend_target(Qml CONDITION QT_FEATURE_qml_jit jit/qv4baselineassembler.cpp jit/qv4baselineassembler_p.h jit/qv4baselinejit.cpp jit/qv4baselinejit_p.h INCLUDE_DIRECTORIES - ${CMAKE_CURRENT_BUILD_DIR}/jit + ${CMAKE_CURRENT_BINARY_DIR}/jit jit ) @@ -433,7 +434,6 @@ extend_target(Qml CONDITION QT_FEATURE_qml_debug debugger/qqmldebugservice.cpp debugger/qqmldebugservice_p.h debugger/qqmldebugservicefactory_p.h debugger/qqmldebugserviceinterfaces.cpp - debugger/qqmlmemoryprofiler.cpp debugger/qqmlprofiler.cpp debugger/qqmlprofilerdefinitions_p.h jsruntime/qv4profiling.cpp @@ -527,7 +527,7 @@ extend_target(Qml CONDITION (NOT ICC AND NOT CLANG AND GCC) AND ((QT_COMPILER_VE -Wno-expansion-to-defined ) -#### Keys ignored in scope 61:.:../3rdparty/masm:../3rdparty/masm/masm-defs.pri:(QT_COMPILER_VERSION_MAJOR STRGREATER 6): +#### Keys ignored in scope 62:.:../3rdparty/masm:../3rdparty/masm/masm-defs.pri:(QT_COMPILER_VERSION_MAJOR STRGREATER 6): # QMAKE_CXXFLAGS_WARN_ON = "-Wno-expansion-to-defined" extend_target(Qml CONDITION WINRT @@ -556,7 +556,7 @@ extend_target(Qml CONDITION DEFINES___contains___WTF_USE_UDIS86=1 ../3rdparty/masm/disassembler/udis86/udis86_syn-intel.c ) -#### Keys ignored in scope 69:.:../3rdparty/masm:../3rdparty/masm/masm.pri:DEFINES___contains___WTF_USE_UDIS86=1: +#### Keys ignored in scope 70:.:../3rdparty/masm:../3rdparty/masm/masm.pri:DEFINES___contains___WTF_USE_UDIS86=1: # ITAB = "$$PWD/disassembler/udis86/optable.xml" # QMAKE_EXTRA_COMPILERS = "udis86" # QMAKE_EXTRA_TARGETS = "udis86_tab_cfile" @@ -567,10 +567,10 @@ extend_target(Qml CONDITION DEFINES___contains___WTF_USE_UDIS86=1 # udis86_tab_cfile.depends = "udis86_itab.h" # udis86_tab_cfile.target = "$$OUT_PWD/udis86_itab.c" -#### Keys ignored in scope 71:.:../3rdparty/masm:../3rdparty/masm/masm.pri:(CMAKE_BUILD_TYPE STREQUAL Debug): +#### Keys ignored in scope 72:.:../3rdparty/masm:../3rdparty/masm/masm.pri:(CMAKE_BUILD_TYPE STREQUAL Debug): # GENERATEDDIR = "$$GENERATEDDIR/debug" -#### Keys ignored in scope 72:.:../3rdparty/masm:../3rdparty/masm/masm.pri:else: +#### Keys ignored in scope 73:.:../3rdparty/masm:../3rdparty/masm/masm.pri:else: # GENERATEDDIR = "$$GENERATEDDIR/release" extend_target(Qml CONDITION (NOT c++11 AND NOT ICC) AND (CLANG) @@ -584,11 +584,6 @@ extend_target(Qml CONDITION (((NOT c++11 AND NOT ICC) AND (NOT (CLANG))) AND (GC -Wno-c++0x-compat ) -extend_target(Qml CONDITION LINUX - LIBRARIES - ${CMAKE_DL_LIBS} -) - qt_create_tracepoints(Qml qtqml.tracepoints) add_qt_docs( diff --git a/src/qml/CMakeLists.txt b/src/qml/CMakeLists.txt index 6a750161f4..7302099c7c 100644 --- a/src/qml/CMakeLists.txt +++ b/src/qml/CMakeLists.txt @@ -65,13 +65,15 @@ add_qt_module(Qml ../3rdparty/masm/yarr/YarrPattern.cpp ../3rdparty/masm/yarr/YarrPattern.h ../3rdparty/masm/yarr/YarrSyntaxChecker.cpp ../3rdparty/masm/yarr/YarrSyntaxChecker.h ../3rdparty/masm/yarr/YarrUnicodeProperties.h + common/qqmlapiversion_p.h + common/qqmljsdiagnosticmessage_p.h compiler/qqmlirbuilder.cpp compiler/qqmlirbuilder_p.h compiler/qv4alloca_p.h compiler/qv4bytecodegenerator.cpp compiler/qv4bytecodegenerator_p.h compiler/qv4bytecodehandler.cpp compiler/qv4bytecodehandler_p.h compiler/qv4calldata_p.h compiler/qv4codegen.cpp compiler/qv4codegen_p.h - compiler/qv4compileddata.cpp compiler/qv4compileddata_p.h + compiler/qv4compileddata_p.h compiler/qv4compiler.cpp compiler/qv4compiler_p.h compiler/qv4compilercontext.cpp compiler/qv4compilercontext_p.h compiler/qv4compilercontrolflow_p.h @@ -84,7 +86,6 @@ add_qt_module(Qml debugger/qqmldebugconnector_p.h debugger/qqmldebugserviceinterfaces_p.h debugger/qqmldebugstatesdelegate_p.h - debugger/qqmlmemoryprofiler_p.h debugger/qqmlprofiler_p.h jsapi/qjsengine.cpp jsapi/qjsengine.h jsapi/qjsengine_p.h jsapi/qjsvalue.cpp jsapi/qjsvalue.h jsapi/qjsvalue_p.h @@ -207,6 +208,7 @@ add_qt_module(Qml qml/qqmlengine.cpp qml/qqmlengine.h qml/qqmlengine_p.h qml/qqmlenumdata_p.h qml/qqmlenumvalue_p.h + qml/qqmlerror.cpp qml/qqmlexpression.cpp qml/qqmlexpression.h qml/qqmlexpression_p.h qml/qqmlextensioninterface.h qml/qqmlextensionplugin.cpp qml/qqmlextensionplugin.h qml/qqmlextensionplugin_p.h @@ -246,6 +248,7 @@ add_qt_module(Qml qml/qqmlpropertyvaluesource.cpp qml/qqmlpropertyvaluesource.h qml/qqmlproxymetaobject.cpp qml/qqmlproxymetaobject_p.h qml/qqmlscriptstring.cpp qml/qqmlscriptstring.h qml/qqmlscriptstring_p.h + qml/qqmlsourcecoordinate_p.h qml/qqmlstaticmetaobject.cpp qml/qqmlstaticmetaobject_p.h qml/qqmlstringconverters.cpp qml/qqmlstringconverters_p.h qml/qqmltype.cpp qml/qqmltype_p.h @@ -267,8 +270,6 @@ add_qt_module(Qml qml/v8/qv4domerrors.cpp qml/v8/qv4domerrors_p.h qml/v8/qv4sqlerrors.cpp qml/v8/qv4sqlerrors_p.h qmldirparser/qqmldirparser.cpp qmldirparser/qqmldirparser_p.h - qmldirparser/qqmlerror.cpp qmldirparser/qqmlerror.h - qmldirparser/qqmlsourcecoordinate_p.h qtqmlglobal.h qtqmlglobal_p.h types/qqmlbind.cpp types/qqmlbind_p.h types/qqmlconnections.cpp types/qqmlconnections_p.h @@ -291,10 +292,10 @@ add_qt_module(Qml WTFReportBacktrace=qmlWTFReportBacktrace WTF_EXPORT_PRIVATE= # special case INCLUDE_DIRECTORIES - ${CMAKE_CURRENT_BUILD_DIR}/compiler - ${CMAKE_CURRENT_BUILD_DIR}/jsruntime - ${CMAKE_CURRENT_BUILD_DIR}/memory - ${CMAKE_CURRENT_BUILD_DIR}/qmldirparser + ${CMAKE_CURRENT_BINARY_DIR}/compiler + ${CMAKE_CURRENT_BINARY_DIR}/jsruntime + ${CMAKE_CURRENT_BINARY_DIR}/memory + ${CMAKE_CURRENT_BINARY_DIR}/qmldirparser ../3rdparty/llvm/include ../3rdparty/masm ../3rdparty/masm/assembler @@ -405,7 +406,7 @@ extend_target(Qml CONDITION QT_FEATURE_qml_jit jit/qv4baselineassembler.cpp jit/qv4baselineassembler_p.h jit/qv4baselinejit.cpp jit/qv4baselinejit_p.h INCLUDE_DIRECTORIES - ${CMAKE_CURRENT_BUILD_DIR}/jit + ${CMAKE_CURRENT_BINARY_DIR}/jit jit ) @@ -440,7 +441,6 @@ extend_target(Qml CONDITION QT_FEATURE_qml_debug debugger/qqmldebugservice.cpp debugger/qqmldebugservice_p.h debugger/qqmldebugservicefactory_p.h debugger/qqmldebugserviceinterfaces.cpp - debugger/qqmlmemoryprofiler.cpp debugger/qqmlprofiler.cpp debugger/qqmlprofilerdefinitions_p.h jsruntime/qv4profiling.cpp @@ -534,7 +534,7 @@ extend_target(Qml CONDITION (NOT ICC AND NOT CLANG AND GCC) AND ((QT_COMPILER_VE -Wno-expansion-to-defined ) -#### Keys ignored in scope 61:.:../3rdparty/masm:../3rdparty/masm/masm-defs.pri:(QT_COMPILER_VERSION_MAJOR STRGREATER 6): +#### Keys ignored in scope 62:.:../3rdparty/masm:../3rdparty/masm/masm-defs.pri:(QT_COMPILER_VERSION_MAJOR STRGREATER 6): # QMAKE_CXXFLAGS_WARN_ON = "-Wno-expansion-to-defined" extend_target(Qml CONDITION WINRT @@ -563,7 +563,7 @@ extend_target(Qml CONDITION DEFINES___contains___WTF_USE_UDIS86=1 ../3rdparty/masm/disassembler/udis86/udis86_syn-intel.c ) -#### Keys ignored in scope 69:.:../3rdparty/masm:../3rdparty/masm/masm.pri:DEFINES___contains___WTF_USE_UDIS86=1: +#### Keys ignored in scope 70:.:../3rdparty/masm:../3rdparty/masm/masm.pri:DEFINES___contains___WTF_USE_UDIS86=1: # ITAB = "$$PWD/disassembler/udis86/optable.xml" # QMAKE_EXTRA_COMPILERS = "udis86" # QMAKE_EXTRA_TARGETS = "udis86_tab_cfile" @@ -574,10 +574,10 @@ extend_target(Qml CONDITION DEFINES___contains___WTF_USE_UDIS86=1 # udis86_tab_cfile.depends = "udis86_itab.h" # udis86_tab_cfile.target = "$$OUT_PWD/udis86_itab.c" -#### Keys ignored in scope 71:.:../3rdparty/masm:../3rdparty/masm/masm.pri:(CMAKE_BUILD_TYPE STREQUAL Debug): +#### Keys ignored in scope 72:.:../3rdparty/masm:../3rdparty/masm/masm.pri:(CMAKE_BUILD_TYPE STREQUAL Debug): # GENERATEDDIR = "$$GENERATEDDIR/debug" -#### Keys ignored in scope 72:.:../3rdparty/masm:../3rdparty/masm/masm.pri:else: +#### Keys ignored in scope 73:.:../3rdparty/masm:../3rdparty/masm/masm.pri:else: # GENERATEDDIR = "$$GENERATEDDIR/release" extend_target(Qml CONDITION (NOT c++11 AND NOT ICC) AND (CLANG) @@ -591,11 +591,6 @@ extend_target(Qml CONDITION (((NOT c++11 AND NOT ICC) AND (NOT (CLANG))) AND (GC -Wno-c++0x-compat ) -extend_target(Qml CONDITION LINUX - LIBRARIES - ${CMAKE_DL_LIBS} -) - qt_create_tracepoints(Qml qtqml.tracepoints) add_qt_docs( diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp index ece2f0d692..c6ace05b8f 100644 --- a/src/qml/animations/qabstractanimationjob.cpp +++ b/src/qml/animations/qabstractanimationjob.cpp @@ -263,7 +263,6 @@ QAbstractAnimationJob::QAbstractAnimationJob() , m_currentLoopStartTime(0) , m_nextSibling(nullptr) , m_previousSibling(nullptr) - , m_wasDeleted(nullptr) , m_hasRegisteredTimer(false) , m_isPause(false) , m_isGroup(false) @@ -277,9 +276,6 @@ QAbstractAnimationJob::QAbstractAnimationJob() QAbstractAnimationJob::~QAbstractAnimationJob() { - if (m_wasDeleted) - *m_wasDeleted = true; - //we can't call stop here. Otherwise we get pure virtual calls if (m_state != Stopped) { State oldState = m_state; @@ -645,7 +641,7 @@ void QAbstractAnimationJob::removeAnimationChangeListener(QAnimationJobChangeLis void QAbstractAnimationJob::debugAnimation(QDebug d) const { - d << "AbstractAnimationJob(" << hex << (const void *) this << dec << ") state:" + d << "AbstractAnimationJob(" << Qt::hex << (const void *) this << Qt::dec << ") state:" << m_state << "duration:" << duration(); } diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h index 0be6ca96ea..d046ce9def 100644 --- a/src/qml/animations/qabstractanimationjob_p.h +++ b/src/qml/animations/qabstractanimationjob_p.h @@ -52,6 +52,7 @@ // #include <private/qtqmlglobal_p.h> +#include <private/qanimationjobutil_p.h> #include <QtCore/QObject> #include <QtCore/private/qabstractanimation_p.h> #include <vector> @@ -130,6 +131,7 @@ public: bool isRenderThreadJob() const { return m_isRenderThreadJob; } bool isRenderThreadProxy() const { return m_isRenderThreadProxy; } + SelfDeletable m_selfDeletable; protected: virtual void updateCurrentTime(int) {} virtual void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState); @@ -174,7 +176,6 @@ protected: QAbstractAnimationJob *m_previousSibling; QQmlAnimationTimer *m_timer = nullptr; - bool *m_wasDeleted; bool m_hasRegisteredTimer:1; bool m_isPause:1; bool m_isGroup:1; diff --git a/src/qml/animations/qanimationjobutil_p.h b/src/qml/animations/qanimationjobutil_p.h index e3d6fe9178..83cf3b246f 100644 --- a/src/qml/animations/qanimationjobutil_p.h +++ b/src/qml/animations/qanimationjobutil_p.h @@ -51,20 +51,40 @@ // We mean it. // +#include <type_traits> + QT_REQUIRE_CONFIG(qml_animation); -#define RETURN_IF_DELETED(func) \ +// SelfDeletable is used for self-destruction detection along with +// ACTION_IF_DELETED and RETURN_IF_DELETED macros. While using, the objects +// under test should have a member m_selfDeletable of type SelfDeletable +struct SelfDeletable { + ~SelfDeletable() { + if (m_wasDeleted) + *m_wasDeleted = true; + } + bool *m_wasDeleted = nullptr; +}; + +// \param p pointer to object under test, which should have a member m_selfDeletable of type SelfDeletable +// \param func statements or functions that to be executed under test. +// \param action post process if p was deleted under test. +#define ACTION_IF_DELETED(p, func, action) \ { \ - bool *prevWasDeleted = m_wasDeleted; \ + static_assert(std::is_same<decltype((p)->m_selfDeletable), SelfDeletable>::value, "m_selfDeletable must be SelfDeletable");\ + bool *prevWasDeleted = (p)->m_selfDeletable.m_wasDeleted; \ bool wasDeleted = false; \ - m_wasDeleted = &wasDeleted; \ - func; \ + (p)->m_selfDeletable.m_wasDeleted = &wasDeleted; \ + {func;} \ if (wasDeleted) { \ if (prevWasDeleted) \ *prevWasDeleted = true; \ - return; \ + {action;} \ } \ - m_wasDeleted = prevWasDeleted; \ + (p)->m_selfDeletable.m_wasDeleted = prevWasDeleted; \ } +#define RETURN_IF_DELETED(func) \ +ACTION_IF_DELETED(this, func, return) + #endif // QANIMATIONJOBUTIL_P_H diff --git a/src/qml/animations/qcontinuinganimationgroupjob.cpp b/src/qml/animations/qcontinuinganimationgroupjob.cpp index 10096bf19c..88c0e9e60e 100644 --- a/src/qml/animations/qcontinuinganimationgroupjob.cpp +++ b/src/qml/animations/qcontinuinganimationgroupjob.cpp @@ -120,7 +120,7 @@ void QContinuingAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimat void QContinuingAnimationGroupJob::debugAnimation(QDebug d) const { - d << "ContinuingAnimationGroupJob(" << hex << (const void *) this << dec << ")"; + d << "ContinuingAnimationGroupJob(" << Qt::hex << (const void *) this << Qt::dec << ")"; debugChildren(d); } diff --git a/src/qml/animations/qparallelanimationgroupjob.cpp b/src/qml/animations/qparallelanimationgroupjob.cpp index 700fdf9fd9..420a934ba2 100644 --- a/src/qml/animations/qparallelanimationgroupjob.cpp +++ b/src/qml/animations/qparallelanimationgroupjob.cpp @@ -239,7 +239,7 @@ void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimatio void QParallelAnimationGroupJob::debugAnimation(QDebug d) const { - d << "ParallelAnimationGroupJob(" << hex << (const void *) this << dec << ")"; + d << "ParallelAnimationGroupJob(" << Qt::hex << (const void *) this << Qt::dec << ")"; debugChildren(d); } diff --git a/src/qml/animations/qpauseanimationjob.cpp b/src/qml/animations/qpauseanimationjob.cpp index 0652ed578b..aac04d2f8d 100644 --- a/src/qml/animations/qpauseanimationjob.cpp +++ b/src/qml/animations/qpauseanimationjob.cpp @@ -67,7 +67,7 @@ void QPauseAnimationJob::updateCurrentTime(int) void QPauseAnimationJob::debugAnimation(QDebug d) const { - d << "PauseAnimationJob(" << hex << (const void *) this << dec << ")" << "duration:" << m_duration; + d << "PauseAnimationJob(" << Qt::hex << (const void *) this << Qt::dec << ")" << "duration:" << m_duration; } QT_END_NAMESPACE diff --git a/src/qml/animations/qsequentialanimationgroupjob.cpp b/src/qml/animations/qsequentialanimationgroupjob.cpp index d98546122f..dc57444b32 100644 --- a/src/qml/animations/qsequentialanimationgroupjob.cpp +++ b/src/qml/animations/qsequentialanimationgroupjob.cpp @@ -426,7 +426,7 @@ void QSequentialAnimationGroupJob::animationRemoved(QAbstractAnimationJob *anim, void QSequentialAnimationGroupJob::debugAnimation(QDebug d) const { - d << "SequentialAnimationGroupJob(" << hex << (const void *) this << dec << ")" << "currentAnimation:" << (void *)m_currentAnimation; + d << "SequentialAnimationGroupJob(" << Qt::hex << (const void *) this << Qt::dec << ")" << "currentAnimation:" << (void *)m_currentAnimation; debugChildren(d); } diff --git a/src/qml/common/common.pri b/src/qml/common/common.pri new file mode 100644 index 0000000000..de95772120 --- /dev/null +++ b/src/qml/common/common.pri @@ -0,0 +1,3 @@ +HEADERS += \ + $$PWD/qqmlapiversion_p.h \ + $$PWD/qqmljsdiagnosticmessage_p.h diff --git a/src/qml/qmldirparser/qqmlsourcecoordinate_p.h b/src/qml/common/qqmlapiversion_p.h index 76ac741ae8..eca05558d8 100644 --- a/src/qml/qmldirparser/qqmlsourcecoordinate_p.h +++ b/src/qml/common/qqmlapiversion_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -37,36 +37,20 @@ ** ****************************************************************************/ -#ifndef QQMLSOURCECOORDINATE_P_H -#define QQMLSOURCECOORDINATE_P_H +#ifndef QQMLAPIVERSION_P_H +#define QQMLAPIVERSION_P_H // // W A R N I N G // ------------- // -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // -#include <QtCore/qglobal.h> +#define Q_QML_PRIVATE_API_VERSION 5 -#include <climits> - -QT_BEGIN_NAMESPACE - -inline quint16 qmlSourceCoordinate(int n) -{ - return (n > 0 && n <= static_cast<int>(USHRT_MAX)) ? static_cast<quint16>(n) : 0; -} - -inline int qmlSourceCoordinate(quint16 n) -{ - return (n == 0) ? -1 : static_cast<int>(n); -} - -QT_END_NAMESPACE - -#endif // QQMLSOURCECOORDINATE_P_H +#endif // QQMLAPIVERSION_P_H diff --git a/src/qml/debugger/qqmlmemoryprofiler_p.h b/src/qml/common/qqmljsdiagnosticmessage_p.h index 12a31a851f..763332ba76 100644 --- a/src/qml/debugger/qqmlmemoryprofiler_p.h +++ b/src/qml/common/qqmljsdiagnosticmessage_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef QQMLMEMORYPROFILER_H -#define QQMLMEMORYPROFILER_H +#ifndef QQMLJSDIAGNOSTICMESSAGE_P_H +#define QQMLJSDIAGNOSTICMESSAGE_P_H // // W A R N I N G @@ -51,84 +51,42 @@ // We mean it. // -#include <private/qtqmlglobal_p.h> -#include <QUrl> +#include <QtCore/qlogging.h> +#include <QtCore/qstring.h> -QT_BEGIN_NAMESPACE - -#if !QT_CONFIG(qml_debug) - -#define QML_MEMORY_SCOPE_URL(url) -#define QML_MEMORY_SCOPE_STRING(s) +// Include the API version here, to avoid complications when querying it for the +// QQmlSourceLocation -> line/column change. +#include <private/qqmlapiversion_p.h> -#else +QT_BEGIN_NAMESPACE -class Q_QML_PRIVATE_EXPORT QQmlMemoryScope +namespace QQmlJS { +struct DiagnosticMessage { -public: - explicit QQmlMemoryScope(const QUrl &url) - : pushed(false) - { - if (Q_UNLIKELY(openLibrary())) - init(url.path().toUtf8().constData()); - } + QString message; + QtMsgType type = QtCriticalMsg; + quint32 line = 0; + quint32 column = 0; - explicit QQmlMemoryScope(const char *string) - : pushed(false) + bool isError() const { - if (Q_UNLIKELY(openLibrary())) - init(string); + return type == QtCriticalMsg; } - ~QQmlMemoryScope() + bool isWarning() const { - if (Q_UNLIKELY(pushed)) - done(); + return type == QtWarningMsg; } - enum LibraryState - { - Unloaded, - Failed, - Loaded - }; - - static bool openLibrary() + bool isValid() const { - if (Q_LIKELY(state == Loaded)) - return true; - if (state == Failed) - return false; - - return doOpenLibrary(); + return !message.isEmpty(); } - -private: - Q_NEVER_INLINE void init(const char *string); - Q_NEVER_INLINE void done(); - Q_NEVER_INLINE static bool doOpenLibrary(); - - static LibraryState state; - - bool pushed; }; +} // namespace QQmlJS -class Q_QML_PRIVATE_EXPORT QQmlMemoryProfiler -{ -public: - static void enable(); - static void disable(); - static bool isEnabled(); - - static void clear(); - static void stats(int *allocCount, int *bytesAllocated); - static void save(const char *filename); -}; - -#define QML_MEMORY_SCOPE_URL(url) QQmlMemoryScope _qml_memory_scope(url) -#define QML_MEMORY_SCOPE_STRING(s) QQmlMemoryScope _qml_memory_scope(s) - -#endif +Q_DECLARE_TYPEINFO(QQmlJS::DiagnosticMessage, Q_MOVABLE_TYPE); QT_END_NAMESPACE -#endif // QQMLMEMORYPROFILER_H + +#endif // QQMLJSDIAGNOSTICMESSAGE_P_H diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri index c3dd5890d6..c6ae8c6b69 100644 --- a/src/qml/compiler/compiler.pri +++ b/src/qml/compiler/compiler.pri @@ -20,7 +20,6 @@ HEADERS += \ SOURCES += \ $$PWD/qv4bytecodegenerator.cpp \ - $$PWD/qv4compileddata.cpp \ $$PWD/qv4compiler.cpp \ $$PWD/qv4compilercontext.cpp \ $$PWD/qv4compilerscanfunctions.cpp \ diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 3e5798ba8b..1891f31f13 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -374,13 +374,12 @@ bool IRBuilder::generateFromQml(const QString &code, const QString &url, Documen if (!parseResult || !diagnosticMessages.isEmpty()) { // Extract errors from the parser for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) { - if (m.isWarning()) { - qWarning("%s:%d : %s", qPrintable(url), m.loc.startLine, qPrintable(m.message)); + qWarning("%s:%d : %s", qPrintable(url), m.line, qPrintable(m.message)); continue; } - recordError(m.loc, m.message); + errors << m; } return false; } @@ -650,11 +649,9 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node) return false; } - if (node->versionToken.isValid()) { - int major, minor; - extractVersion(textRefAt(node->versionToken), &major, &minor); - import->majorVersion = major; - import->minorVersion = minor; + if (node->version) { + import->majorVersion = node->version->majorVersion; + import->minorVersion = node->version->minorVersion; } else if (import->type == QV4::CompiledData::Import::ImportLibrary) { recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Library import requires a version")); return false; @@ -770,33 +767,33 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) static const struct TypeNameToType { const char *name; size_t nameLength; - QV4::CompiledData::Property::Type type; + QV4::CompiledData::BuiltinType type; } propTypeNameToTypes[] = { - { "int", strlen("int"), QV4::CompiledData::Property::Int }, - { "bool", strlen("bool"), QV4::CompiledData::Property::Bool }, - { "double", strlen("double"), QV4::CompiledData::Property::Real }, - { "real", strlen("real"), QV4::CompiledData::Property::Real }, - { "string", strlen("string"), QV4::CompiledData::Property::String }, - { "url", strlen("url"), QV4::CompiledData::Property::Url }, - { "color", strlen("color"), QV4::CompiledData::Property::Color }, + { "int", strlen("int"), QV4::CompiledData::BuiltinType::Int }, + { "bool", strlen("bool"), QV4::CompiledData::BuiltinType::Bool }, + { "double", strlen("double"), QV4::CompiledData::BuiltinType::Real }, + { "real", strlen("real"), QV4::CompiledData::BuiltinType::Real }, + { "string", strlen("string"), QV4::CompiledData::BuiltinType::String }, + { "url", strlen("url"), QV4::CompiledData::BuiltinType::Url }, + { "color", strlen("color"), QV4::CompiledData::BuiltinType::Color }, // Internally QTime, QDate and QDateTime are all supported. // To be more consistent with JavaScript we expose only // QDateTime as it matches closely with the Date JS type. // We also call it "date" to match. // { "time", strlen("time"), Property::Time }, // { "date", strlen("date"), Property::Date }, - { "date", strlen("date"), QV4::CompiledData::Property::DateTime }, - { "rect", strlen("rect"), QV4::CompiledData::Property::Rect }, - { "point", strlen("point"), QV4::CompiledData::Property::Point }, - { "size", strlen("size"), QV4::CompiledData::Property::Size }, - { "font", strlen("font"), QV4::CompiledData::Property::Font }, - { "vector2d", strlen("vector2d"), QV4::CompiledData::Property::Vector2D }, - { "vector3d", strlen("vector3d"), QV4::CompiledData::Property::Vector3D }, - { "vector4d", strlen("vector4d"), QV4::CompiledData::Property::Vector4D }, - { "quaternion", strlen("quaternion"), QV4::CompiledData::Property::Quaternion }, - { "matrix4x4", strlen("matrix4x4"), QV4::CompiledData::Property::Matrix4x4 }, - { "variant", strlen("variant"), QV4::CompiledData::Property::Variant }, - { "var", strlen("var"), QV4::CompiledData::Property::Var } + { "date", strlen("date"), QV4::CompiledData::BuiltinType::DateTime }, + { "rect", strlen("rect"), QV4::CompiledData::BuiltinType::Rect }, + { "point", strlen("point"), QV4::CompiledData::BuiltinType::Point }, + { "size", strlen("size"), QV4::CompiledData::BuiltinType::Size }, + { "font", strlen("font"), QV4::CompiledData::BuiltinType::Font }, + { "vector2d", strlen("vector2d"), QV4::CompiledData::BuiltinType::Vector2D }, + { "vector3d", strlen("vector3d"), QV4::CompiledData::BuiltinType::Vector3D }, + { "vector4d", strlen("vector4d"), QV4::CompiledData::BuiltinType::Vector4D }, + { "quaternion", strlen("quaternion"), QV4::CompiledData::BuiltinType::Quaternion }, + { "matrix4x4", strlen("matrix4x4"), QV4::CompiledData::BuiltinType::Matrix4x4 }, + { "variant", strlen("variant"), QV4::CompiledData::BuiltinType::Variant }, + { "var", strlen("var"), QV4::CompiledData::BuiltinType::Var } }; static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) / sizeof(propTypeNameToTypes[0]); @@ -836,8 +833,9 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) if (memberType.at(0).isUpper()) { // Must be a QML object type. // Lazily determine type during compilation. - param->type = QV4::CompiledData::Property::Custom; - param->customTypeNameIndex = registerString(memberType); + param->indexIsBuiltinType = false; + param->typeNameIndexOrBuiltinType = registerString(memberType); + Q_ASSERT(quint32(jsGenerator->getStringId(memberType)) < (1u << 31)); } else { QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: "); errStr.append(memberType); @@ -846,13 +844,12 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) } } else { // the parameter is a known basic type - param->type = type->type; - param->customTypeNameIndex = emptyStringIndex; + param->indexIsBuiltinType = true; + param->typeNameIndexOrBuiltinType = static_cast<quint32>(type->type); + Q_ASSERT(quint32(type->type) < (1u << 31)); } param->nameIndex = registerString(p->name.toString()); - param->location.line = p->identifierToken.startLine; - param->location.column = p->identifierToken.startColumn; signal->parameters->append(param); p = p->next; } @@ -875,13 +872,15 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) } else { const QStringRef &name = node->name; + Property *property = New<Property>(); + property->isReadOnly = node->isReadonlyMember; + bool typeFound = false; - QV4::CompiledData::Property::Type type = QV4::CompiledData::Property::Var; for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) { const TypeNameToType *t = propTypeNameToTypes + ii; if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) { - type = t->type; + property->setBuiltinType(t->type); typeFound = true; } } @@ -889,11 +888,10 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) if (!typeFound && memberType.at(0).isUpper()) { const QStringRef &typeModifier = node->typeModifier; - if (typeModifier.isEmpty()) { - type = QV4::CompiledData::Property::Custom; - } else if (typeModifier == QLatin1String("list")) { - type = QV4::CompiledData::Property::CustomList; - } else { + property->setCustomType(registerString(memberType)); + if (typeModifier == QLatin1String("list")) { + property->isList = true; + } else if (!typeModifier.isEmpty()) { recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier")); return false; } @@ -908,16 +906,6 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) return false; } - Property *property = New<Property>(); - property->flags = 0; - if (node->isReadonlyMember) - property->flags |= QV4::CompiledData::Property::IsReadOnly; - property->type = type; - if (type >= QV4::CompiledData::Property::Custom) - property->customTypeNameIndex = registerString(memberType); - else - property->customTypeNameIndex = emptyStringIndex; - const QString propName = name.toString(); property->nameIndex = registerString(propName); @@ -1040,7 +1028,7 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST binding->valueLocation.line = loc.startLine; binding->valueLocation.column = loc.startColumn; binding->type = QV4::CompiledData::Binding::Type_Invalid; - if (_propertyDeclaration && (_propertyDeclaration->flags & QV4::CompiledData::Property::IsReadOnly)) + if (_propertyDeclaration && _propertyDeclaration->isReadOnly) binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration; QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement); @@ -1271,7 +1259,7 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo binding->flags = 0; - if (_propertyDeclaration && (_propertyDeclaration->flags & QV4::CompiledData::Property::IsReadOnly)) + if (_propertyDeclaration && _propertyDeclaration->isReadOnly) binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration; // No type name on the initializer means it must be a group property @@ -1502,7 +1490,8 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O void IRBuilder::recordError(const QQmlJS::AST::SourceLocation &location, const QString &description) { QQmlJS::DiagnosticMessage error; - error.loc = location; + error.line = location.startLine; + error.column = location.startColumn; error.message = description; errors << error; } @@ -1534,7 +1523,7 @@ bool IRBuilder::isStatementNodeScript(QQmlJS::AST::Statement *statement) bool IRBuilder::isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement) { - if (property->type != QV4::CompiledData::Property::Custom) + if (property->isBuiltinType || property->isList) return false; QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement); if (!exprStmt) @@ -1749,7 +1738,7 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen jsUnit->unitSize += totalSize; memcpy(jsUnit->qmlUnit(), qmlUnit, totalSize); free(qmlUnit); - jsUnit->generateChecksum(); + QV4::Compiler::JSUnitGenerator::generateUnitChecksum(jsUnit); qmlUnit = jsUnit->qmlUnit(); } @@ -1838,7 +1827,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil } scan.leaveEnvironment(); - if (hasError) + if (hasError()) return QVector<int>(); _context = nullptr; diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index b49eaee420..64298466e0 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -526,16 +526,15 @@ private: } // namespace QmlIR -struct QQmlCompileError +inline QQmlJS::DiagnosticMessage qQmlCompileError(const QV4::CompiledData::Location &location, + const QString &description) { - QQmlCompileError() {} - QQmlCompileError(const QV4::CompiledData::Location &location, const QString &description) - : location(location), description(description) {} - QV4::CompiledData::Location location; - QString description; - - bool isSet() const { return !description.isEmpty(); } -}; + QQmlJS::DiagnosticMessage error; + error.line = location.line; + error.column = location.column; + error.message = description; + return error; +} QT_END_NAMESPACE diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index b7e3e20fd0..453963c1dd 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -43,6 +43,7 @@ #include <QtCore/QCoreApplication> #include <QtCore/QStringList> #include <QtCore/QStack> +#include <QtCore/qurl.h> #include <QScopeGuard> #include <private/qqmljsast_p.h> #include <private/qqmljslexer_p.h> @@ -53,7 +54,8 @@ #include <private/qv4compilercontrolflow_p.h> #include <private/qv4bytecodegenerator_p.h> #include <private/qv4compilerscanfunctions_p.h> -#include <qqmlerror.h> +#include <private/qv4stringtoarrayindex_p.h> +#include <private/qqmljsdiagnosticmessage_p.h> #include <cmath> #include <iostream> @@ -96,7 +98,6 @@ Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict) , jsUnitGenerator(jsUnitGenerator) , _strictMode(strict) , _fileNameIsUrl(false) - , hasError(false) { jsUnitGenerator->codeGeneratorName = QStringLiteral("moth"); pushExpr(); @@ -189,7 +190,7 @@ void Codegen::generateFromProgram(const QString &fileName, ScanFunctions scan(this, sourceCode, contextType); scan(node); - if (hasError) + if (hasError()) return; defineFunction(QStringLiteral("%entry"), node, nullptr, node->statements); @@ -213,7 +214,7 @@ void Codegen::generateFromModule(const QString &fileName, ScanFunctions scan(this, sourceCode, ContextType::ESModule); scan(node); - if (hasError) + if (hasError()) return; { @@ -263,7 +264,7 @@ Context *Codegen::enterBlock(Node *node) Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr) { - if (hasError) + if (hasError()) return exprResult(); if (expr.isConstant()) { @@ -414,7 +415,7 @@ void Codegen::statement(ExpressionNode *ast) qSwap(_volatileMemoryLocations, vLocs); Reference result = popResult(); - if (hasError) + if (hasError()) return; if (result.loadTriggersSideEffect()) result.loadInAccumulator(); // triggers side effects @@ -424,7 +425,7 @@ void Codegen::statement(ExpressionNode *ast) void Codegen::condition(ExpressionNode *ast, const BytecodeGenerator::Label *iftrue, const BytecodeGenerator::Label *iffalse, bool trueBlockFollowsCondition) { - if (hasError) + if (hasError()) return; if (!ast) @@ -434,7 +435,7 @@ void Codegen::condition(ExpressionNode *ast, const BytecodeGenerator::Label *ift accept(ast); Result r = popExpr(); - if (hasError) + if (hasError()) return; if (r.format() == ex) { @@ -588,7 +589,7 @@ Codegen::Reference Codegen::targetForPatternElement(AST::PatternElement *p) if (!p->bindingTarget || p->destructuringPattern()) return Codegen::Reference::fromStackSlot(this); Reference lhs = expression(p->bindingTarget); - if (hasError) + if (hasError()) return lhs; if (!lhs.isLValue()) { throwReferenceError(p->bindingTarget->firstSourceLocation(), QStringLiteral("Binding target is not a reference.")); @@ -606,14 +607,14 @@ void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, con Reference varToStore = targetForPatternElement(e); if (isDefinition) varToStore.isReferenceToConst = false; - if (hasError) + if (hasError()) return; if (e->initializer) { if (!baseRef.isValid()) { // assignment Reference expr = expression(e->initializer); - if (hasError) + if (hasError()) return; expr.loadInAccumulator(); varToStore.storeConsumeAccumulator(); @@ -621,7 +622,7 @@ void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, con baseRef.loadInAccumulator(); BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined(); Reference expr = expression(e->initializer); - if (hasError) { + if (hasError()) { jump.link(); return; } @@ -632,7 +633,7 @@ void Codegen::initializeAndDestructureBindingElement(AST::PatternElement *e, con baseRef.loadInAccumulator(); BytecodeGenerator::Jump jump = bytecodeGenerator->jumpNotUndefined(); Reference expr = expression(e->initializer); - if (hasError) { + if (hasError()) { jump.link(); return; } @@ -669,7 +670,7 @@ Codegen::Reference Codegen::referenceForPropertyName(const Codegen::Reference &o Reference property; if (cname) { Reference computedName = expression(cname->expression); - if (hasError) + if (hasError()) return Reference(); computedName = computedName.storeOnStack(); property = Reference::fromSubscript(object, computedName).asLValue(); @@ -692,10 +693,10 @@ void Codegen::destructurePropertyList(const Codegen::Reference &object, PatternP PatternProperty *p = it->property; RegisterScope scope(this); Reference property = referenceForPropertyName(object, p->name); - if (hasError) + if (hasError()) return; initializeAndDestructureBindingElement(p, property, isDefinition); - if (hasError) + if (hasError()) return; } } @@ -751,7 +752,7 @@ void Codegen::destructureElementList(const Codegen::Reference &array, PatternEle next.done = iteratorDone.stackSlot(); bytecodeGenerator->addInstruction(next); initializeAndDestructureBindingElement(e, iteratorValue, isDefinition); - if (hasError) + if (hasError()) return; } } @@ -1015,7 +1016,7 @@ bool Codegen::visit(ClassExpression *ast) if (ast->heritage) { bytecodeGenerator->setLocation(ast->heritage->firstSourceLocation()); Reference r = expression(ast->heritage); - if (hasError) + if (hasError()) return false; r.storeOnStack(heritage.stackSlot()); } else { @@ -1034,7 +1035,7 @@ bool Codegen::visit(ClassExpression *ast) RegisterScope scope(this); bytecodeGenerator->setLocation(cname->firstSourceLocation()); Reference computedName = expression(cname->expression); - if (hasError) + if (hasError()) return false; computedName.storeOnStack(member->isStatic ? currentStaticName++ : currentNonStaticName++); } @@ -1067,19 +1068,20 @@ bool Codegen::visit(ClassDeclaration *ast) bool Codegen::visit(Expression *ast) { - if (hasError) + if (hasError()) return false; TailCallBlocker blockTailCalls(this); statement(ast->left); blockTailCalls.unblock(); + clearExprResultName(); // The name only holds for the left part accept(ast->right); return false; } bool Codegen::visit(ArrayPattern *ast) { - if (hasError) + if (hasError()) return false; TailCallBlocker blockTailCalls(this); @@ -1101,7 +1103,7 @@ bool Codegen::visit(ArrayPattern *ast) } else { RegisterScope scope(this); Reference r = expression(arg); - if (hasError) + if (hasError()) return; (void) r.storeOnStack(temp); } @@ -1119,7 +1121,7 @@ bool Codegen::visit(ArrayPattern *ast) continue; push(e->initializer); - if (hasError) + if (hasError()) return false; } @@ -1180,7 +1182,7 @@ bool Codegen::visit(ArrayPattern *ast) { RegisterScope innerScope(this); Reference expr = expression(it->element->initializer); - if (hasError) + if (hasError()) return false; expr.loadInAccumulator(); @@ -1221,7 +1223,7 @@ bool Codegen::visit(ArrayPattern *ast) } else { RegisterScope innerScope(this); Reference expr = expression(it->element->initializer); - if (hasError) + if (hasError()) return false; expr.loadInAccumulator(); @@ -1239,12 +1241,12 @@ bool Codegen::visit(ArrayPattern *ast) bool Codegen::visit(ArrayMemberExpression *ast) { - if (hasError) + if (hasError()) return false; TailCallBlocker blockTailCalls(this); Reference base = expression(ast->base); - if (hasError) + if (hasError()) return false; if (base.isSuper()) { Reference index = expression(ast->expression).storeOnStack(); @@ -1252,7 +1254,7 @@ bool Codegen::visit(ArrayMemberExpression *ast) return false; } base = base.storeOnStack(); - if (hasError) + if (hasError()) return false; if (AST::StringLiteral *str = AST::cast<AST::StringLiteral *>(ast->expression)) { QString s = str->value.toString(); @@ -1266,7 +1268,7 @@ bool Codegen::visit(ArrayMemberExpression *ast) return false; } Reference index = expression(ast->expression); - if (hasError) + if (hasError()) return false; setExprResult(Reference::fromSubscript(base, index)); return false; @@ -1293,7 +1295,7 @@ static QSOperator::Op baseOp(int op) bool Codegen::visit(BinaryExpression *ast) { - if (hasError) + if (hasError()) return false; TailCallBlocker blockTailCalls(this); @@ -1311,7 +1313,7 @@ bool Codegen::visit(BinaryExpression *ast) auto endif = bytecodeGenerator->newLabel(); Reference left = expression(ast->left); - if (hasError) + if (hasError()) return false; left.loadInAccumulator(); @@ -1321,7 +1323,7 @@ bool Codegen::visit(BinaryExpression *ast) blockTailCalls.unblock(); Reference right = expression(ast->right); - if (hasError) + if (hasError()) return false; right.loadInAccumulator(); @@ -1342,7 +1344,7 @@ bool Codegen::visit(BinaryExpression *ast) auto endif = bytecodeGenerator->newLabel(); Reference left = expression(ast->left); - if (hasError) + if (hasError()) return false; left.loadInAccumulator(); @@ -1352,7 +1354,7 @@ bool Codegen::visit(BinaryExpression *ast) blockTailCalls.unblock(); Reference right = expression(ast->right); - if (hasError) + if (hasError()) return false; right.loadInAccumulator(); @@ -1365,7 +1367,7 @@ bool Codegen::visit(BinaryExpression *ast) if (AST::Pattern *p = ast->left->patternCast()) { RegisterScope scope(this); Reference right = expression(ast->right); - if (hasError) + if (hasError()) return false; right = right.storeOnStack(); destructurePattern(p, right); @@ -1376,7 +1378,7 @@ bool Codegen::visit(BinaryExpression *ast) return false; } Reference left = expression(ast->left); - if (hasError) + if (hasError()) return false; if (!left.isLValue()) { @@ -1388,7 +1390,7 @@ bool Codegen::visit(BinaryExpression *ast) return false; blockTailCalls.unblock(); Reference r = expression(ast->right); - if (hasError) + if (hasError()) return false; r.loadInAccumulator(); if (exprAccept(nx)) @@ -1399,7 +1401,7 @@ bool Codegen::visit(BinaryExpression *ast) } Reference left = expression(ast->left); - if (hasError) + if (hasError()) return false; switch (ast->op) { @@ -1433,7 +1435,7 @@ bool Codegen::visit(BinaryExpression *ast) Reference tempLeft = left.storeOnStack(); Reference right = expression(ast->right); - if (hasError) + if (hasError()) return false; binopHelper(baseOp(ast->op), tempLeft, right).loadInAccumulator(); @@ -1447,7 +1449,7 @@ bool Codegen::visit(BinaryExpression *ast) case QSOperator::BitXor: if (left.isConstant()) { Reference right = expression(ast->right); - if (hasError) + if (hasError()) return false; setExprResult(binopHelper(static_cast<QSOperator::Op>(ast->op), right, left)); break; @@ -1480,7 +1482,7 @@ bool Codegen::visit(BinaryExpression *ast) left = left.storeOnStack(); // force any loads of the lhs, so the rhs won't clobber it right = expression(ast->right); } - if (hasError) + if (hasError()) return false; setExprResult(binopHelper(static_cast<QSOperator::Op>(ast->op), left, right)); @@ -1864,7 +1866,7 @@ Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Refe bool Codegen::visit(CallExpression *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); @@ -1872,7 +1874,7 @@ bool Codegen::visit(CallExpression *ast) Reference base = expression(ast->base); - if (hasError) + if (hasError()) return false; switch (base.type) { case Reference::Member: @@ -1895,7 +1897,7 @@ bool Codegen::visit(CallExpression *ast) int functionObject = bytecodeGenerator->newRegister(); auto calldata = pushArgs(ast->arguments); - if (hasError) + if (hasError()) return false; blockTailCalls.unblock(); @@ -2043,7 +2045,7 @@ Codegen::Arguments Codegen::pushArgs(ArgumentList *args) } RegisterScope scope(this); Reference e = expression(it->expression); - if (hasError) + if (hasError()) break; if (!argc && !it->next && !hasSpread) { // avoid copy for functions taking a single argument @@ -2072,7 +2074,7 @@ Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args) for (TemplateLiteral *it = args; it && it->expression; it = it->next) { RegisterScope scope(this); Reference e = expression(it->expression); - if (hasError) + if (hasError()) break; (void) e.storeOnStack(calldata + argc); ++argc; @@ -2083,7 +2085,7 @@ Codegen::Arguments Codegen::pushTemplateArgs(TemplateLiteral *args) bool Codegen::visit(ConditionalExpression *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); @@ -2097,14 +2099,14 @@ bool Codegen::visit(ConditionalExpression *ast) iftrue.link(); Reference ok = expression(ast->ok); - if (hasError) + if (hasError()) return false; ok.loadInAccumulator(); BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump(); iffalse.link(); Reference ko = expression(ast->ko); - if (hasError) { + if (hasError()) { jump_endif.link(); // dummy link, to prevent assert in Jump destructor from triggering return false; } @@ -2118,13 +2120,13 @@ bool Codegen::visit(ConditionalExpression *ast) bool Codegen::visit(DeleteExpression *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); TailCallBlocker blockTailCalls(this); Reference expr = expression(ast->expression); - if (hasError) + if (hasError()) return false; switch (expr.type) { @@ -2189,7 +2191,7 @@ bool Codegen::visit(DeleteExpression *ast) bool Codegen::visit(FalseLiteral *) { - if (hasError) + if (hasError()) return false; setExprResult(Reference::fromConst(this, QV4::Encode(false))); @@ -2198,7 +2200,7 @@ bool Codegen::visit(FalseLiteral *) bool Codegen::visit(SuperLiteral *) { - if (hasError) + if (hasError()) return false; setExprResult(Reference::fromSuper(this)); @@ -2207,7 +2209,7 @@ bool Codegen::visit(SuperLiteral *) bool Codegen::visit(FieldMemberExpression *ast) { - if (hasError) + if (hasError()) return false; TailCallBlocker blockTailCalls(this); @@ -2230,7 +2232,7 @@ bool Codegen::visit(FieldMemberExpression *ast) } Reference base = expression(ast->base); - if (hasError) + if (hasError()) return false; if (base.isSuper()) { Instruction::LoadRuntimeString load; @@ -2246,7 +2248,7 @@ bool Codegen::visit(FieldMemberExpression *ast) bool Codegen::visit(TaggedTemplate *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); @@ -2255,7 +2257,7 @@ bool Codegen::visit(TaggedTemplate *ast) bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast) { - if (hasError) + if (hasError()) return false; int functionObject = -1, thisObject = -1; @@ -2279,7 +2281,7 @@ bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast) int templateObjectTemp = Reference::fromAccumulator(this).storeOnStack().stackSlot(); Q_UNUSED(templateObjectTemp); auto calldata = pushTemplateArgs(ast->templateLiteral); - if (hasError) + if (hasError()) return false; ++calldata.argc; Q_ASSERT(calldata.argv == templateObjectTemp + 1); @@ -2308,7 +2310,7 @@ void Codegen::createTemplateObject(TemplateLiteral *t) bool Codegen::visit(FunctionExpression *ast) { - if (hasError) + if (hasError()) return false; TailCallBlocker blockTailCalls(this); @@ -2316,7 +2318,7 @@ bool Codegen::visit(FunctionExpression *ast) RegisterScope scope(this); int function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body); - if (hasError) + if (hasError()) return false; loadClosure(function); setExprResult(Reference::fromAccumulator(this)); @@ -2372,7 +2374,7 @@ void Codegen::loadClosure(int closureId) bool Codegen::visit(IdentifierExpression *ast) { - if (hasError) + if (hasError()) return false; setExprResult(referenceForName(ast->name.toString(), false, ast->firstSourceLocation())); @@ -2381,7 +2383,7 @@ bool Codegen::visit(IdentifierExpression *ast) bool Codegen::visit(NestedExpression *ast) { - if (hasError) + if (hasError()) return false; accept(ast->expression); @@ -2400,7 +2402,7 @@ void Codegen::handleConstruct(const Reference &base, ArgumentList *arguments) } auto calldata = pushArgs(arguments); - if (hasError) + if (hasError()) return; if (base.isSuper()) @@ -2430,14 +2432,14 @@ void Codegen::handleConstruct(const Reference &base, ArgumentList *arguments) bool Codegen::visit(NewExpression *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); TailCallBlocker blockTailCalls(this); Reference base = expression(ast->expression); - if (hasError) + if (hasError()) return false; if (base.isSuper()) { throwSyntaxError(ast->expression->firstSourceLocation(), QStringLiteral("Cannot use new with super.")); @@ -2450,14 +2452,14 @@ bool Codegen::visit(NewExpression *ast) bool Codegen::visit(NewMemberExpression *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); TailCallBlocker blockTailCalls(this); Reference base = expression(ast->base); - if (hasError) + if (hasError()) return false; if (base.isSuper()) { throwSyntaxError(ast->base->firstSourceLocation(), QStringLiteral("Cannot use new with super.")); @@ -2470,7 +2472,7 @@ bool Codegen::visit(NewMemberExpression *ast) bool Codegen::visit(NotExpression *ast) { - if (hasError) + if (hasError()) return false; TailCallBlocker blockTailCalls(this); @@ -2480,7 +2482,7 @@ bool Codegen::visit(NotExpression *ast) bool Codegen::visit(NullExpression *) { - if (hasError) + if (hasError()) return false; if (exprAccept(cx)) @@ -2493,7 +2495,7 @@ bool Codegen::visit(NullExpression *) bool Codegen::visit(NumericLiteral *ast) { - if (hasError) + if (hasError()) return false; setExprResult(Reference::fromConst(this, QV4::Encode::smallestNumber(ast->value))); @@ -2502,7 +2504,7 @@ bool Codegen::visit(NumericLiteral *ast) bool Codegen::visit(ObjectPattern *ast) { - if (hasError) + if (hasError()) return false; TailCallBlocker blockTailCalls(this); @@ -2537,8 +2539,8 @@ bool Codegen::visit(ObjectPattern *ast) { RegisterScope innerScope(this); - Reference value = expression(p->initializer); - if (hasError) + Reference value = expression(p->initializer, name); + if (hasError()) return false; value.loadInAccumulator(); } @@ -2565,7 +2567,7 @@ bool Codegen::visit(ObjectPattern *ast) if (cname) { RegisterScope innerScope(this); Reference name = expression(cname->expression); - if (hasError) + if (hasError()) return false; name.loadInAccumulator(); } else { @@ -2590,12 +2592,12 @@ bool Codegen::visit(ObjectPattern *ast) FunctionExpression *f = p->initializer->asFunctionDefinition(); Q_ASSERT(f); int function = defineFunction(f->name.toString(), f, f->formals, f->body); - if (hasError) + if (hasError()) return false; Reference::fromConst(this, Encode(function)).loadInAccumulator(); } else { Reference value = expression(p->initializer); - if (hasError) + if (hasError()) return false; value.loadInAccumulator(); } @@ -2614,11 +2616,11 @@ bool Codegen::visit(ObjectPattern *ast) bool Codegen::visit(PostDecrementExpression *ast) { - if (hasError) + if (hasError()) return false; Reference expr = expression(ast->base); - if (hasError) + if (hasError()) return false; if (!expr.isLValue()) { throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation")); @@ -2634,11 +2636,11 @@ bool Codegen::visit(PostDecrementExpression *ast) bool Codegen::visit(PostIncrementExpression *ast) { - if (hasError) + if (hasError()) return false; Reference expr = expression(ast->base); - if (hasError) + if (hasError()) return false; if (!expr.isLValue()) { throwReferenceError(ast->base->lastSourceLocation(), QStringLiteral("Invalid left-hand side expression in postfix operation")); @@ -2652,11 +2654,11 @@ bool Codegen::visit(PostIncrementExpression *ast) } bool Codegen::visit(PreDecrementExpression *ast) -{ if (hasError) +{ if (hasError()) return false; Reference expr = expression(ast->expression); - if (hasError) + if (hasError()) return false; if (!expr.isLValue()) { throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference.")); @@ -2671,11 +2673,11 @@ bool Codegen::visit(PreDecrementExpression *ast) bool Codegen::visit(PreIncrementExpression *ast) { - if (hasError) + if (hasError()) return false; Reference expr = expression(ast->expression); - if (hasError) + if (hasError()) return false; if (!expr.isLValue()) { throwReferenceError(ast->expression->lastSourceLocation(), QStringLiteral("Prefix ++ operator applied to value that is not a reference.")); @@ -2690,7 +2692,7 @@ bool Codegen::visit(PreIncrementExpression *ast) bool Codegen::visit(RegExpLiteral *ast) { - if (hasError) + if (hasError()) return false; auto r = Reference::fromStackSlot(this); @@ -2706,7 +2708,7 @@ bool Codegen::visit(RegExpLiteral *ast) bool Codegen::visit(StringLiteral *ast) { - if (hasError) + if (hasError()) return false; auto r = Reference::fromAccumulator(this); @@ -2721,7 +2723,7 @@ bool Codegen::visit(StringLiteral *ast) bool Codegen::visit(TemplateLiteral *ast) { - if (hasError) + if (hasError()) return false; TailCallBlocker blockTailCalls(this); @@ -2738,7 +2740,7 @@ bool Codegen::visit(TemplateLiteral *ast) bytecodeGenerator->addInstruction(store); Reference expr = expression(ast->expression); - if (hasError) + if (hasError()) return false; if (ast->next) { @@ -2768,7 +2770,7 @@ bool Codegen::visit(TemplateLiteral *ast) bool Codegen::visit(ThisExpression *) { - if (hasError) + if (hasError()) return false; if (_context->isArrowFunction) { @@ -2783,7 +2785,7 @@ bool Codegen::visit(ThisExpression *) bool Codegen::visit(TildeExpression *ast) { - if (hasError) + if (hasError()) return false; TailCallBlocker blockTailCalls(this); @@ -2793,7 +2795,7 @@ bool Codegen::visit(TildeExpression *ast) bool Codegen::visit(TrueLiteral *) { - if (hasError) + if (hasError()) return false; setExprResult(Reference::fromConst(this, QV4::Encode(true))); @@ -2802,14 +2804,14 @@ bool Codegen::visit(TrueLiteral *) bool Codegen::visit(TypeOfExpression *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); TailCallBlocker blockTailCalls(this); Reference expr = expression(ast->expression); - if (hasError) + if (hasError()) return false; if (expr.type == Reference::Name) { @@ -2829,7 +2831,7 @@ bool Codegen::visit(TypeOfExpression *ast) bool Codegen::visit(UnaryMinusExpression *ast) { - if (hasError) + if (hasError()) return false; TailCallBlocker blockTailCalls(this); @@ -2839,7 +2841,7 @@ bool Codegen::visit(UnaryMinusExpression *ast) bool Codegen::visit(UnaryPlusExpression *ast) { - if (hasError) + if (hasError()) return false; TailCallBlocker blockTailCalls(this); @@ -2849,7 +2851,7 @@ bool Codegen::visit(UnaryPlusExpression *ast) bool Codegen::visit(VoidExpression *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); @@ -2862,7 +2864,7 @@ bool Codegen::visit(VoidExpression *ast) bool Codegen::visit(FunctionDeclaration * ast) { - if (hasError) + if (hasError()) return false; // no need to block tail calls: the function body isn't visited here. @@ -2884,7 +2886,7 @@ bool Codegen::visit(YieldExpression *ast) RegisterScope scope(this); TailCallBlocker blockTailCalls(this); Reference expr = ast->expression ? expression(ast->expression) : Reference::fromConst(this, Encode::undefined()); - if (hasError) + if (hasError()) return false; Reference acc = Reference::fromAccumulator(this); @@ -2979,7 +2981,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, // already defined return leaveContext(); - _context->name = name; + _context->name = name.isEmpty() ? currentExpr().result().name : name; _module->functions.append(_context); _context->functionIndex = _module->functions.count() - 1; @@ -3062,7 +3064,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, } else { if (e->bindingTarget || e->initializer) { initializeAndDestructureBindingElement(e, arg); - if (hasError) + if (hasError()) break; } } @@ -3078,7 +3080,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, statementList(body); - if (!hasError) { + if (!hasError()) { bytecodeGenerator->setLocation(ast->lastSourceLocation()); _context->emitBlockFooter(this); @@ -3125,7 +3127,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, bool Codegen::visit(Block *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); @@ -3137,7 +3139,7 @@ bool Codegen::visit(Block *ast) bool Codegen::visit(BreakStatement *ast) { - if (hasError) + if (hasError()) return false; // no need to block tail calls here: children aren't visited @@ -3162,7 +3164,7 @@ bool Codegen::visit(BreakStatement *ast) bool Codegen::visit(ContinueStatement *ast) { - if (hasError) + if (hasError()) return false; // no need to block tail calls here: children aren't visited @@ -3195,7 +3197,7 @@ bool Codegen::visit(DebuggerStatement *) bool Codegen::visit(DoWhileStatement *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); @@ -3240,7 +3242,7 @@ bool Codegen::visit(EmptyStatement *) bool Codegen::visit(ExpressionStatement *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); @@ -3248,7 +3250,7 @@ bool Codegen::visit(ExpressionStatement *ast) if (requiresReturnValue) { Reference e = expression(ast->expression); - if (hasError) + if (hasError()) return false; (void) e.storeOnStack(_returnAddress); } else { @@ -3259,7 +3261,7 @@ bool Codegen::visit(ExpressionStatement *ast) bool Codegen::visit(ForEachStatement *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); @@ -3275,7 +3277,7 @@ bool Codegen::visit(ForEachStatement *ast) RegisterScope innerScope(this); ControlFlowBlock controlFlow(this, ast); Reference expr = expression(ast->expression); - if (hasError) + if (hasError()) return false; expr.loadInAccumulator(); @@ -3318,7 +3320,7 @@ bool Codegen::visit(ForEachStatement *ast) destructurePattern(p, lhsValue); } else { Reference lhs = expression(e); - if (hasError) + if (hasError()) goto error; if (!lhs.isLValue()) { throwReferenceError(e->firstSourceLocation(), QStringLiteral("Invalid left-hand side expression for 'in' expression")); @@ -3330,7 +3332,7 @@ bool Codegen::visit(ForEachStatement *ast) } } else if (PatternElement *p = AST::cast<PatternElement *>(ast->lhs)) { initializeAndDestructureBindingElement(p, lhsValue, /*isDefinition =*/ true); - if (hasError) + if (hasError()) goto error; } else { Q_UNREACHABLE(); @@ -3356,7 +3358,7 @@ bool Codegen::visit(ForEachStatement *ast) bool Codegen::visit(ForStatement *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); @@ -3400,7 +3402,7 @@ bool Codegen::visit(ForStatement *ast) bool Codegen::visit(IfStatement *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); @@ -3432,7 +3434,7 @@ bool Codegen::visit(IfStatement *ast) bool Codegen::visit(LabelledStatement *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); @@ -3480,7 +3482,7 @@ void Codegen::emitReturn(const Reference &expr) bool Codegen::visit(ReturnStatement *ast) { - if (hasError) + if (hasError()) return false; if (_functionContext->contextType != ContextType::Function && _functionContext->contextType != ContextType::Binding) { @@ -3490,7 +3492,7 @@ bool Codegen::visit(ReturnStatement *ast) Reference expr; if (ast->expression) { expr = expression(ast->expression); - if (hasError) + if (hasError()) return false; } else { expr = Reference::fromConst(this, Encode::undefined()); @@ -3503,7 +3505,7 @@ bool Codegen::visit(ReturnStatement *ast) bool Codegen::visit(SwitchStatement *ast) { - if (hasError) + if (hasError()) return false; if (requiresReturnValue) @@ -3516,7 +3518,7 @@ bool Codegen::visit(SwitchStatement *ast) BytecodeGenerator::Label switchEnd = bytecodeGenerator->newLabel(); Reference lhs = expression(ast->expression); - if (hasError) + if (hasError()) return false; lhs = lhs.storeOnStack(); @@ -3535,7 +3537,7 @@ bool Codegen::visit(SwitchStatement *ast) for (CaseClauses *it = ast->block->clauses; it; it = it->next) { CaseClause *clause = it->clause; Reference rhs = expression(clause->expression); - if (hasError) + if (hasError()) return false; rhs.loadInAccumulator(); bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause)); @@ -3544,7 +3546,7 @@ bool Codegen::visit(SwitchStatement *ast) for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) { CaseClause *clause = it->clause; Reference rhs = expression(clause->expression); - if (hasError) + if (hasError()) return false; rhs.loadInAccumulator(); bytecodeGenerator->jumpStrictEqual(lhs.stackSlot(), blockMap.value(clause)); @@ -3590,14 +3592,14 @@ bool Codegen::visit(SwitchStatement *ast) bool Codegen::visit(ThrowStatement *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); TailCallBlocker blockTailCalls(this); Reference expr = expression(ast->expression); - if (hasError) + if (hasError()) return false; expr.loadInAccumulator(); @@ -3634,7 +3636,7 @@ void Codegen::handleTryFinally(TryStatement *ast) bool Codegen::visit(TryStatement *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); @@ -3650,7 +3652,7 @@ bool Codegen::visit(TryStatement *ast) bool Codegen::visit(VariableStatement *ast) { - if (hasError) + if (hasError()) return false; variableDeclarationList(ast->declarations); @@ -3659,7 +3661,7 @@ bool Codegen::visit(VariableStatement *ast) bool Codegen::visit(WhileStatement *ast) { - if (hasError) + if (hasError()) return false; if (AST::cast<FalseLiteral *>(ast->expression)) @@ -3691,14 +3693,14 @@ bool Codegen::visit(WhileStatement *ast) bool Codegen::visit(WithStatement *ast) { - if (hasError) + if (hasError()) return false; RegisterScope scope(this); TailCallBlocker blockTailCalls(this); Reference src = expression(ast->expression); - if (hasError) + if (hasError()) return false; src = src.storeOnStack(); // trigger load before we setup the exception handler, so exceptions here go to the right place src.loadInAccumulator(); @@ -3768,33 +3770,30 @@ bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(const Reference &r, return isArgOrEval; } -void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail) +void Codegen::throwError(ErrorType errorType, const SourceLocation &loc, const QString &detail) { - if (hasError) + if (hasError()) return; - hasError = true; - QQmlJS::DiagnosticMessage error; - error.message = detail; - error.loc = loc; - _errors << error; + _errorType = errorType; + _error.message = detail; + _error.line = loc.startLine; + _error.column = loc.startColumn; } -void Codegen::throwReferenceError(const SourceLocation &loc, const QString &detail) +void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail) { - if (hasError) - return; + throwError(SyntaxError, loc, detail); +} - hasError = true; - QQmlJS::DiagnosticMessage error; - error.message = detail; - error.loc = loc; - _errors << error; +void Codegen::throwReferenceError(const SourceLocation &loc, const QString &detail) +{ + throwError(ReferenceError, loc, detail); } -QList<QQmlJS::DiagnosticMessage> Codegen::errors() const +QQmlJS::DiagnosticMessage Codegen::error() const { - return _errors; + return _error; } QV4::CompiledData::CompilationUnit Codegen::generateCompilationUnit( @@ -3837,12 +3836,11 @@ CompiledData::CompilationUnit Codegen::compileModule( JSUnitGenerator jsGenerator(&compilerModule); Codegen cg(&jsGenerator, /*strictMode*/true); cg.generateFromModule(url, url, sourceCode, moduleNode, &compilerModule); - auto errors = cg.errors(); - if (diagnostics) - *diagnostics << errors; - - if (!errors.isEmpty()) + if (cg.hasError()) { + if (diagnostics) + *diagnostics << cg.error(); return CompiledData::CompilationUnit(); + } return cg.generateCompilationUnit(); } @@ -3960,28 +3958,9 @@ Codegen::VolatileMemoryLocations Codegen::scanVolatileMemoryLocations(AST::Node return scanner.scan(ast); } - -QList<QQmlError> Codegen::qmlErrors() const +QUrl Codegen::url() const { - QList<QQmlError> qmlErrors; - - // Short circuit to avoid costly (de)heap allocation of QUrl if there are no errors. - if (_errors.size() == 0) - return qmlErrors; - - qmlErrors.reserve(_errors.size()); - - QUrl url(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName)); - for (const QQmlJS::DiagnosticMessage &msg: qAsConst(_errors)) { - QQmlError e; - e.setUrl(url); - e.setLine(msg.loc.startLine); - e.setColumn(msg.loc.startColumn); - e.setDescription(msg.message); - qmlErrors << e; - } - - return qmlErrors; + return QUrl(_fileNameIsUrl ? QUrl(_module->fileName) : QUrl::fromLocalFile(_module->fileName)); } bool Codegen::RValue::operator==(const RValue &other) const diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 6d5f8c0951..51b821aafe 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -54,14 +54,13 @@ #include <private/qqmljsastvisitor_p.h> #include <private/qqmljsengine_p.h> #include <private/qqmljsast_p.h> +#include <private/qqmljsdiagnosticmessage_p.h> #include <private/qv4compiler_p.h> #include <private/qv4compilercontext_p.h> #include <private/qv4util_p.h> #include <private/qv4bytecodegenerator_p.h> #include <private/qv4calldata_p.h> -#include <QtQml/qqmlerror.h> - QT_BEGIN_NAMESPACE using namespace QQmlJS; @@ -199,8 +198,9 @@ public: codegen = cg; } - Reference() : + Reference(const QString &name = QString()) : constant(0), + name(name), isArgOrEval(false), isReadonly(false), isReferenceToConst(false), @@ -418,6 +418,11 @@ protected: bool _trueBlockFollowsCondition = false; public: + explicit Result(const QString &name) + : _result(name) + , _requested(ex) + {} + explicit Result(const Reference &lrvalue) : _result(lrvalue) , _requested(ex) @@ -476,6 +481,10 @@ protected: void setResult(Reference &&result) { _result = std::move(result); } + + void clearResultName() { + _result.name.clear(); + } }; void enterContext(AST::Node *node); @@ -523,19 +532,19 @@ protected: const BytecodeGenerator::Label *iffalse, bool trueBlockFollowsCondition); - inline Reference expression(AST::ExpressionNode *ast) + inline Reference expression(AST::ExpressionNode *ast, const QString &name = QString()) { - if (!ast || hasError) + if (!ast || hasError()) return Reference(); - pushExpr(); + pushExpr(name); ast->accept(this); return popResult(); } inline void accept(AST::Node *node) { - if (!hasError && node) + if (!hasError() && node) node->accept(this); } @@ -662,8 +671,16 @@ protected: } public: - QList<DiagnosticMessage> errors() const; - QList<QQmlError> qmlErrors() const; + enum ErrorType { + NoError, + SyntaxError, + ReferenceError + }; + + ErrorType errorType() const { return _errorType; } + bool hasError() const { return _errorType != NoError; } + DiagnosticMessage error() const; + QUrl url() const; Reference binopHelper(QSOperator::Op oper, Reference &left, Reference &right); Reference jumpBinop(QSOperator::Op oper, Reference &left, Reference &right); @@ -716,6 +733,7 @@ protected: inline void setExprResult(const Reference &result) { m_expressions.back().setResult(result); } inline void setExprResult(Reference &&result) { m_expressions.back().setResult(std::move(result)); } inline Reference exprResult() const { return m_expressions.back().result(); } + inline void clearExprResultName() { m_expressions.back().clearResultName(); } inline bool exprAccept(Format f) { return m_expressions.back().accept(f); } @@ -723,7 +741,7 @@ protected: inline void pushExpr(Result &&expr) { m_expressions.push_back(std::move(expr)); } inline void pushExpr(const Result &expr) { m_expressions.push_back(expr); } - inline void pushExpr() { m_expressions.emplace_back(); } + inline void pushExpr(const QString &name = QString()) { m_expressions.emplace_back(name); } inline Result popExpr() { @@ -760,8 +778,8 @@ protected: ControlFlow *controlFlow = nullptr; bool _fileNameIsUrl; - bool hasError; - QList<QQmlJS::DiagnosticMessage> _errors; + ErrorType _errorType = NoError; + QQmlJS::DiagnosticMessage _error; class TailCallBlocker { @@ -790,6 +808,7 @@ protected: private: VolatileMemoryLocations scanVolatileMemoryLocations(AST::Node *ast); void handleConstruct(const Reference &base, AST::ArgumentList *args); + void throwError(ErrorType errorType, const AST::SourceLocation &loc, const QString &detail); }; } diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp deleted file mode 100644 index 813868b0ae..0000000000 --- a/src/qml/compiler/qv4compileddata.cpp +++ /dev/null @@ -1,283 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qv4compileddata_p.h" -#include <private/qv4staticvalue_p.h> -#include <private/qqmlirbuilder_p.h> -#include <QCoreApplication> -#include <QCryptographicHash> -#include <QSaveFile> -#include <QScopeGuard> -#include <QFileInfo> - -// generated by qmake: -#include "qml_compile_hash_p.h" - -#include <algorithm> - -QT_BEGIN_NAMESPACE - -namespace QV4 { - -namespace CompiledData { - -#if defined(QML_COMPILE_HASH) -# ifdef Q_OS_LINUX -// Place on a separate section on Linux so it's easier to check from outside -// what the hash version is. -__attribute__((section(".qml_compile_hash"))) -# endif -const char qml_compile_hash[48 + 1] = QML_COMPILE_HASH; -static_assert(sizeof(Unit::libraryVersionHash) >= QML_COMPILE_HASH_LENGTH + 1, "Compile hash length exceeds reserved size in data structure. Please adjust and bump the format version"); -#else -# error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files" -#endif - - -CompilationUnit::CompilationUnit(const Unit *unitData, const QString &fileName, const QString &finalUrlString) -{ - setUnitData(unitData, nullptr, fileName, finalUrlString); -} - -CompilationUnit::~CompilationUnit() -{ - if (data) { - if (data->qmlUnit() != qmlData) - free(const_cast<QmlUnit *>(qmlData)); - qmlData = nullptr; - - if (!(data->flags & QV4::CompiledData::Unit::StaticData)) - free(const_cast<Unit *>(data)); - } - data = nullptr; -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - delete [] constants; - constants = nullptr; -#endif - - delete [] imports; - imports = nullptr; -} - -bool CompilationUnit::saveToDisk(const QString &outputFileName, QString *errorString) const -{ - errorString->clear(); - -#if QT_CONFIG(temporaryfile) - // Foo.qml -> Foo.qmlc - QSaveFile cacheFile(outputFileName); - if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - *errorString = cacheFile.errorString(); - return false; - } - - SaveableUnitPointer saveable(this); - qint64 headerWritten = cacheFile.write(saveable.data<char>(), saveable.size()); - if (headerWritten != saveable.size()) { - *errorString = cacheFile.errorString(); - return false; - } - - if (!cacheFile.commit()) { - *errorString = cacheFile.errorString(); - return false; - } - - return true; -#else - Q_UNUSED(outputFileName) - *errorString = QStringLiteral("features.temporaryfile is disabled."); - return false; -#endif // QT_CONFIG(temporaryfile) -} - -void CompilationUnit::setUnitData(const Unit *unitData, const QmlUnit *qmlUnit, - const QString &fileName, const QString &finalUrlString) -{ - data = unitData; - qmlData = nullptr; -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - delete [] constants; -#endif - constants = nullptr; - m_fileName.clear(); - m_finalUrlString.clear(); - if (!data) - return; - - qmlData = qmlUnit ? qmlUnit : data->qmlUnit(); - -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - StaticValue *bigEndianConstants = new StaticValue[data->constantTableSize]; - const quint64_le *littleEndianConstants = data->constants(); - for (uint i = 0; i < data->constantTableSize; ++i) - bigEndianConstants[i] = StaticValue::fromReturnedValue(littleEndianConstants[i]); - constants = bigEndianConstants; -#else - constants = reinterpret_cast<const StaticValue*>(data->constants()); -#endif - - m_fileName = !fileName.isEmpty() ? fileName : stringAt(data->sourceFileIndex); - m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(data->finalUrlIndex); -} - -//reverse of Lexer::singleEscape() -QString Binding::escapedString(const QString &string) -{ - QString tmp = QLatin1String("\""); - for (int i = 0; i < string.length(); ++i) { - const QChar &c = string.at(i); - switch (c.unicode()) { - case 0x08: - tmp += QLatin1String("\\b"); - break; - case 0x09: - tmp += QLatin1String("\\t"); - break; - case 0x0A: - tmp += QLatin1String("\\n"); - break; - case 0x0B: - tmp += QLatin1String("\\v"); - break; - case 0x0C: - tmp += QLatin1String("\\f"); - break; - case 0x0D: - tmp += QLatin1String("\\r"); - break; - case 0x22: - tmp += QLatin1String("\\\""); - break; - case 0x27: - tmp += QLatin1String("\\\'"); - break; - case 0x5C: - tmp += QLatin1String("\\\\"); - break; - default: - tmp += c; - break; - } - } - tmp += QLatin1Char('\"'); - return tmp; -} - -void CompilationUnit::unlink() -{ - free(runtimeStrings); - runtimeStrings = nullptr; - delete [] runtimeRegularExpressions; - runtimeRegularExpressions = nullptr; - free(runtimeClasses); - runtimeClasses = nullptr; -} - -void Unit::generateChecksum() -{ -#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 - QCryptographicHash hash(QCryptographicHash::Md5); - - const int checksummableDataOffset = offsetof(QV4::CompiledData::Unit, md5Checksum) + sizeof(md5Checksum); - - const char *dataPtr = reinterpret_cast<const char *>(this) + checksummableDataOffset; - hash.addData(dataPtr, unitSize - checksummableDataOffset); - - QByteArray checksum = hash.result(); - Q_ASSERT(checksum.size() == sizeof(md5Checksum)); - memcpy(md5Checksum, checksum.constData(), sizeof(md5Checksum)); -#else - memset(md5Checksum, 0, sizeof(md5Checksum)); -#endif -} - -bool Unit::verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const -{ - if (strncmp(magic, CompiledData::magic_str, sizeof(magic))) { - *errorString = QStringLiteral("Magic bytes in the header do not match"); - return false; - } - - if (version != quint32(QV4_DATA_STRUCTURE_VERSION)) { - *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2").arg(version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16); - return false; - } - - if (qtVersion != quint32(QT_VERSION)) { - *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2").arg(qtVersion, 0, 16).arg(QT_VERSION, 0, 16); - return false; - } - - if (sourceTimeStamp) { - // Files from the resource system do not have any time stamps, so fall back to the application - // executable. - if (!expectedSourceTimeStamp.isValid()) - expectedSourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified(); - - if (expectedSourceTimeStamp.isValid() && expectedSourceTimeStamp.toMSecsSinceEpoch() != sourceTimeStamp) { - *errorString = QStringLiteral("QML source file has a different time stamp than cached file."); - return false; - } - } - -#if defined(QML_COMPILE_HASH) - if (qstrcmp(CompiledData::qml_compile_hash, libraryVersionHash) != 0) { - *errorString = QStringLiteral("QML library version mismatch. Expected compile hash does not match"); - return false; - } -#else -#error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files" -#endif - - return true; -} - -Location &Location::operator=(const QQmlJS::AST::SourceLocation &astLocation) -{ - line = astLocation.startLine; - column = astLocation.startColumn; - return *this; -} - -} - -} - -QT_END_NAMESPACE diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 63738d6002..f3d5de3db1 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -51,19 +51,17 @@ // #include <QtCore/qstring.h> -#include <QtCore/qcryptographichash.h> -#include <QVector> -#include <QStringList> -#include <QHash> -#include <QUrl> - -#include <private/qv4executableallocator_p.h> -#include <private/qqmlrefcount_p.h> -#include <private/qqmlnullablevalue_p.h> -#include <private/qv4identifier_p.h> -#include <private/qflagpointer_p.h> +#include <QtCore/qscopeguard.h> +#include <QtCore/qvector.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qhash.h> + +#if QT_CONFIG(temporaryfile) +#include <QtCore/qsavefile.h> +#endif + #include <private/qendian_p.h> -#include <private/qqmljsastfwd_p.h> +#include <private/qv4staticvalue_p.h> QT_BEGIN_NAMESPACE @@ -88,10 +86,10 @@ struct Document; } namespace QV4 { -struct StaticValue; - namespace Heap { struct Module; +struct String; +struct InternalClass; }; struct Function; @@ -128,8 +126,6 @@ struct Location Location() : _dummy(0) { } - Location &operator=(const QQmlJS::AST::SourceLocation &astLocation); - inline bool operator<(const Location &other) const { return line < other.line || (line == other.line && column < other.column); @@ -411,7 +407,7 @@ static_assert(sizeof(ImportEntry) == 16, "ImportEntry structure needs to have th // Qml data structures -struct Q_QML_EXPORT TranslationData +struct TranslationData { quint32_le stringIndex; quint32_le commentIndex; @@ -420,7 +416,7 @@ struct Q_QML_EXPORT TranslationData }; static_assert(sizeof(TranslationData) == 16, "TranslationData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); -struct Q_QML_PRIVATE_EXPORT Binding +struct Binding { quint32_le propertyNameIndex; @@ -517,7 +513,48 @@ struct Q_QML_PRIVATE_EXPORT Binding bool isFunctionExpression() const { return (flags & IsFunctionExpression); } - static QString escapedString(const QString &string); + //reverse of Lexer::singleEscape() + static QString escapedString(const QString &string) + { + QString tmp = QLatin1String("\""); + for (int i = 0; i < string.length(); ++i) { + const QChar &c = string.at(i); + switch (c.unicode()) { + case 0x08: + tmp += QLatin1String("\\b"); + break; + case 0x09: + tmp += QLatin1String("\\t"); + break; + case 0x0A: + tmp += QLatin1String("\\n"); + break; + case 0x0B: + tmp += QLatin1String("\\v"); + break; + case 0x0C: + tmp += QLatin1String("\\f"); + break; + case 0x0D: + tmp += QLatin1String("\\r"); + break; + case 0x22: + tmp += QLatin1String("\\\""); + break; + case 0x27: + tmp += QLatin1String("\\\'"); + break; + case 0x5C: + tmp += QLatin1String("\\\\"); + break; + default: + tmp += c; + break; + } + } + tmp += QLatin1Char('\"'); + return tmp; + } bool isTranslationBinding() const { return type == Type_Translation || type == Type_TranslationById; } bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); } @@ -565,14 +602,22 @@ struct Enum }; static_assert(sizeof(Enum) == 12, "Enum structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); +enum class BuiltinType : unsigned int { + Var = 0, Variant, Int, Bool, Real, String, Url, Color, + Font, Time, Date, DateTime, Rect, Point, Size, + Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, InvalidBuiltin +}; + struct Parameter { quint32_le nameIndex; - quint32_le type; - quint32_le customTypeNameIndex; - Location location; + union { + quint32 _dummy; + quint32_le_bitfield<0, 1> indexIsBuiltinType; + quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType; + }; }; -static_assert(sizeof(Parameter) == 16, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); +static_assert(sizeof(Parameter) == 8, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); struct Signal { @@ -601,24 +646,33 @@ static_assert(sizeof(Signal) == 12, "Signal structure needs to have the expected struct Property { - enum Type : unsigned int { Var = 0, Variant, Int, Bool, Real, String, Url, Color, - Font, Time, Date, DateTime, Rect, Point, Size, - Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, - Custom, CustomList }; - - enum Flags : unsigned int { - IsReadOnly = 0x1 - }; - quint32_le nameIndex; union { - quint32_le_bitfield<0, 31> type; - quint32_le_bitfield<31, 1> flags; // readonly + quint32_le_bitfield<0, 29> builtinTypeOrTypeNameIndex; + quint32_le_bitfield<29, 1> isBuiltinType; + quint32_le_bitfield<30, 1> isList; + quint32_le_bitfield<31, 1> isReadOnly; }; - quint32_le customTypeNameIndex; // If type >= Custom + Location location; + + void setBuiltinType(BuiltinType t) + { + builtinTypeOrTypeNameIndex = static_cast<quint32>(t); + isBuiltinType = true; + } + BuiltinType builtinType() const { + if (isBuiltinType) + return static_cast<BuiltinType>(quint32(builtinTypeOrTypeNameIndex)); + return BuiltinType::InvalidBuiltin; + } + void setCustomType(int nameIndex) + { + builtinTypeOrTypeNameIndex = nameIndex; + isBuiltinType = false; + } }; -static_assert(sizeof(Property) == 16, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); +static_assert(sizeof(Property) == 12, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); struct Alias { enum Flags : unsigned int { @@ -815,7 +869,6 @@ static_assert(sizeof(QmlUnit) == 16, "QmlUnit structure needs to have the expect enum { QmlCompileHashSpace = 48 }; static const char magic_str[] = "qv4cdata"; -extern const char qml_compile_hash[QmlCompileHashSpace + 1]; struct Unit { @@ -830,8 +883,6 @@ struct Unit char libraryVersionHash[QmlCompileHashSpace]; char md5Checksum[16]; // checksum of all bytes following this field. - void generateChecksum(); - char dependencyMD5Checksum[16]; enum : unsigned int { @@ -879,8 +930,6 @@ struct Unit quint32_le offsetToQmlUnit; - bool verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const; - /* QML specific fields */ const QmlUnit *qmlUnit() const { @@ -1014,8 +1063,8 @@ struct TypeReferenceMap : QHash<int, TypeReference> auto prop = obj->propertiesBegin(); auto propEnd = obj->propertiesEnd(); for ( ; prop != propEnd; ++prop) { - if (prop->type >= QV4::CompiledData::Property::Custom) { - TypeReference &r = this->add(prop->customTypeNameIndex, prop->location); + if (!prop->isBuiltinType) { + TypeReference &r = this->add(prop->builtinTypeOrTypeNameIndex, prop->location); r.errorWhenNotFound = true; } } @@ -1043,7 +1092,7 @@ typedef QVector<QQmlPropertyData*> BindingPropertyData; // This is how this hooks into the existing structures: -struct Q_QML_PRIVATE_EXPORT CompilationUnitBase +struct CompilationUnitBase { Q_DISABLE_COPY(CompilationUnitBase) @@ -1080,11 +1129,11 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnitBase Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value); Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeStrings) == 0); Q_STATIC_ASSERT(offsetof(CompilationUnitBase, constants) == sizeof(QV4::Heap::String **)); -Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offsetof(CompilationUnitBase, constants) + sizeof(const Value *)); -Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const Value *)); -Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const Value *)); +Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offsetof(CompilationUnitBase, constants) + sizeof(const StaticValue *)); +Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const StaticValue *)); +Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const StaticValue *)); -struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase +struct CompilationUnit : public CompilationUnitBase { Q_DISABLE_COPY(CompilationUnit) @@ -1094,8 +1143,31 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase public: using CompiledObject = CompiledData::Object; - CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(), const QString &finalUrlString = QString()); - ~CompilationUnit(); + CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(), + const QString &finalUrlString = QString()) + { + setUnitData(unitData, nullptr, fileName, finalUrlString); + } + + ~CompilationUnit() + { + if (data) { + if (data->qmlUnit() != qmlData) + free(const_cast<QmlUnit *>(qmlData)); + qmlData = nullptr; + + if (!(data->flags & QV4::CompiledData::Unit::StaticData)) + free(const_cast<Unit *>(data)); + } + data = nullptr; +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + delete [] constants; + constants = nullptr; +#endif + + delete [] imports; + imports = nullptr; + } CompilationUnit(CompilationUnit &&other) noexcept { @@ -1123,8 +1195,36 @@ public: } const Unit *unitData() const { return data; } + void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr, - const QString &fileName = QString(), const QString &finalUrlString = QString()); + const QString &fileName = QString(), const QString &finalUrlString = QString()) + { + data = unitData; + qmlData = nullptr; +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + delete [] constants; +#endif + constants = nullptr; + m_fileName.clear(); + m_finalUrlString.clear(); + if (!data) + return; + + qmlData = qmlUnit ? qmlUnit : data->qmlUnit(); + +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + StaticValue *bigEndianConstants = new StaticValue[data->constantTableSize]; + const quint64_le *littleEndianConstants = data->constants(); + for (uint i = 0; i < data->constantTableSize; ++i) + bigEndianConstants[i] = StaticValue::fromReturnedValue(littleEndianConstants[i]); + constants = bigEndianConstants; +#else + constants = reinterpret_cast<const StaticValue*>(data->constants()); +#endif + + m_fileName = !fileName.isEmpty() ? fileName : stringAt(data->sourceFileIndex); + m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(data->finalUrlIndex); + } QString stringAt(int index) const { @@ -1139,58 +1239,76 @@ public: Heap::Module *module() const { return m_module; } void setModule(Heap::Module *module) { m_module = module; } - void unlink(); - private: QString m_fileName; // initialized from data->sourceFileIndex QString m_finalUrlString; // initialized from data->finalUrlIndex Heap::Module *m_module = nullptr; - -public: - bool saveToDisk(const QString &outputFileName, QString *errorString) const; }; class SaveableUnitPointer { Q_DISABLE_COPY_MOVE(SaveableUnitPointer) public: - SaveableUnitPointer(const CompilationUnit *unit, quint32 temporaryFlags = Unit::StaticData) : - unit(unit) + SaveableUnitPointer(const Unit *unit, quint32 temporaryFlags = Unit::StaticData) : + unit(unit), + temporaryFlags(temporaryFlags) { - quint32_le &unitFlags = mutableFlags(); - quint32 origFlags = unitFlags; - unitFlags |= temporaryFlags; - changedFlags = origFlags ^ unitFlags; } - ~SaveableUnitPointer() + ~SaveableUnitPointer() = default; + + template<typename Char> + bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const { - mutableFlags() ^= changedFlags; + auto cleanup = qScopeGuard([this]() { mutableFlags() ^= temporaryFlags; }); + mutableFlags() |= temporaryFlags; + return writer(data<Char>(), size()); } - const CompilationUnit *operator->() const { return unit; } - const CompilationUnit &operator*() const { return *unit; } - operator const CompilationUnit *() { return unit; } + static bool writeDataToFile(const QString &outputFileName, const char *data, quint32 size, + QString *errorString) + { +#if QT_CONFIG(temporaryfile) + QSaveFile cacheFile(outputFileName); + if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate) + || cacheFile.write(data, size) != size + || !cacheFile.commit()) { + *errorString = cacheFile.errorString(); + return false; + } + + errorString->clear(); + return true; +#else + Q_UNUSED(outputFileName) + *errorString = QStringLiteral("features.temporaryfile is disabled."); + return false; +#endif + } + +private: + const Unit *unit; + quint32 temporaryFlags; + + quint32_le &mutableFlags() const + { + return const_cast<Unit *>(unit)->flags; + } template<typename Char> const Char *data() const { Q_STATIC_ASSERT(sizeof(Char) == 1); const Char *dataPtr; - memcpy(&dataPtr, &unit->data, sizeof(dataPtr)); + memcpy(&dataPtr, &unit, sizeof(dataPtr)); return dataPtr; } quint32 size() const { - return unit->data->unitSize; + return unit->unitSize; } - -private: - quint32_le &mutableFlags() { return const_cast<Unit *>(unit->unitData())->flags; }; - const CompilationUnit *unit; - quint32 changedFlags; }; diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index d8f293211e..b378c294b7 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -44,6 +44,7 @@ #include <private/qv4alloca_p.h> #include <private/qqmljslexer_p.h> #include <private/qqmljsast_p.h> +#include <private/qml_compile_hash_p.h> #include <QCryptographicHash> // Efficient implementation that takes advantage of powers of two. @@ -125,6 +126,25 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit) } } +void QV4::Compiler::JSUnitGenerator::generateUnitChecksum(QV4::CompiledData::Unit *unit) +{ +#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 + QCryptographicHash hash(QCryptographicHash::Md5); + + const int checksummableDataOffset + = offsetof(QV4::CompiledData::Unit, md5Checksum) + sizeof(unit->md5Checksum); + + const char *dataPtr = reinterpret_cast<const char *>(unit) + checksummableDataOffset; + hash.addData(dataPtr, unit->unitSize - checksummableDataOffset); + + QByteArray checksum = hash.result(); + Q_ASSERT(checksum.size() == sizeof(unit->md5Checksum)); + memcpy(unit->md5Checksum, checksum.constData(), sizeof(unit->md5Checksum)); +#else + memset(unit->md5Checksum, 0, sizeof(unit->md5Checksum)); +#endif +} + QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::Compiler::Module *module) : module(module) { @@ -391,7 +411,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO if (option == GenerateWithStringTable) stringTable.serialize(unit); - unit->generateChecksum(); + generateUnitChecksum(unit); return unit; } @@ -580,7 +600,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp unit.flags |= module->unitFlags; unit.version = QV4_DATA_STRUCTURE_VERSION; unit.qtVersion = QT_VERSION; - qstrcpy(unit.libraryVersionHash, CompiledData::qml_compile_hash); + qstrcpy(unit.libraryVersionHash, QML_COMPILE_HASH); memset(unit.md5Checksum, 0, sizeof(unit.md5Checksum)); memset(unit.dependencyMD5Checksum, 0, sizeof(unit.dependencyMD5Checksum)); diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h index 49e334bb81..f5884f6478 100644 --- a/src/qml/compiler/qv4compiler_p.h +++ b/src/qml/compiler/qv4compiler_p.h @@ -103,6 +103,8 @@ private: }; struct Q_QML_PRIVATE_EXPORT JSUnitGenerator { + static void generateUnitChecksum(CompiledData::Unit *unit); + struct MemberInfo { QString name; bool isAccessor; diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp index ef67a11a70..416a0edee0 100644 --- a/src/qml/compiler/qv4compilerscanfunctions.cpp +++ b/src/qml/compiler/qv4compilerscanfunctions.cpp @@ -44,7 +44,6 @@ #include <QtCore/QSet> #include <QtCore/QBuffer> #include <QtCore/QBitArray> -#include <QtCore/QLinkedList> #include <QtCore/QStack> #include <private/qqmljsast_p.h> #include <private/qv4compilercontext_p.h> @@ -55,6 +54,15 @@ using namespace QV4; using namespace QV4::Compiler; using namespace QQmlJS::AST; +static CompiledData::Location location(const QQmlJS::AST::SourceLocation &astLocation) +{ + CompiledData::Location target; + target.line = astLocation.startLine; + target.column = astLocation.startColumn; + return target; +} + + ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, ContextType defaultProgramType) : QQmlJS::AST::Visitor(cg->recursionDepth()) , _cg(cg) @@ -176,7 +184,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration) Compiler::ExportEntry entry; entry.moduleRequest = declaration->fromClause->moduleSpecifier.toString(); entry.importName = QStringLiteral("*"); - entry.location = declaration->firstSourceLocation(); + entry.location = location(declaration->firstSourceLocation()); _context->exportEntries << entry; } else if (declaration->exportClause) { for (ExportsList *it = declaration->exportClause->exportsList; it; it = it->next) { @@ -189,7 +197,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration) entry.moduleRequest = module; entry.exportName = spec->exportedIdentifier.toString(); - entry.location = it->firstSourceLocation(); + entry.location = location(it->firstSourceLocation()); _context->exportEntries << entry; } @@ -204,7 +212,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration) Compiler::ExportEntry entry; entry.localName = name; entry.exportName = name; - entry.location = vstmt->firstSourceLocation(); + entry.location = location(vstmt->firstSourceLocation()); _context->exportEntries << entry; } } else if (auto *classDecl = AST::cast<AST::ClassDeclaration*>(declaration->variableStatementOrDeclaration)) { @@ -213,7 +221,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration) Compiler::ExportEntry entry; entry.localName = name; entry.exportName = name; - entry.location = classDecl->firstSourceLocation(); + entry.location = location(classDecl->firstSourceLocation()); _context->exportEntries << entry; if (declaration->exportDefault) localNameForDefaultExport = entry.localName; @@ -232,7 +240,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration) Compiler::ExportEntry entry; entry.localName = functionName; entry.exportName = functionName; - entry.location = fdef->firstSourceLocation(); + entry.location = location(fdef->firstSourceLocation()); _context->exportEntries << entry; if (declaration->exportDefault) localNameForDefaultExport = entry.localName; @@ -244,7 +252,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration) entry.localName = localNameForDefaultExport; _context->localNameForDefaultExport = localNameForDefaultExport; entry.exportName = QStringLiteral("default"); - entry.location = declaration->firstSourceLocation(); + entry.location = location(declaration->firstSourceLocation()); _context->exportEntries << entry; } @@ -269,7 +277,7 @@ bool ScanFunctions::visit(ImportDeclaration *declaration) entry.moduleRequest = module; entry.importName = QStringLiteral("default"); entry.localName = import->importedDefaultBinding.toString(); - entry.location = declaration->firstSourceLocation(); + entry.location = location(declaration->firstSourceLocation()); _context->importEntries << entry; } @@ -278,7 +286,7 @@ bool ScanFunctions::visit(ImportDeclaration *declaration) entry.moduleRequest = module; entry.importName = QStringLiteral("*"); entry.localName = import->nameSpaceImport->importedBinding.toString(); - entry.location = declaration->firstSourceLocation(); + entry.location = location(declaration->firstSourceLocation()); _context->importEntries << entry; } @@ -291,7 +299,7 @@ bool ScanFunctions::visit(ImportDeclaration *declaration) entry.importName = it->importSpecifier->identifier.toString(); else entry.importName = entry.localName; - entry.location = declaration->firstSourceLocation(); + entry.location = location(declaration->firstSourceLocation()); _context->importEntries << entry; } } diff --git a/src/qml/debugger/debugger.pri b/src/qml/debugger/debugger.pri index 202a46e550..1281886816 100644 --- a/src/qml/debugger/debugger.pri +++ b/src/qml/debugger/debugger.pri @@ -14,7 +14,6 @@ qtConfig(qml-debug) { $$PWD/qqmldebugconnector.cpp \ $$PWD/qqmldebugservice.cpp \ $$PWD/qqmlabstractprofileradapter.cpp \ - $$PWD/qqmlmemoryprofiler.cpp \ $$PWD/qqmlprofiler.cpp \ $$PWD/qqmldebugserviceinterfaces.cpp } @@ -24,7 +23,6 @@ HEADERS += \ $$PWD/qqmldebugserviceinterfaces_p.h \ $$PWD/qqmldebugstatesdelegate_p.h \ $$PWD/qqmldebug.h \ - $$PWD/qqmlmemoryprofiler_p.h \ $$PWD/qqmlprofiler_p.h INCLUDEPATH += $$PWD diff --git a/src/qml/debugger/qqmlmemoryprofiler.cpp b/src/qml/debugger/qqmlmemoryprofiler.cpp deleted file mode 100644 index b89dbfd02d..0000000000 --- a/src/qml/debugger/qqmlmemoryprofiler.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlmemoryprofiler_p.h" - -QT_BEGIN_NAMESPACE - - -QQmlMemoryScope::LibraryState QQmlMemoryScope::state = QQmlMemoryScope::Unloaded; - -typedef void (qmlmemprofile_stats)(int *allocCount, int *bytesAllocated); -typedef void (qmlmemprofile_clear)(); -typedef void (qmlmemprofile_enable)(); -typedef void (qmlmemprofile_disable)(); -typedef void (qmlmemprofile_push_location)(const char *filename, int lineNumber); -typedef void (qmlmemprofile_pop_location)(); -typedef void (qmlmemprofile_save)(const char *filename); -typedef int (qmlmemprofile_is_enabled)(); - -static qmlmemprofile_stats *memprofile_stats; -static qmlmemprofile_clear *memprofile_clear; -static qmlmemprofile_enable *memprofile_enable; -static qmlmemprofile_disable *memprofile_disable; -static qmlmemprofile_push_location *memprofile_push_location; -static qmlmemprofile_pop_location *memprofile_pop_location; -static qmlmemprofile_save *memprofile_save; -static qmlmemprofile_is_enabled *memprofile_is_enabled; - -#if QT_CONFIG(library) -extern QFunctionPointer qt_linux_find_symbol_sys(const char *symbol); -#endif - -bool QQmlMemoryScope::doOpenLibrary() -{ -#if defined(Q_OS_LINUX) && QT_CONFIG(library) - if (state == Unloaded) { - memprofile_stats = (qmlmemprofile_stats *) qt_linux_find_symbol_sys("qmlmemprofile_stats"); - memprofile_clear = (qmlmemprofile_clear *) qt_linux_find_symbol_sys("qmlmemprofile_clear"); - memprofile_enable = (qmlmemprofile_enable *) qt_linux_find_symbol_sys("qmlmemprofile_enable"); - memprofile_disable = (qmlmemprofile_disable *) qt_linux_find_symbol_sys("qmlmemprofile_disable"); - memprofile_push_location = (qmlmemprofile_push_location *) qt_linux_find_symbol_sys("qmlmemprofile_push_location"); - memprofile_pop_location = (qmlmemprofile_pop_location *) qt_linux_find_symbol_sys("qmlmemprofile_pop_location"); - memprofile_save = (qmlmemprofile_save *) qt_linux_find_symbol_sys("qmlmemprofile_save"); - memprofile_is_enabled = (qmlmemprofile_is_enabled *) qt_linux_find_symbol_sys("qmlmemprofile_is_enabled"); - - if (memprofile_stats && memprofile_clear && memprofile_enable && memprofile_disable && - memprofile_push_location && memprofile_pop_location && memprofile_save && memprofile_is_enabled) - state = Loaded; - else - state = Failed; - } -#endif // Q_OS_LINUX - - return state == Loaded; -} - -void QQmlMemoryScope::init(const char *string) -{ - if (memprofile_is_enabled()) { - memprofile_push_location(string, 0); - pushed = true; - } -} - -void QQmlMemoryScope::done() -{ - memprofile_pop_location(); -} - -bool QQmlMemoryProfiler::isEnabled() -{ - if (QQmlMemoryScope::openLibrary()) - return memprofile_is_enabled(); - - return false; -} - -void QQmlMemoryProfiler::enable() -{ - if (QQmlMemoryScope::openLibrary()) - memprofile_enable(); -} - -void QQmlMemoryProfiler::disable() -{ - if (QQmlMemoryScope::openLibrary()) - memprofile_disable(); -} - -void QQmlMemoryProfiler::clear() -{ - if (QQmlMemoryScope::openLibrary()) - memprofile_clear(); -} - -void QQmlMemoryProfiler::stats(int *allocCount, int *bytesAllocated) -{ - if (QQmlMemoryScope::openLibrary()) - memprofile_stats(allocCount, bytesAllocated); -} - -void QQmlMemoryProfiler::save(const char *filename) -{ - if (QQmlMemoryScope::openLibrary()) - memprofile_save(filename); -} - -QT_END_NAMESPACE diff --git a/src/qml/doc/snippets/qml/componentCreation.js b/src/qml/doc/snippets/qml/componentCreation.js index 7364139d3d..ea45f18c37 100644 --- a/src/qml/doc/snippets/qml/componentCreation.js +++ b/src/qml/doc/snippets/qml/componentCreation.js @@ -17,7 +17,7 @@ function createSpriteObjects() { //![local] component = Qt.createComponent("Sprite.qml"); - sprite = component.createObject(appWindow, {"x": 100, "y": 100}); + sprite = component.createObject(appWindow, {x: 100, y: 100}); if (sprite == null) { // Error Handling @@ -32,7 +32,7 @@ function createSpriteObjects() { //![finishCreation] function finishCreation() { if (component.status == Component.Ready) { - sprite = component.createObject(appWindow, {"x": 100, "y": 100}); + sprite = component.createObject(appWindow, {x: 100, y: 100}); if (sprite == null) { // Error Handling console.log("Error creating object"); diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc index 969dd51433..ab54b5fd1d 100644 --- a/src/qml/doc/src/qmlfunctions.qdoc +++ b/src/qml/doc/src/qmlfunctions.qdoc @@ -538,7 +538,7 @@ Alternatively, you can use a C++11 lambda: \code - qmlRegisterSingletonType<SingletonTypeExample>("Qt.example.qjsvalueApi", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { + qmlRegisterSingletonType<SingletonTypeExample>("Qt.example.qobjectSingleton", 1, 0, "MyApi", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { Q_UNUSED(engine) Q_UNUSED(scriptEngine) @@ -564,6 +564,14 @@ \sa {Choosing the Correct Integration Method Between C++ and QML} */ + +/*! + \fn int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, std::function<QObject*(QQmlEngine *, QJSEngine *)> callback) + \relates QQmlEngine + + \overload qmlRegisterSingletonType +*/ + /*! \fn int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName) \relates QQmlEngine diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc index 15e8e4c52c..c4ecaf367c 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc @@ -548,7 +548,7 @@ Therefore, if you create an alias to an object referenced via id with extra properties declared inline, the extra properties won't be accessible through the alias: -\code +\qml // MyItem.qml Item { property alias inner: innerItem @@ -558,23 +558,23 @@ Item { property int extraProperty } } -\code +\endqml You cannot initialize \a inner.extraProperty from outside of this component, as inner is only an \a Item: -\code +\qml // main.qml MyItem { inner.extraProperty: 5 // fails } -\code +\endqml However, if you extract the inner object into a separate component with a dedicated .qml file, you can instantiate that component instead and have all its properties available through the alias: -\code +\qml // MainItem.qml Item { // Now you can access inner.extraProperty, as inner is now an ExtraItem @@ -589,8 +589,7 @@ Item { Item { property int extraProperty } -\code - +\endqml \section3 Default Properties diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp index 9dd2cdc43b..906cc30e67 100644 --- a/src/qml/jit/qv4baselinejit.cpp +++ b/src/qml/jit/qv4baselinejit.cpp @@ -897,7 +897,6 @@ void BaselineJIT::generate_ThrowOnNullOrUndefined() void BaselineJIT::generate_GetTemplateObject(int index) { - STORE_ACC(); as->prepareCallWithArgCount(2); as->passInt32AsArg(index, 1); as->passFunctionAsArg(0); diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index 7bf2a4d004..1bfd72227f 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -490,7 +490,7 @@ void QJSEngine::setInterrupted(bool interrupted) */ bool QJSEngine::isInterrupted() const { - return m_v4Engine->isInterrupted; + return m_v4Engine->isInterrupted.loadAcquire(); } static QUrl urlForFileName(const QString &fileName) @@ -550,7 +550,7 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in result = script.run(); if (scope.engine->hasException) result = v4->catchException(); - if (v4->isInterrupted) + if (v4->isInterrupted.loadAcquire()) result = v4->newErrorObject(QStringLiteral("Interrupted")); QJSValue retval(v4, result->asReturnedValue()); @@ -590,7 +590,7 @@ QJSValue QJSEngine::importModule(const QString &fileName) if (m_v4Engine->hasException) return QJSValue(m_v4Engine, m_v4Engine->catchException()); moduleUnit->evaluate(); - if (!m_v4Engine->isInterrupted) + if (!m_v4Engine->isInterrupted.loadAcquire()) return QJSValue(m_v4Engine, moduleNamespace->asReturnedValue()); return QJSValue( diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index 92eaf1d8ee..c2957dd294 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -769,7 +769,7 @@ QJSValue QJSValue::call(const QJSValueList &args) ScopedValue result(scope, f->call(jsCallData)); if (engine->hasException) result = engine->catchException(); - if (engine->isInterrupted) + if (engine->isInterrupted.loadAcquire()) result = engine->newErrorObject(QStringLiteral("Interrupted")); return QJSValue(engine, result->asReturnedValue()); @@ -827,7 +827,7 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList ScopedValue result(scope, f->call(jsCallData)); if (engine->hasException) result = engine->catchException(); - if (engine->isInterrupted) + if (engine->isInterrupted.loadAcquire()) result = engine->newErrorObject(QStringLiteral("Interrupted")); return QJSValue(engine, result->asReturnedValue()); @@ -877,7 +877,7 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args) ScopedValue result(scope, f->callAsConstructor(jsCallData)); if (engine->hasException) result = engine->catchException(); - if (engine->isInterrupted) + if (engine->isInterrupted.loadAcquire()) result = engine->newErrorObject(QStringLiteral("Interrupted")); return QJSValue(engine, result->asReturnedValue()); diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h index bcf0a9d12d..2faffffbae 100644 --- a/src/qml/jsapi/qjsvalue_p.h +++ b/src/qml/jsapi/qjsvalue_p.h @@ -60,6 +60,8 @@ #include <private/qv4mm_p.h> #include <private/qv4persistent_p.h> +#include <QtCore/qthread.h> + QT_BEGIN_NAMESPACE class Q_AUTOTEST_EXPORT QJSValuePrivate @@ -79,6 +81,11 @@ public: return nullptr; } + static inline void setRawValue(QJSValue *jsval, QV4::Value *v) + { + jsval->d = reinterpret_cast<quintptr>(v); + } + static inline void setVariant(QJSValue *jsval, const QVariant &v) { QVariant *val = new QVariant(v); jsval->d = reinterpret_cast<quintptr>(val) | 1; @@ -169,10 +176,20 @@ public: } static inline void free(QJSValue *jsval) { - if (QV4::Value *v = QJSValuePrivate::getValue(jsval)) + if (QV4::Value *v = QJSValuePrivate::getValue(jsval)) { + if (QV4::ExecutionEngine *e = engine(jsval)) { + if (QJSEngine *jsEngine = e->jsEngine()) { + if (jsEngine->thread() != QThread::currentThread()) { + QMetaObject::invokeMethod( + jsEngine, [v](){ QV4::PersistentValueStorage::free(v); }); + return; + } + } + } QV4::PersistentValueStorage::free(v); - else if (QVariant *v = QJSValuePrivate::getVariant(jsval)) + } else if (QVariant *v = QJSValuePrivate::getVariant(jsval)) { delete v; + } } }; diff --git a/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp b/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp index 6768bc9596..a9ab2f5ccb 100644 --- a/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp +++ b/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp @@ -45,7 +45,7 @@ #include <QScopeGuard> #include <QDateTime> -#include "qv4compileddata_p.h" +#include "qv4executablecompilationunit_p.h" QT_BEGIN_NAMESPACE @@ -73,7 +73,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co return nullptr; } - if (!header.verifyHeader(sourceTimeStamp, errorString)) + if (!ExecutableCompilationUnit::verifyHeader(&header, sourceTimeStamp, errorString)) return nullptr; // Data structure and qt version matched, so now we can access the rest of the file safely. diff --git a/src/qml/jsruntime/qv4compilationunitmapper_win.cpp b/src/qml/jsruntime/qv4compilationunitmapper_win.cpp index 779c1288fe..9e8babc5e6 100644 --- a/src/qml/jsruntime/qv4compilationunitmapper_win.cpp +++ b/src/qml/jsruntime/qv4compilationunitmapper_win.cpp @@ -39,7 +39,7 @@ #include "qv4compilationunitmapper_p.h" -#include "qv4compileddata_p.h" +#include "qv4executablecompilationunit_p.h" #include <QScopeGuard> #include <QFileInfo> #include <QDateTime> @@ -87,7 +87,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co return nullptr; } - if (!header.verifyHeader(sourceTimeStamp, errorString)) + if (!ExecutableCompilationUnit::verifyHeader(&header, sourceTimeStamp, errorString)) return nullptr; // Data structure and qt version matched, so now we can access the rest of the file safely. diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index cd77ebd22a..0d3ae71b05 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -42,6 +42,7 @@ #include <private/qv4compiler_p.h> #include <private/qv4compilercontext_p.h> #include <private/qv4codegen_p.h> +#include <private/qqmljsdiagnosticmessage_p.h> #include <QtCore/QTextStream> #include <QDateTime> @@ -109,7 +110,6 @@ #include <private/qqmllistwrapper_p.h> #include <private/qqmllist_p.h> #include <private/qqmltypeloader_p.h> -#include <private/qqmlmemoryprofiler_p.h> #include <private/qqmlbuiltinfunctions_p.h> #if QT_CONFIG(qml_locale) #include <private/qqmllocale_p.h> @@ -206,10 +206,19 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) #endif , m_qmlEngine(nullptr) { + bool ok = false; + const int envMaxJSStackSize = qEnvironmentVariableIntValue("QV4_JS_MAX_STACK_SIZE", &ok); + if (ok && envMaxJSStackSize > 0) + m_maxJSStackSize = envMaxJSStackSize; + + const int envMaxGCStackSize = qEnvironmentVariableIntValue("QV4_GC_MAX_STACK_SIZE", &ok); + if (ok && envMaxGCStackSize > 0) + m_maxGCStackSize = envMaxGCStackSize; + memoryManager = new QV4::MemoryManager(this); if (maxCallDepth == -1) { - bool ok = false; + ok = false; maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok); if (!ok || maxCallDepth <= 0) { #if defined(QT_NO_DEBUG) && !defined(__SANITIZE_ADDRESS__) && !QT_HAS_FEATURE(address_sanitizer) @@ -223,24 +232,24 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) Q_ASSERT(maxCallDepth > 0); // reserve space for the JS stack - // we allow it to grow to a bit more than JSStackLimit, as we can overshoot due to ScopedValues + // we allow it to grow to a bit more than m_maxJSStackSize, as we can overshoot due to ScopedValues // allocated outside of JIT'ed methods. - *jsStack = WTF::PageAllocation::allocate(JSStackLimit + 256*1024, WTF::OSAllocator::JSVMStackPages, + *jsStack = WTF::PageAllocation::allocate(m_maxJSStackSize + 256*1024, WTF::OSAllocator::JSVMStackPages, /* writable */ true, /* executable */ false, /* includesGuardPages */ true); jsStackBase = (Value *)jsStack->base(); #ifdef V4_USE_VALGRIND - VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, JSStackLimit + 256*1024); + VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, m_maxJSStackSize + 256*1024); #endif jsStackTop = jsStackBase; - *gcStack = WTF::PageAllocation::allocate(GCStackLimit, WTF::OSAllocator::JSVMStackPages, + *gcStack = WTF::PageAllocation::allocate(m_maxGCStackSize, WTF::OSAllocator::JSVMStackPages, /* writable */ true, /* executable */ false, /* includesGuardPages */ true); { - bool ok = false; + ok = false; jitCallCountThreshold = qEnvironmentVariableIntValue("QV4_JIT_CALL_THRESHOLD", &ok); if (!ok) jitCallCountThreshold = 3; @@ -258,7 +267,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) jsSymbols = jsAlloca(NJSSymbols); // set up stack limits - jsStackLimit = jsStackBase + JSStackLimit/sizeof(Value); + jsStackLimit = jsStackBase + m_maxJSStackSize/sizeof(Value); identifierTable = new IdentifierTable(this); @@ -683,7 +692,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) ScopedFunctionObject t(scope, memoryManager->allocate<FunctionObject>(rootContext(), nullptr, ::throwTypeError)); t->defineReadonlyProperty(id_length(), Value::fromInt32(0)); - t->setInternalClass(t->internalClass()->frozen()); + t->setInternalClass(t->internalClass()->cryopreserved()); jsObjects[ThrowerObject] = t; ScopedProperty pd(scope); @@ -692,7 +701,6 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) functionPrototype()->insertMember(id_caller(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable); functionPrototype()->insertMember(id_arguments(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable); - QML_MEMORY_SCOPE_STRING("QV4Engine::QV4Engine"); qMetaTypeId<QJSValue>(); qMetaTypeId<QList<int> >(); @@ -1738,6 +1746,16 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data) return fromVariant(variant); } +int ExecutionEngine::maxJSStackSize() const +{ + return m_maxJSStackSize; +} + +int ExecutionEngine::maxGCStackSize() const +{ + return m_maxGCStackSize; +} + ReturnedValue ExecutionEngine::global() { return globalObject->asReturnedValue(); @@ -1768,10 +1786,10 @@ QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::compileModule( sourceCode, sourceTimeStamp, &diagnostics); for (const QQmlJS::DiagnosticMessage &m : diagnostics) { if (m.isError()) { - throwSyntaxError(m.message, url.toString(), m.loc.startLine, m.loc.startColumn); + throwSyntaxError(m.message, url.toString(), m.line, m.column); return nullptr; } else { - qWarning() << url << ':' << m.loc.startLine << ':' << m.loc.startColumn + qWarning() << url << ':' << m.line << ':' << m.column << ": warning: " << m.message; } } @@ -1872,7 +1890,7 @@ void ExecutionEngine::setQmlEngine(QQmlEngine *engine) static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object) { - if (object->as<QV4::QObjectWrapper>()) + if (object->as<QV4::QObjectWrapper>() || object->internalClass()->isFrozen) return; QV4::Scope scope(v4); @@ -1889,10 +1907,8 @@ static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object) if (!instanceOfObject) return; - QV4::Heap::InternalClass *frozen = object->internalClass()->propertiesFrozen(); - if (object->internalClass() == frozen) - return; - object->setInternalClass(frozen); + Heap::InternalClass *frozen = object->internalClass()->frozen(); + object->setInternalClass(frozen); // Immediately assign frozen to prevent it from getting GC'd QV4::ScopedObject o(scope); for (uint i = 0; i < frozen->size; ++i) { diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index f8ac0e0268..ce25ab16b1 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -170,10 +170,6 @@ public: WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine. - enum { - JSStackLimit = 4*1024*1024, - GCStackLimit = 2*1024*1024 - }; WTF::PageAllocation *jsStack; WTF::PageAllocation *gcStack; @@ -641,6 +637,9 @@ public: bool metaTypeFromJS(const Value *value, int type, void *data); QV4::ReturnedValue metaTypeToJS(int type, const void *data); + int maxJSStackSize() const; + int maxGCStackSize() const; + bool checkStackLimits(); bool canJIT(Function *f = nullptr) @@ -734,6 +733,9 @@ private: QHash<QString, quint32> m_consoleCount; QVector<Deletable *> m_extensionData; + + int m_maxJSStackSize = 4 * 1024 * 1024; + int m_maxGCStackSize = 2 * 1024 * 1024; }; #define CHECK_STACK_LIMITS(v4) if ((v4)->checkStackLimits()) return Encode::undefined(); \ diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp index c68f6a7cbf..492d1f4d03 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit.cpp +++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp @@ -51,6 +51,7 @@ #include <private/qqmlvaluetypewrapper_p.h> #include <private/qv4module_p.h> #include <private/qv4compilationunitmapper_p.h> +#include <private/qml_compile_hash_p.h> #include <QtQml/qqmlfile.h> #include <QtQml/qqmlpropertymap.h> @@ -59,6 +60,20 @@ #include <QtCore/qstandardpaths.h> #include <QtCore/qfileinfo.h> #include <QtCore/qscopeguard.h> +#include <QtCore/qcryptographichash.h> + +#if defined(QML_COMPILE_HASH) +# ifdef Q_OS_LINUX +// Place on a separate section on Linux so it's easier to check from outside +// what the hash version is. +__attribute__((section(".qml_compile_hash"))) +# endif +const char qml_compile_hash[48 + 1] = QML_COMPILE_HASH; +static_assert(sizeof(QV4::CompiledData::Unit::libraryVersionHash) >= QML_COMPILE_HASH_LENGTH + 1, + "Compile hash length exceeds reserved size in data structure. Please adjust and bump the format version"); +#else +# error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files" +#endif QT_BEGIN_NAMESPACE @@ -105,7 +120,7 @@ static QString toString(QV4::ReturnedValue v) static void dumpConstantTable(const StaticValue *constants, uint count) { QDebug d = qDebug(); - d.nospace() << right; + d.nospace() << Qt::right; for (uint i = 0; i < count; ++i) { d << qSetFieldWidth(8) << i << qSetFieldWidth(0) << ": " << toString(constants[i].asReturnedValue()).toUtf8().constData() << "\n"; @@ -308,7 +323,12 @@ void ExecutableCompilationUnit::unlink() f->destroy(); runtimeFunctions.clear(); - CompiledData::CompilationUnit::unlink(); + free(runtimeStrings); + runtimeStrings = nullptr; + delete [] runtimeRegularExpressions; + runtimeRegularExpressions = nullptr; + free(runtimeClasses); + runtimeClasses = nullptr; } void ExecutableCompilationUnit::markObjects(QV4::MarkStack *markStack) @@ -673,7 +693,11 @@ bool ExecutableCompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorSt return false; } - return CompilationUnit::saveToDisk(localCacheFilePath(unitUrl), errorString); + return CompiledData::SaveableUnitPointer(unitData()).saveToDisk<char>( + [this, &unitUrl, errorString](const char *data, quint32 size) { + return CompiledData::SaveableUnitPointer::writeDataToFile(localCacheFilePath(unitUrl), data, + size, errorString); + }); } /*! @@ -766,8 +790,8 @@ QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Bind #if !QT_CONFIG(translation) case Binding::Type_TranslationById: case Binding::Type_Translation: - return unit->stringAt( - unit->data->translations()[binding->value.translationDataIndex].stringIndex); + return stringAt( + data->translations()[binding->value.translationDataIndex].stringIndex); #else case Binding::Type_TranslationById: { const TranslationData &translation @@ -804,6 +828,50 @@ QString ExecutableCompilationUnit::bindingValueAsScriptString( : bindingValueAsString(binding); } +bool ExecutableCompilationUnit::verifyHeader( + const CompiledData::Unit *unit, QDateTime expectedSourceTimeStamp, QString *errorString) +{ + if (strncmp(unit->magic, CompiledData::magic_str, sizeof(unit->magic))) { + *errorString = QStringLiteral("Magic bytes in the header do not match"); + return false; + } + + if (unit->version != quint32(QV4_DATA_STRUCTURE_VERSION)) { + *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2") + .arg(unit->version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16); + return false; + } + + if (unit->qtVersion != quint32(QT_VERSION)) { + *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2") + .arg(unit->qtVersion, 0, 16).arg(QT_VERSION, 0, 16); + return false; + } + + if (unit->sourceTimeStamp) { + // Files from the resource system do not have any time stamps, so fall back to the application + // executable. + if (!expectedSourceTimeStamp.isValid()) + expectedSourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified(); + + if (expectedSourceTimeStamp.isValid() + && expectedSourceTimeStamp.toMSecsSinceEpoch() != unit->sourceTimeStamp) { + *errorString = QStringLiteral("QML source file has a different time stamp than cached file."); + return false; + } + } + +#if defined(QML_COMPILE_HASH) + if (qstrcmp(qml_compile_hash, unit->libraryVersionHash) != 0) { + *errorString = QStringLiteral("QML library version mismatch. Expected compile hash does not match"); + return false; + } +#else +#error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files" +#endif + return true; +} + } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h index 4e3aadf28a..010b8a2fd0 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit_p.h +++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h @@ -52,10 +52,12 @@ // #include <private/qv4compileddata_p.h> +#include <private/qv4identifier_p.h> #include <private/qqmlrefcount_p.h> #include <private/qintrusivelist_p.h> #include <private/qqmlpropertycachevector_p.h> #include <private/qqmltype_p.h> +#include <private/qqmlnullablevalue_p.h> QT_BEGIN_NAMESPACE @@ -251,6 +253,9 @@ public: return constants[binding->value.constantValueIndex].doubleValue(); } + static bool verifyHeader(const CompiledData::Unit *unit, QDateTime expectedSourceTimeStamp, + QString *errorString); + protected: quint32 totalStringCount() const { return data->stringTableSize; } diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp index f9bc7b68c6..c3d7165f71 100644 --- a/src/qml/jsruntime/qv4identifier.cpp +++ b/src/qml/jsruntime/qv4identifier.cpp @@ -50,7 +50,7 @@ IdentifierHashData::IdentifierHashData(IdentifierTable *table, int numBits) , numBits(numBits) , identifierTable(table) { - refCount.store(1); + refCount.storeRelaxed(1); alloc = qPrimeForNumBits(numBits); entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry)); memset(entries, 0, alloc*sizeof(IdentifierHashEntry)); @@ -62,7 +62,7 @@ IdentifierHashData::IdentifierHashData(IdentifierHashData *other) , numBits(other->numBits) , identifierTable(other->identifierTable) { - refCount.store(1); + refCount.storeRelaxed(1); alloc = other->alloc; entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry)); memcpy(entries, other->entries, alloc*sizeof(IdentifierHashEntry)); @@ -82,7 +82,7 @@ IdentifierHash::IdentifierHash(ExecutionEngine *engine) void IdentifierHash::detach() { - if (!d || d->refCount == 1) + if (!d || d->refCount.loadAcquire() == 1) return; IdentifierHashData *newData = new IdentifierHashData(d); if (d && !d->refCount.deref()) diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index d597335031..70849775cb 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -290,7 +290,6 @@ void InternalClass::init(ExecutionEngine *engine) void InternalClass::init(Heap::InternalClass *other) { Base::init(); - Q_ASSERT(!other->isFrozen); new (&propertyTable) PropertyHash(other->propertyTable); new (&nameMap) SharedInternalClassData<PropertyKey>(other->nameMap); new (&propertyData) SharedInternalClassData<PropertyAttributes>(other->propertyData); @@ -564,22 +563,6 @@ Heap::InternalClass *InternalClass::sealed() if (isSealed) return this; - bool alreadySealed = !extensible; - for (uint i = 0; i < size; ++i) { - PropertyAttributes attrs = propertyData.at(i); - if (attrs.isEmpty()) - continue; - if (attrs.isConfigurable()) { - alreadySealed = false; - break; - } - } - - if (alreadySealed) { - isSealed = true; - return this; - } - Transition temp = { { PropertyKey::invalid() }, nullptr, InternalClassTransition::Sealed }; Transition &t = lookupOrInsertTransition(temp); @@ -592,14 +575,15 @@ Heap::InternalClass *InternalClass::sealed() Scoped<QV4::InternalClass> ic(scope, engine->newClass(this)); Heap::InternalClass *s = ic->d(); - for (uint i = 0; i < size; ++i) { - PropertyAttributes attrs = propertyData.at(i); - if (attrs.isEmpty()) - continue; - attrs.setConfigurable(false); - s->propertyData.set(i, attrs); + if (!isFrozen) { // freezing also makes all properties non-configurable + for (uint i = 0; i < size; ++i) { + PropertyAttributes attrs = propertyData.at(i); + if (attrs.isEmpty()) + continue; + attrs.setConfigurable(false); + s->propertyData.set(i, attrs); + } } - s->extensible = false; s->isSealed = true; t.lookup = s; @@ -611,28 +595,11 @@ Heap::InternalClass *InternalClass::frozen() if (isFrozen) return this; - bool alreadyFrozen = !extensible; - for (uint i = 0; i < size; ++i) { - PropertyAttributes attrs = propertyData.at(i); - if (attrs.isEmpty()) - continue; - if ((attrs.isData() && attrs.isWritable()) || attrs.isConfigurable()) { - alreadyFrozen = false; - break; - } - } - - if (alreadyFrozen) { - isSealed = true; - isFrozen = true; - return this; - } - Transition temp = { { PropertyKey::invalid() }, nullptr, InternalClassTransition::Frozen }; Transition &t = lookupOrInsertTransition(temp); if (t.lookup) { - Q_ASSERT(t.lookup && t.lookup->isSealed && t.lookup->isFrozen); + Q_ASSERT(t.lookup && t.lookup->isFrozen); return t.lookup; } @@ -649,29 +616,42 @@ Heap::InternalClass *InternalClass::frozen() attrs.setConfigurable(false); f->propertyData.set(i, attrs); } - f->extensible = false; - f->isSealed = true; f->isFrozen = true; t.lookup = f; return f; } -Heap::InternalClass *InternalClass::propertiesFrozen() +InternalClass *InternalClass::canned() { + // scope the intermediate result to prevent it from getting garbage collected Scope scope(engine); - Scoped<QV4::InternalClass> frozen(scope, this); + Scoped<QV4::InternalClass> ic(scope, sealed()); + return ic->d()->nonExtensible(); +} + +InternalClass *InternalClass::cryopreserved() +{ + // scope the intermediate result to prevent it from getting garbage collected + Scope scope(engine); + Scoped<QV4::InternalClass> ic(scope, frozen()); + return ic->d()->canned(); +} + +bool InternalClass::isImplicitlyFrozen() const +{ + if (isFrozen) + return true; + for (uint i = 0; i < size; ++i) { - PropertyAttributes attrs = propertyData.at(i); - if (!nameMap.at(i).isValid()) + const PropertyAttributes attrs = propertyData.at(i); + if (attrs.isEmpty()) continue; - if (!attrs.isEmpty()) { - attrs.setWritable(false); - attrs.setConfigurable(false); - } - frozen = frozen->changeMember(nameMap.at(i), attrs); + if ((attrs.isData() && attrs.isWritable()) || attrs.isConfigurable()) + return false; } - return frozen->d(); + + return true; } Heap::InternalClass *InternalClass::asProtoClass() diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 7bb10f47a3..403702ae55 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -432,7 +432,9 @@ struct InternalClass : Base { Q_REQUIRED_RESULT InternalClass *sealed(); Q_REQUIRED_RESULT InternalClass *frozen(); - Q_REQUIRED_RESULT InternalClass *propertiesFrozen(); + Q_REQUIRED_RESULT InternalClass *canned(); // sealed + nonExtensible + Q_REQUIRED_RESULT InternalClass *cryopreserved(); // frozen + sealed + nonExtensible + bool isImplicitlyFrozen() const; Q_REQUIRED_RESULT InternalClass *asProtoClass(); diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 99f425293e..0cda6b864a 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -77,8 +77,13 @@ ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Valu primitiveLookup.type = object.type(); switch (primitiveLookup.type) { case Value::Undefined_Type: - case Value::Null_Type: - return engine->throwTypeError(); + case Value::Null_Type: { + Scope scope(engine); + ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); + const QString message = QStringLiteral("Cannot read property '%1' of %2").arg(name->toQString()) + .arg(QLatin1String(primitiveLookup.type == Value::Undefined_Type ? "undefined" : "null")); + return engine->throwTypeError(message); + } case Value::Boolean_Type: primitiveLookup.proto = engine->booleanPrototype()->d(); break; diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 94bf1a98ae..7578de4d14 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -120,7 +120,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup { } indexedLookup; struct { Heap::InternalClass *ic; - Heap::QObjectWrapper *staticQObject; + Heap::InternalClass *qmlTypeIc; // only used when lookup goes through QQmlTypeWrapper QQmlPropertyCache *propertyCache; QQmlPropertyData *propertyData; } qobjectLookup; diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index ffebe1b5da..34b0c38ae6 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -72,8 +72,9 @@ Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberD // The above code can overflow in a number of interesting ways. All of those are unsigned, // and therefore defined behavior. Still, apply some sane bounds. - if (alloc > size_t(std::numeric_limits<int>::max())) - alloc = size_t(std::numeric_limits<int>::max()); + const size_t intMax = std::numeric_limits<int>::max(); + if (alloc > intMax) + alloc = intMax; Heap::MemberData *m; if (old) { diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 6b4c3ba71a..3d3b3f413f 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -422,7 +422,7 @@ ReturnedValue ObjectPrototype::method_seal(const FunctionObject *b, const Value Scope scope(b); ScopedObject o(scope, a); - o->setInternalClass(o->internalClass()->sealed()); + o->setInternalClass(o->internalClass()->canned()); if (o->arrayData()) { ArrayData::ensureAttributes(o); @@ -448,7 +448,7 @@ ReturnedValue ObjectPrototype::method_freeze(const FunctionObject *b, const Valu if (ArgumentsObject::isNonStrictArgumentsObject(o)) static_cast<ArgumentsObject *>(o.getPointer())->fullyCreate(); - o->setInternalClass(o->internalClass()->frozen()); + o->setInternalClass(o->internalClass()->cryopreserved()); if (o->arrayData()) { ArrayData::ensureAttributes(o); @@ -489,7 +489,7 @@ ReturnedValue ObjectPrototype::method_isSealed(const FunctionObject *b, const Va if (o->isExtensible()) return Encode(false); - if (o->internalClass() != o->internalClass()->sealed()) + if (o->internalClass() != o->internalClass()->canned()) return Encode(false); if (!o->arrayData() || !o->arrayData()->length()) @@ -521,7 +521,7 @@ ReturnedValue ObjectPrototype::method_isFrozen(const FunctionObject *b, const Va if (o->isExtensible()) return Encode(false); - if (o->internalClass() != o->internalClass()->frozen()) + if (!o->internalClass()->isImplicitlyFrozen()) return Encode(false); if (!o->arrayData() || !o->arrayData()->length()) diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index f3351f6da0..c832bff051 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -292,7 +292,6 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, scopeObject))); const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue()); lookup->qobjectLookup.ic = That->internalClass(); - lookup->qobjectLookup.staticQObject = nullptr; lookup->qobjectLookup.propertyCache = ddata->propertyCache; lookup->qobjectLookup.propertyCache->addref(); lookup->qobjectLookup.propertyData = propertyData; @@ -325,7 +324,6 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, context->contextObject))); const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue()); lookup->qobjectLookup.ic = That->internalClass(); - lookup->qobjectLookup.staticQObject = nullptr; lookup->qobjectLookup.propertyCache = ddata->propertyCache; lookup->qobjectLookup.propertyCache->addref(); lookup->qobjectLookup.propertyData = propertyData; @@ -540,7 +538,6 @@ ReturnedValue QQmlContextWrapper::lookupIdObject(Lookup *l, ExecutionEngine *eng ReturnedValue QQmlContextWrapper::lookupScopeObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base) { - Q_UNUSED(base) Scope scope(engine); Scoped<QmlContext> qmlContext(scope, engine->qmlContext()); if (!qmlContext) @@ -561,12 +558,15 @@ ReturnedValue QQmlContextWrapper::lookupScopeObjectProperty(Lookup *l, Execution }; ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, scopeObject)); + + if (base) + *base = obj; + return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup); } ReturnedValue QQmlContextWrapper::lookupContextObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base) { - Q_UNUSED(base) Scope scope(engine); Scoped<QmlContext> qmlContext(scope, engine->qmlContext()); if (!qmlContext) @@ -591,6 +591,10 @@ ReturnedValue QQmlContextWrapper::lookupContextObjectProperty(Lookup *l, Executi }; ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, contextObject)); + + if (base) + *base = obj; + return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup); } diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 8b7de89d5b..8a4adfe69a 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -872,7 +872,6 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E } lookup->qobjectLookup.ic = This->internalClass(); - lookup->qobjectLookup.staticQObject = nullptr; lookup->qobjectLookup.propertyCache = ddata->propertyCache; lookup->qobjectLookup.propertyCache->addref(); lookup->qobjectLookup.propertyData = property; diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 795bf241f2..ac9cad2bdb 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -231,8 +231,7 @@ inline ReturnedValue QObjectWrapper::lookupGetterImpl(Lookup *lookup, ExecutionE if (!o || o->internalClass != lookup->qobjectLookup.ic) return revertLookup(); - const Heap::QObjectWrapper *This = lookup->qobjectLookup.staticQObject ? lookup->qobjectLookup.staticQObject : - static_cast<const Heap::QObjectWrapper *>(o); + const Heap::QObjectWrapper *This = static_cast<const Heap::QObjectWrapper *>(o); QObject *qobj = This->object(); if (QQmlData::wasDeleted(qobj)) return QV4::Encode::undefined(); diff --git a/src/qml/jsruntime/qv4runtimecodegen.cpp b/src/qml/jsruntime/qv4runtimecodegen.cpp index 99d0de5ec6..8d324acbd0 100644 --- a/src/qml/jsruntime/qv4runtimecodegen.cpp +++ b/src/qml/jsruntime/qv4runtimecodegen.cpp @@ -59,7 +59,7 @@ void RuntimeCodegen::generateFromFunctionExpression(const QString &fileName, scan(ast); scan.leaveEnvironment(); - if (hasError) + if (hasError()) return; int index = defineFunction(ast->name.toString(), ast, ast->formals, ast->body); @@ -68,17 +68,19 @@ void RuntimeCodegen::generateFromFunctionExpression(const QString &fileName, void RuntimeCodegen::throwSyntaxError(const AST::SourceLocation &loc, const QString &detail) { - if (hasError) + if (hasError()) return; - hasError = true; + + Codegen::throwSyntaxError(loc, detail); engine->throwSyntaxError(detail, _module->fileName, loc.startLine, loc.startColumn); } void RuntimeCodegen::throwReferenceError(const AST::SourceLocation &loc, const QString &detail) { - if (hasError) + if (hasError()) return; - hasError = true; + + Codegen::throwReferenceError(loc, detail); engine->throwReferenceError(detail, _module->fileName, loc.startLine, loc.startColumn); } diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index ee7f4dff0b..c463812590 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -108,10 +108,10 @@ void Script::parse() const auto diagnosticMessages = parser.diagnosticMessages(); for (const DiagnosticMessage &m : diagnosticMessages) { if (m.isError()) { - valueScope.engine->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn); + valueScope.engine->throwSyntaxError(m.message, sourceFile, m.line, m.column); return; } else { - qWarning() << sourceFile << ':' << m.loc.startLine << ':' << m.loc.startColumn + qWarning() << sourceFile << ':' << m.line << ':' << m.column << ": warning: " << m.message; } } @@ -203,10 +203,16 @@ QV4::CompiledData::CompilationUnit Script::precompile( Codegen cg(unitGenerator, /*strict mode*/false); cg.generateFromProgram(fileName, finalUrl, source, program, module, contextType); - errors = cg.qmlErrors(); - if (!errors.isEmpty()) { - if (reportedErrors) - *reportedErrors << errors; + if (cg.hasError()) { + if (reportedErrors) { + const auto v4Error = cg.error(); + QQmlError error; + error.setUrl(cg.url()); + error.setLine(v4Error.line); + error.setColumn(v4Error.column); + error.setDescription(v4Error.message); + reportedErrors->append(error); + } return nullptr; } diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 43e1dabb6d..7d33167762 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -214,7 +214,7 @@ template <typename T> ReturnedValue atomicLoad(char *data) { typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data); - T val = QAtomicOps<T>::load(*mem); + T val = QAtomicOps<T>::loadRelaxed(*mem); return typeToValue(val); } @@ -223,7 +223,7 @@ ReturnedValue atomicStore(char *data, Value v) { T value = valueToType<T>(v); typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data); - QAtomicOps<T>::store(*mem, value); + QAtomicOps<T>::storeRelaxed(*mem, value); return typeToValue(value); } diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index a9c8ac66bd..4e901721cb 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -87,12 +87,29 @@ struct Q_QML_PRIVATE_EXPORT Value : public StaticValue QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const { HeapBasePtr b; +#ifdef __ia64 +// Restore bits 49-47 to bits 63-61, undoing the workaround explained in +// setM below. + quint64 _tmp; + + _tmp = _val & (7L << 47); // 0x3800000000000 + _tmp = (_tmp << 14) | (_val ^ _tmp); + memcpy(&b, &_tmp, 8); +#else memcpy(&b, &_val, 8); +#endif return b; } QML_NEARLY_ALWAYS_INLINE void setM(HeapBasePtr b) { memcpy(&_val, &b, 8); +#ifdef __ia64 +// On ia64, bits 63-61 in a 64-bit pointer are used to store the virtual region +// number. Since this implementation is not 64-bit clean, we move bits 63-61 +// to bits 49-47 and hope for the best. This is undone in *m(), above. + _val |= ((_val & (7L << 61)) >> 14); + _val &= ((1L << 50)-1); +#endif } #elif QT_POINTER_SIZE == 4 QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 5b68725bcf..b2bbe985d3 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -206,7 +206,7 @@ int qt_v4DebuggerHook(const char *json) return ProtocolVersion; // Version number. } - int version = ob.value(QLatin1Literal("version")).toString().toInt(); + int version = ob.value(QLatin1String("version")).toString().toInt(); if (version != ProtocolVersion) { return -WrongProtocol; } @@ -349,7 +349,7 @@ static struct InstrCount { #undef CHECK_EXCEPTION #endif #define CHECK_EXCEPTION \ - if (engine->hasException || engine->isInterrupted) \ + if (engine->hasException || engine->isInterrupted.loadAcquire()) \ goto handleUnwind static inline Heap::CallContext *getScope(QV4::Value *stack, int level) @@ -1376,7 +1376,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, // We do start the exception handler in case of isInterrupted. The exception handler will // immediately abort, due to the same isInterrupted. We don't skip the exception handler // because the current behavior is easier to implement in the JIT. - Q_ASSERT(engine->hasException || engine->isInterrupted || frame->unwindLevel); + Q_ASSERT(engine->hasException || engine->isInterrupted.loadAcquire() || frame->unwindLevel); if (!frame->unwindHandler) { acc = Encode::undefined(); return acc; diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index 07af5a6f7a..d7cfa193e6 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -234,7 +234,7 @@ struct QQmlQPointer { } T *data() const { - return d == nullptr || d->strongref.load() == 0 ? nullptr : qObject; + return d == nullptr || d->strongref.loadRelaxed() == 0 ? nullptr : qObject; } operator T*() const { return data(); } inline T* operator->() const { return data(); } @@ -247,7 +247,7 @@ struct QQmlQPointer { } bool isNull() const Q_DECL_NOTHROW { - return d == nullptr || qObject == nullptr || d->strongref.load() == 0; + return d == nullptr || qObject == nullptr || d->strongref.loadRelaxed() == 0; } private: diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 9288d3e3b6..6ee36cbfcf 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -112,7 +112,11 @@ enum { struct MemorySegment { enum { +#ifdef Q_OS_RTEMS + NumChunks = sizeof(quint64), +#else NumChunks = 8*sizeof(quint64), +#endif SegmentSize = NumChunks*Chunk::ChunkSize, }; @@ -219,7 +223,8 @@ Chunk *MemorySegment::allocate(size_t size) pageReservation.commit(candidate, size); for (uint i = 0; i < requiredChunks; ++i) setBit(candidate - base + i); - DEBUG << "allocated chunk " << candidate << hex << size; + DEBUG << "allocated chunk " << candidate << Qt::hex << size; + return candidate; } } @@ -847,7 +852,7 @@ MarkStack::MarkStack(ExecutionEngine *engine) { base = (Heap::Base **)engine->gcStack->base(); top = base; - limit = base + ExecutionEngine::GCStackLimit/sizeof(Heap::Base)*3/4; + limit = base + engine->maxGCStackSize()/sizeof(Heap::Base)*3/4; } void MarkStack::drain() @@ -1020,7 +1025,7 @@ static size_t dumpBins(BlockAllocator *b, const char *title) SDUMP() << " large slot map"; HeapItem *h = b->freeBins[BlockAllocator::NumBins - 1]; while (h) { - SDUMP() << " " << hex << (quintptr(h)/32) << h->freeData.availableSlots; + SDUMP() << " " << Qt::hex << (quintptr(h)/32) << h->freeData.availableSlots; h = h->freeData.next; } diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index 0c947b541b..daaa402ef1 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -58,6 +58,7 @@ %token T_MINUS "-" T_MINUS_EQ "-=" T_MINUS_MINUS "--" %token T_NEW "new" T_NOT "!" T_NOT_EQ "!=" %token T_NOT_EQ_EQ "!==" T_NUMERIC_LITERAL "numeric literal" T_OR "|" +%token T_VERSION_NUMBER "version number" %token T_OR_EQ "|=" T_OR_OR "||" T_PLUS "+" %token T_PLUS_EQ "+=" T_PLUS_PLUS "++" T_QUESTION "?" %token T_RBRACE "}" T_RBRACKET "]" T_REMAINDER "%" @@ -245,6 +246,7 @@ #include <private/qqmljsgrammar_p.h> #include <private/qqmljsast_p.h> #include <private/qqmljsengine_p.h> +#include <private/qqmljsdiagnosticmessage_p.h> #include <QtCore/qlist.h> #include <QtCore/qstring.h> @@ -314,6 +316,7 @@ public: AST::UiArrayMemberList *UiArrayMemberList; AST::UiQualifiedId *UiQualifiedId; AST::UiEnumMemberList *UiEnumMemberList; + AST::UiVersionSpecifier *UiVersionSpecifier; }; public: @@ -365,7 +368,7 @@ public: inline DiagnosticMessage diagnosticMessage() const { for (const DiagnosticMessage &d : diagnostic_messages) { - if (d.kind != DiagnosticMessage::Warning) + if (d.type != QtWarningMsg) return d; } @@ -376,10 +379,10 @@ public: { return diagnosticMessage().message; } inline int errorLineNumber() const - { return diagnosticMessage().loc.startLine; } + { return diagnosticMessage().line; } inline int errorColumnNumber() const - { return diagnosticMessage().loc.startColumn; } + { return diagnosticMessage().column; } protected: bool parse(int startToken); @@ -403,11 +406,22 @@ protected: void pushToken(int token); int lookaheadToken(Lexer *lexer); + static DiagnosticMessage compileError(const AST::SourceLocation &location, + const QString &message, QtMsgType kind = QtCriticalMsg) + { + DiagnosticMessage error; + error.line = location.startLine; + error.column = location.startColumn; + error.message = message; + error.type = kind; + return error; + } + void syntaxError(const AST::SourceLocation &location, const char *message) { - diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location, QLatin1String(message))); + diagnostic_messages.append(compileError(location, QLatin1String(message))); } void syntaxError(const AST::SourceLocation &location, const QString &message) { - diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location, message)); + diagnostic_messages.append(compileError(location, message)); } protected: @@ -790,20 +804,47 @@ UiImport: UiImportHead T_SEMICOLON; } break; ./ -UiImport: UiImportHead T_NUMERIC_LITERAL T_AUTOMATIC_SEMICOLON; -UiImport: UiImportHead T_NUMERIC_LITERAL T_SEMICOLON; +UiVersionSpecifier: T_VERSION_NUMBER T_DOT T_VERSION_NUMBER; /. case $rule_number: { - sym(1).UiImport->versionToken = loc(2); + auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval, sym(3).dval); + version->majorToken = loc(1); + version->minorToken = loc(3); + sym(1).UiVersionSpecifier = version; + } break; +./ + + +UiVersionSpecifier: T_VERSION_NUMBER; +/. + case $rule_number: { + auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval, 0); + version->majorToken = loc(1); + sym(1).UiVersionSpecifier = version; + } break; +./ + +UiImport: UiImportHead UiVersionSpecifier T_AUTOMATIC_SEMICOLON; +UiImport: UiImportHead UiVersionSpecifier T_SEMICOLON; +/. + case $rule_number: { + auto versionToken = loc(2); + auto version = sym(2).UiVersionSpecifier; + sym(1).UiImport->version = version; + if (version->minorToken.isValid()) { + versionToken.length += version->minorToken.length + (version->minorToken.offset - versionToken.offset - versionToken.length); + } + sym(1).UiImport->versionToken = versionToken; sym(1).UiImport->semicolonToken = loc(3); } break; ./ -UiImport: UiImportHead T_NUMERIC_LITERAL T_AS QmlIdentifier T_AUTOMATIC_SEMICOLON; -UiImport: UiImportHead T_NUMERIC_LITERAL T_AS QmlIdentifier T_SEMICOLON; +UiImport: UiImportHead UiVersionSpecifier T_AS QmlIdentifier T_AUTOMATIC_SEMICOLON; +UiImport: UiImportHead UiVersionSpecifier T_AS QmlIdentifier T_SEMICOLON; /. case $rule_number: { sym(1).UiImport->versionToken = loc(2); + sym(1).UiImport->version = sym(2).UiVersionSpecifier; sym(1).UiImport->asToken = loc(3); sym(1).UiImport->importIdToken = loc(4); sym(1).UiImport->importId = stringRef(4); @@ -840,7 +881,7 @@ UiImportHead: T_IMPORT ImportId; if (node) { node->importToken = loc(1); } else { - diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1), + diagnostic_messages.append(compileError(loc(1), QLatin1String("Expected a qualified name id or a string literal"))); return false; // ### remove me @@ -1110,6 +1151,23 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T } break; ./ +UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_AUTOMATIC_SEMICOLON; +UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_SEMICOLON; +/. + case $rule_number: { + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7)); + node->isReadonlyMember = true; + node->readonlyToken = loc(1); + node->typeModifier = stringRef(3); + node->propertyToken = loc(2); + node->typeModifierToken = loc(3); + node->typeToken = loc(5); + node->identifierToken = loc(7); + node->semicolonToken = loc(8); + sym(1).Node = node; + } break; +./ + UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_AUTOMATIC_SEMICOLON; UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_SEMICOLON; /. @@ -1221,6 +1279,34 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T } break; ./ +UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET; +/. + case $rule_number: { + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7)); + node->isReadonlyMember = true; + node->readonlyToken = loc(1); + node->typeModifier = stringRef(3); + node->propertyToken = loc(2); + node->typeModifierToken = loc(3); + node->typeToken = loc(5); + node->identifierToken = loc(7); + node->semicolonToken = loc(8); // insert a fake ';' before ':' + + AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(7)); + propertyName->identifierToken = loc(7); + propertyName->next = 0; + + AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(propertyName, sym(10).UiArrayMemberList->finish()); + binding->colonToken = loc(8); + binding->lbracketToken = loc(9); + binding->rbracketToken = loc(11); + + node->binding = binding; + + sym(1).Node = node; + } break; +./ + UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer; /. case $rule_number: { @@ -1287,8 +1373,8 @@ UiQualifiedId: MemberExpression; /. case $rule_number: { if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) { - diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken, - QLatin1String("Ignored annotation"))); + diagnostic_messages.append(compileError(mem->lbracketToken, + QLatin1String("Ignored annotation"), QtWarningMsg)); sym(1).Expression = mem->base; } @@ -1298,7 +1384,7 @@ UiQualifiedId: MemberExpression; } else { sym(1).UiQualifiedId = 0; - diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1), + diagnostic_messages.append(compileError(loc(1), QLatin1String("Expected a qualified name id"))); return false; // ### recover @@ -1545,7 +1631,7 @@ RegularExpressionLiteral: T_DIVIDE_EQ; scan_regexp: { bool rx = lexer->scanRegExp(prefix); if (!rx) { - diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); + diagnostic_messages.append(compileError(location(lexer), lexer->errorMessage())); return false; } @@ -1773,10 +1859,6 @@ PropertyDefinition: PropertyName T_COLON AssignmentExpression_In; /. case $rule_number: { AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, sym(3).Expression); - if (auto *f = asAnonymousFunctionDefinition(sym(3).Expression)) { - if (!AST::cast<AST::ComputedPropertyName *>(sym(1).PropertyName)) - f->name = driver->newStringRef(sym(1).PropertyName->asString()); - } if (auto *c = asAnonymousClassDefinition(sym(3).Expression)) { if (!AST::cast<AST::ComputedPropertyName *>(sym(1).PropertyName)) c->name = driver->newStringRef(sym(1).PropertyName->asString()); @@ -4379,7 +4461,7 @@ ExportSpecifier: IdentifierName T_AS IdentifierName; yylloc.length = 0; //const QString msg = QCoreApplication::translate("QQmlParser", "Missing `;'"); - //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg)); + //diagnostic_messages.append(compileError(yyloc, msg, QtWarningMsg)); first_token = &token_buffer[0]; last_token = &token_buffer[1]; @@ -4416,7 +4498,7 @@ ExportSpecifier: IdentifierName T_AS IdentifierName; msg = QCoreApplication::translate("QQmlParser", "Syntax error"); else msg = QCoreApplication::translate("QQmlParser", "Unexpected token `%1'").arg(QLatin1String(spell[token])); - diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + diagnostic_messages.append(compileError(token_buffer[0].loc, msg)); action = errorState; goto _Lcheck_token; @@ -4447,7 +4529,7 @@ ExportSpecifier: IdentifierName T_AS IdentifierName; qDebug() << "Parse error, trying to recover (2)."; #endif const QString msg = QCoreApplication::translate("QQmlParser", "Expected token `%1'").arg(QLatin1String(spell[*tk])); - diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + diagnostic_messages.append(compileError(token_buffer[0].loc, msg)); pushToken(*tk); goto _Lcheck_token; @@ -4462,7 +4544,7 @@ ExportSpecifier: IdentifierName T_AS IdentifierName; int a = t_action(errorState, tk); if (a > 0 && t_action(a, yytoken)) { const QString msg = QCoreApplication::translate("QQmlParser", "Expected token `%1'").arg(QLatin1String(spell[tk])); - diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + diagnostic_messages.append(compileError(token_buffer[0].loc, msg)); pushToken(tk); goto _Lcheck_token; @@ -4470,7 +4552,7 @@ ExportSpecifier: IdentifierName T_AS IdentifierName; } const QString msg = QCoreApplication::translate("QQmlParser", "Syntax error"); - diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg)); + diagnostic_messages.append(compileError(token_buffer[0].loc, msg)); } return false; diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp index e5817ab763..1bc0e6e364 100644 --- a/src/qml/parser/qqmljsast.cpp +++ b/src/qml/parser/qqmljsast.cpp @@ -1472,6 +1472,12 @@ LeftHandSideExpression *LeftHandSideExpression::leftHandSideExpressionCast() return this; } +void UiVersionSpecifier::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + } + visitor->endVisit(this); +} } } // namespace QQmlJS::AST QT_END_NAMESPACE diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index b81553776d..606137b67d 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -234,7 +234,6 @@ public: Kind_PatternProperty, Kind_PatternPropertyList, - Kind_UiArrayBinding, Kind_UiImport, Kind_UiObjectBinding, @@ -251,7 +250,8 @@ public: Kind_UiSourceElement, Kind_UiHeaderItemList, Kind_UiEnumDeclaration, - Kind_UiEnumMemberList + Kind_UiEnumMemberList, + Kind_UiVersionSpecifier }; inline Node() {} @@ -492,7 +492,30 @@ public: SourceLocation literalToken; }; -class QML_PARSER_EXPORT StringLiteral: public LeftHandSideExpression +class QML_PARSER_EXPORT UiVersionSpecifier : public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(UiVersionSpecifier) + + UiVersionSpecifier(int majorum, int minorum) : majorVersion(majorum), minorVersion(minorum) { kind = K; } + + void accept0(Visitor *visitor) override; + + SourceLocation firstSourceLocation() const override { return majorToken; } + + SourceLocation lastSourceLocation() const override + { + return minorToken.isValid() ? minorToken : majorToken; + } + + // attributes: + int majorVersion; + int minorVersion; + SourceLocation majorToken; + SourceLocation minorToken; +}; + +class QML_PARSER_EXPORT StringLiteral : public LeftHandSideExpression { public: QQMLJS_DECLARE_AST_NODE(StringLiteral) @@ -2855,6 +2878,7 @@ public: SourceLocation asToken; SourceLocation importIdToken; SourceLocation semicolonToken; + UiVersionSpecifier *version = nullptr; }; class QML_PARSER_EXPORT UiObjectMember: public Node diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h index e9caa918d5..6fe108e425 100644 --- a/src/qml/parser/qqmljsastfwd_p.h +++ b/src/qml/parser/qqmljsastfwd_p.h @@ -178,8 +178,10 @@ class UiQualifiedId; class UiHeaderItemList; class UiEnumDeclaration; class UiEnumMemberList; +class UiVersionSpecifier; -} } // namespace AST +} // namespace AST +} // namespace QQmlJS QT_END_NAMESPACE diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h index 9115449a46..f3732cbba8 100644 --- a/src/qml/parser/qqmljsastvisitor_p.h +++ b/src/qml/parser/qqmljsastvisitor_p.h @@ -111,6 +111,7 @@ public: virtual bool visit(UiQualifiedId *) { return true; } virtual bool visit(UiEnumDeclaration *) { return true; } virtual bool visit(UiEnumMemberList *) { return true; } + virtual bool visit(UiVersionSpecifier *) { return true; } virtual void endVisit(UiProgram *) {} virtual void endVisit(UiImport *) {} @@ -129,6 +130,7 @@ public: virtual void endVisit(UiQualifiedId *) {} virtual void endVisit(UiEnumDeclaration *) {} virtual void endVisit(UiEnumMemberList *) { } + virtual void endVisit(UiVersionSpecifier *) {} // QQmlJS virtual bool visit(ThisExpression *) { return true; } diff --git a/src/qml/parser/qqmljsengine_p.h b/src/qml/parser/qqmljsengine_p.h index b7f7da9478..6a754fc236 100644 --- a/src/qml/parser/qqmljsengine_p.h +++ b/src/qml/parser/qqmljsengine_p.h @@ -91,28 +91,6 @@ public: } }; - -class QML_PARSER_EXPORT DiagnosticMessage -{ -public: - enum Kind { Hint, Warning, Error }; - - DiagnosticMessage() {} - - DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, const QString &message) - : kind(kind), loc(loc), message(message) {} - - bool isWarning() const - { return kind == Warning; } - - bool isError() const - { return kind == Error; } - - Kind kind = Error; - AST::SourceLocation loc; - QString message; -}; - class QML_PARSER_EXPORT Engine { Lexer *_lexer; diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp index c53b13f64d..165925d2a2 100644 --- a/src/qml/parser/qqmljslexer.cpp +++ b/src/qml/parser/qqmljslexer.cpp @@ -42,9 +42,12 @@ #include "qqmljsmemorypool_p.h" #include "qqmljskeywords_p.h" +#include <private/qqmljsdiagnosticmessage_p.h> + #include <QtCore/qcoreapplication.h> #include <QtCore/qvarlengtharray.h> #include <QtCore/qdebug.h> +#include <QtCore/QScopedValueRollback> QT_BEGIN_NAMESPACE Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok); @@ -269,16 +272,29 @@ int Lexer::lex() ++_bracesCount; Q_FALLTHROUGH(); case T_SEMICOLON: + _importState = ImportState::NoQmlImport; + Q_FALLTHROUGH(); case T_QUESTION: case T_COLON: case T_TILDE: _delimited = true; break; + case T_AUTOMATIC_SEMICOLON: + case T_AS: + _importState = ImportState::NoQmlImport; + Q_FALLTHROUGH(); default: if (isBinop(_tokenKind)) _delimited = true; break; + case T_IMPORT: + if (qmlMode() || (_handlingDirectives && previousTokenKind == T_DOT)) + _importState = ImportState::SawImport; + if (isBinop(_tokenKind)) + _delimited = true; + break; + case T_IF: case T_FOR: case T_WHILE: @@ -618,6 +634,8 @@ again: return T_DIVIDE_; case '.': + if (_importState == ImportState::SawImport) + return T_DOT; if (isDecimalDigit(_char.unicode())) return scanNumber(ch); if (_char == QLatin1Char('.')) { @@ -728,7 +746,10 @@ again: case '7': case '8': case '9': - return scanNumber(ch); + if (_importState == ImportState::SawImport) + return scanVersionNumber(ch); + else + return scanNumber(ch); default: { uint c = ch.unicode(); @@ -1146,6 +1167,26 @@ int Lexer::scanNumber(QChar ch) return T_NUMERIC_LITERAL; } +int Lexer::scanVersionNumber(QChar ch) +{ + if (ch == QLatin1Char('0')) { + _tokenValue = 0; + return T_VERSION_NUMBER; + } + + int acc = 0; + acc += ch.digitValue(); + + while (_char.isDigit()) { + acc *= 10; + acc += _char.digitValue(); + scanChar(); // consume the digit + } + + _tokenValue = acc; + return T_VERSION_NUMBER; +} + bool Lexer::scanRegExp(RegExpBodyPrefix prefix) { _tokenText.resize(0); @@ -1402,6 +1443,13 @@ static inline bool isUriToken(int token) bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error) { + auto setError = [error, this](QString message) { + error->message = std::move(message); + error->line = tokenStartLine(); + error->column = tokenStartColumn(); + }; + + QScopedValueRollback<bool> directivesGuard(_handlingDirectives, true); Q_ASSERT(!_qmlMode); lex(); // fetch the first token @@ -1422,9 +1470,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error) if (! (directiveName == QLatin1String("pragma") || directiveName == QLatin1String("import"))) { - error->message = QCoreApplication::translate("QQmlParser", "Syntax error"); - error->loc.startLine = tokenStartLine(); - error->loc.startColumn = tokenStartColumn(); + setError(QCoreApplication::translate("QQmlParser", "Syntax error")); return false; // not a valid directive name } @@ -1432,9 +1478,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error) if (directiveName == QLatin1String("pragma")) { // .pragma library if (! (lex() == T_IDENTIFIER && tokenText() == QLatin1String("library"))) { - error->message = QCoreApplication::translate("QQmlParser", "Syntax error"); - error->loc.startLine = tokenStartLine(); - error->loc.startColumn = tokenStartColumn(); + setError(QCoreApplication::translate("QQmlParser", "Syntax error")); return false; // expected `library } @@ -1456,20 +1500,15 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error) pathOrUri = tokenText(); if (!pathOrUri.endsWith(QLatin1String("js"))) { - error->message = QCoreApplication::translate("QQmlParser","Imported file must be a script"); - error->loc.startLine = tokenStartLine(); - error->loc.startColumn = tokenStartColumn(); + setError(QCoreApplication::translate("QQmlParser","Imported file must be a script")); return false; } } else if (_tokenKind == T_IDENTIFIER) { - // .import T_IDENTIFIER (. T_IDENTIFIER)* T_NUMERIC_LITERAL as T_IDENTIFIER - + // .import T_IDENTIFIER (. T_IDENTIFIER)* T_VERSION_NUMBER . T_VERSION_NUMBER as T_IDENTIFIER while (true) { if (!isUriToken(_tokenKind)) { - error->message = QCoreApplication::translate("QQmlParser","Invalid module URI"); - error->loc.startLine = tokenStartLine(); - error->loc.startColumn = tokenStartColumn(); + setError(QCoreApplication::translate("QQmlParser","Invalid module URI")); return false; } @@ -1477,9 +1516,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error) lex(); if (tokenStartLine() != lineNumber) { - error->message = QCoreApplication::translate("QQmlParser","Invalid module URI"); - error->loc.startLine = tokenStartLine(); - error->loc.startColumn = tokenStartColumn(); + setError(QCoreApplication::translate("QQmlParser","Invalid module URI")); return false; } if (_tokenKind != QQmlJSGrammar::T_DOT) @@ -1489,21 +1526,30 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error) lex(); if (tokenStartLine() != lineNumber) { - error->message = QCoreApplication::translate("QQmlParser","Invalid module URI"); - error->loc.startLine = tokenStartLine(); - error->loc.startColumn = tokenStartColumn(); + setError(QCoreApplication::translate("QQmlParser","Invalid module URI")); return false; } } - if (_tokenKind != T_NUMERIC_LITERAL) { - error->message = QCoreApplication::translate("QQmlParser","Module import requires a version"); - error->loc.startLine = tokenStartLine(); - error->loc.startColumn = tokenStartColumn(); + if (_tokenKind != T_VERSION_NUMBER) { + setError(QCoreApplication::translate("QQmlParser","Module import requires a version")); return false; // expected the module version number } version = tokenText(); + lex(); + if (_tokenKind != T_DOT) { + setError(QCoreApplication::translate( "QQmlParser", "Module import requires a minor version (missing dot)")); + return false; // expected the module version number + } + version += QLatin1Char('.'); + + lex(); + if (_tokenKind != T_VERSION_NUMBER) { + setError(QCoreApplication::translate( "QQmlParser", "Module import requires a minor version (missing number)")); + return false; // expected the module version number + } + version += tokenText(); } // @@ -1511,34 +1557,27 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error) // if (! (lex() == T_AS && tokenStartLine() == lineNumber)) { if (fileImport) - error->message = QCoreApplication::translate("QQmlParser", "File import requires a qualifier"); + setError(QCoreApplication::translate("QQmlParser", "File import requires a qualifier")); else - error->message = QCoreApplication::translate("QQmlParser", "Module import requires a qualifier"); + setError(QCoreApplication::translate("QQmlParser", "Module import requires a qualifier")); if (tokenStartLine() != lineNumber) { - error->loc.startLine = lineNumber; - error->loc.startColumn = column; - } else { - error->loc.startLine = tokenStartLine(); - error->loc.startColumn = tokenStartColumn(); + error->line = lineNumber; + error->line = column; } return false; // expected `as' } if (lex() != T_IDENTIFIER || tokenStartLine() != lineNumber) { if (fileImport) - error->message = QCoreApplication::translate("QQmlParser", "File import requires a qualifier"); + setError(QCoreApplication::translate("QQmlParser", "File import requires a qualifier")); else - error->message = QCoreApplication::translate("QQmlParser", "Module import requires a qualifier"); - error->loc.startLine = tokenStartLine(); - error->loc.startColumn = tokenStartColumn(); + setError(QCoreApplication::translate("QQmlParser", "Module import requires a qualifier")); return false; // expected module name } const QString module = tokenText(); if (!module.at(0).isUpper()) { - error->message = QCoreApplication::translate("QQmlParser","Invalid import qualifier"); - error->loc.startLine = tokenStartLine(); - error->loc.startColumn = tokenStartColumn(); + setError(QCoreApplication::translate("QQmlParser","Invalid import qualifier")); return false; } @@ -1549,9 +1588,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error) } if (tokenStartLine() != lineNumber) { - error->message = QCoreApplication::translate("QQmlParser", "Syntax error"); - error->loc.startLine = tokenStartLine(); - error->loc.startColumn = tokenStartColumn(); + setError(QCoreApplication::translate("QQmlParser", "Syntax error")); return false; // the directives cannot span over multiple lines } diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h index 51152bfd6e..e2ee4ae351 100644 --- a/src/qml/parser/qqmljslexer_p.h +++ b/src/qml/parser/qqmljslexer_p.h @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE namespace QQmlJS { class Engine; -class DiagnosticMessage; +struct DiagnosticMessage; class Directives; class QML_PARSER_EXPORT Lexer: public QQmlJSGrammar @@ -124,6 +124,11 @@ public: StaticIsKeyword = 0x4 }; + enum class ImportState { + SawImport, + NoQmlImport + }; + public: Lexer(Engine *engine); @@ -188,6 +193,7 @@ private: inline void scanChar(); int scanToken(); int scanNumber(QChar ch); + int scanVersionNumber(QChar ch); enum ScanStringMode { SingleQuote = '\'', DoubleQuote = '"', @@ -242,6 +248,7 @@ private: int _tokenLength; int _tokenLine; int _tokenColumn; + ImportState _importState = ImportState::NoQmlImport; bool _validTokenText; bool _prohibitAutomaticSemicolon; @@ -253,6 +260,7 @@ private: bool _skipLinefeed = false; int _generatorLevel = 0; bool _staticIsKeyword = false; + bool _handlingDirectives = false; }; } // end of namespace QQmlJS diff --git a/src/qml/qml.pro b/src/qml/qml.pro index 5cb51e0d03..99ad6ace60 100644 --- a/src/qml/qml.pro +++ b/src/qml/qml.pro @@ -67,6 +67,7 @@ HEADERS += qtqmlglobal.h \ qtqmlglobal_p.h #modules +include(common/common.pri) include(util/util.pri) include(memory/memory.pri) include(parser/parser.pri) diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h index 140f129b21..b4f8acad49 100644 --- a/src/qml/qml/ftw/qqmlrefcount_p.h +++ b/src/qml/qml/ftw/qqmlrefcount_p.h @@ -113,25 +113,25 @@ QQmlRefCount::QQmlRefCount() QQmlRefCount::~QQmlRefCount() { - Q_ASSERT(refCount.load() == 0); + Q_ASSERT(refCount.loadRelaxed() == 0); } void QQmlRefCount::addref() const { - Q_ASSERT(refCount.load() > 0); + Q_ASSERT(refCount.loadRelaxed() > 0); refCount.ref(); } void QQmlRefCount::release() const { - Q_ASSERT(refCount.load() > 0); + Q_ASSERT(refCount.loadRelaxed() > 0); if (!refCount.deref()) delete this; } int QQmlRefCount::count() const { - return refCount.load(); + return refCount.loadRelaxed(); } template<class T> diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp index 2ef1dc7e93..e961ed3d0d 100644 --- a/src/qml/qml/ftw/qqmlthread.cpp +++ b/src/qml/qml/ftw/qqmlthread.cpp @@ -104,14 +104,18 @@ QQmlThreadPrivate::MainObject::MainObject(QQmlThreadPrivate *p) // Trigger mainEvent in main thread. Must be called from thread. void QQmlThreadPrivate::triggerMainEvent() { +#if QT_CONFIG(thread) Q_ASSERT(q->isThisThread()); +#endif QCoreApplication::postEvent(&m_mainObject, new QEvent(QEvent::User)); } // Trigger even in thread. Must be called from main thread. void QQmlThreadPrivate::triggerThreadEvent() { +#if QT_CONFIG(thread) Q_ASSERT(!q->isThisThread()); +#endif QCoreApplication::postEvent(this, new QEvent(QEvent::User)); } @@ -353,6 +357,12 @@ void QQmlThread::internalCallMethodInThread(Message *message) void QQmlThread::internalCallMethodInMain(Message *message) { +#if !QT_CONFIG(thread) + message->call(this); + delete message; + return; +#endif + Q_ASSERT(isThisThread()); d->lock(); @@ -397,7 +407,9 @@ void QQmlThread::internalPostMethodToThread(Message *message) void QQmlThread::internalPostMethodToMain(Message *message) { +#if QT_CONFIG(thread) Q_ASSERT(isThisThread()); +#endif d->lock(); bool wasEmpty = d->mainList.isEmpty(); d->mainList.append(message); @@ -408,7 +420,9 @@ void QQmlThread::internalPostMethodToMain(Message *message) void QQmlThread::waitForNextMessage() { +#if QT_CONFIG(thread) Q_ASSERT(!isThisThread()); +#endif d->lock(); Q_ASSERT(d->m_mainThreadWaiting == false); diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri index c625743f61..15ea12cbe7 100644 --- a/src/qml/qml/qml.pri +++ b/src/qml/qml/qml.pri @@ -1,5 +1,6 @@ SOURCES += \ $$PWD/qqml.cpp \ + $$PWD/qqmlerror.cpp \ $$PWD/qqmlopenmetaobject.cpp \ $$PWD/qqmlvmemetaobject.cpp \ $$PWD/qqmlengine.cpp \ @@ -142,7 +143,8 @@ HEADERS += \ $$PWD/qqmlpropertyresolver_p.h \ $$PWD/qqmltypecompiler_p.h \ $$PWD/qqmlpropertycachecreator_p.h \ - $$PWD/qqmlpropertyvalidator_p.h + $$PWD/qqmlpropertyvalidator_p.h \ + $$PWD/qqmlsourcecoordinate_p.h qtConfig(qml-xml-http-request) { HEADERS += \ diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index c1a8ed2a3d..613816e3f7 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -55,9 +55,7 @@ void qmlClearTypeRegistrations() // Declared in qqml.h { QQmlMetaType::clearTypeRegistrations(); QQmlEnginePrivate::baseModulesUninitialized = true; //So the engine re-registers its types -#if QT_CONFIG(library) qmlClearEnginePlugins(); -#endif } //From qqml.h @@ -113,4 +111,24 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data) return dtype.index(); } +void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data) +{ + switch (type) { + case AutoParentRegistration: + QQmlMetaType::unregisterAutoParentFunction(reinterpret_cast<AutoParentFunction>(data)); + break; + case QmlUnitCacheHookRegistration: + QQmlMetaType::removeCachedUnitLookupFunction( + reinterpret_cast<QmlUnitCacheLookupFunction>(data)); + break; + case TypeRegistration: + case InterfaceRegistration: + case SingletonRegistration: + case CompositeRegistration: + case CompositeSingletonRegistration: + QQmlMetaType::unregisterType(data); + break; + } +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 7b3f89e943..4f3bfb76b0 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -608,9 +608,12 @@ Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versi template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true) { - QObject *mutableObj = const_cast<QObject *>(obj); - return qmlAttachedPropertiesObject( - mutableObj, qmlAttachedPropertiesFunction(mutableObj, &T::staticMetaObject), create); + // We don't need a concrete object to resolve the function. As T is a C++ type, it and all its + // super types should be registered as CppType (or not at all). We only need the object and its + // QML engine to resolve composite types. Therefore, the function is actually a static property + // of the C++ type system and we can cache it here for improved performance on further lookups. + static const auto func = qmlAttachedPropertiesFunction(nullptr, &T::staticMetaObject); + return qmlAttachedPropertiesObject(const_cast<QObject *>(obj), func, create); } inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, @@ -621,13 +624,13 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi uri, versionMajor, versionMinor, typeName, - callback, nullptr, nullptr, 0, 0 + callback, nullptr, nullptr, 0, 0, {} }; return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); } -enum { QmlCurrentSingletonTypeRegistrationVersion = 2 }; +enum { QmlCurrentSingletonTypeRegistrationVersion = 3 }; template <typename T> inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject *(*callback)(QQmlEngine *, QJSEngine *)) @@ -639,7 +642,26 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi uri, versionMajor, versionMinor, typeName, - nullptr, callback, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0 + nullptr, nullptr, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, callback + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); +} + +template <typename T, typename F, typename std::enable_if<std::is_convertible<F, std::function<QObject *(QQmlEngine *, QJSEngine *)>>::value + && !std::is_convertible<F, QObject *(*)(QQmlEngine *, QJSEngine *)>::value, void>::type* = nullptr> +inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, + F&& callback) +{ + + QML_GETTYPENAMES + + QQmlPrivate::RegisterSingletonType api = { + QmlCurrentSingletonTypeRegistrationVersion, + + uri, versionMajor, versionMinor, typeName, + + nullptr, nullptr, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, callback }; return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp index 1b7a433a84..7149f8c134 100644 --- a/src/qml/qml/qqmlapplicationengine.cpp +++ b/src/qml/qml/qqmlapplicationengine.cpp @@ -62,9 +62,6 @@ void QQmlApplicationEnginePrivate::cleanUp() obj->disconnect(q); qDeleteAll(objects); -#if QT_CONFIG(translation) - qDeleteAll(translators); -#endif } void QQmlApplicationEnginePrivate::init() @@ -75,10 +72,11 @@ void QQmlApplicationEnginePrivate::init() q->connect(q, &QQmlApplicationEngine::exit, QCoreApplication::instance(), &QCoreApplication::exit, Qt::QueuedConnection); #if QT_CONFIG(translation) - QTranslator* qtTranslator = new QTranslator; - if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) + QTranslator* qtTranslator = new QTranslator(q); + if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath), QLatin1String(".qm"))) QCoreApplication::installTranslator(qtTranslator); - translators << qtTranslator; + else + delete qtTranslator; #endif new QQmlFileSelector(q,q); QCoreApplication::instance()->setProperty("__qml_using_qqmlapplicationengine", QVariant(true)); @@ -90,15 +88,14 @@ void QQmlApplicationEnginePrivate::loadTranslations(const QUrl &rootFile) if (rootFile.scheme() != QLatin1String("file") && rootFile.scheme() != QLatin1String("qrc")) return; - QFileInfo fi(rootFile.toLocalFile()); + QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(rootFile)); - QTranslator *translator = new QTranslator; - if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"))) { + Q_Q(QQmlApplicationEngine); + QTranslator *translator = new QTranslator(q); + if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"), QLatin1String(".qm"))) QCoreApplication::installTranslator(translator); - translators << translator; - } else { + else delete translator; - } #else Q_UNUSED(rootFile) #endif @@ -180,6 +177,9 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c) \list \li Connecting Qt.quit() to QCoreApplication::quit() \li Automatically loads translation files from an i18n directory adjacent to the main QML file. + \list + \li Translation files must have "qml_" prefix e.g. qml_ja_JP.qm. + \endlist \li Automatically sets an incubation controller if the scene contains a QQuickWindow. \li Automatically sets a \c QQmlFileSelector as the url interceptor, applying file selectors to all QML files and assets. diff --git a/src/qml/qml/qqmlapplicationengine_p.h b/src/qml/qml/qqmlapplicationengine_p.h index 6cf6828832..7a341847bd 100644 --- a/src/qml/qml/qqmlapplicationengine_p.h +++ b/src/qml/qml/qqmlapplicationengine_p.h @@ -59,7 +59,6 @@ QT_BEGIN_NAMESPACE -class QTranslator; class QFileSelector; class Q_QML_PRIVATE_EXPORT QQmlApplicationEnginePrivate : public QQmlEnginePrivate { @@ -74,10 +73,6 @@ public: void loadTranslations(const QUrl &rootFile); void finishLoad(QQmlComponent *component); QList<QObject *> objects; - -#if QT_CONFIG(translation) - QList<QTranslator *> translators; -#endif }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 04debc0615..59b5cc2691 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -64,7 +64,6 @@ #include <QThreadStorage> #include <QtCore/qdebug.h> #include <qqmlinfo.h> -#include "qqmlmemoryprofiler_p.h" namespace { QThreadStorage<int> creationDepth; @@ -774,7 +773,6 @@ QQmlComponent::QQmlComponent(QQmlComponentPrivate &dd, QObject *parent) QObject *QQmlComponent::create(QQmlContext *context) { Q_D(QQmlComponent); - QML_MEMORY_SCOPE_URL(url()); if (!context) context = d->engine->rootContext(); @@ -1206,7 +1204,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent) \js var component = Qt.createComponent("Button.qml"); if (component.status == Component.Ready) - component.createObject(parent, {"x": 100, "y": 100}); + component.createObject(parent, {x: 100, y: 100}); \endjs Dynamically created instances can be deleted with the \c destroy() method. diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index bd59409475..14892bd6ad 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -317,6 +317,12 @@ void QQmlContext::setContextProperty(const QString &name, const QVariant &value) d->propertyValues[idx] = value; QMetaObject::activate(this, d->notifyIndex, idx, nullptr); } + + if (auto *obj = qvariant_cast<QObject *>(value)) { + connect(obj, &QObject::destroyed, this, [d, name](QObject *destroyed) { + d->dropDestroyedQObject(name, destroyed); + }); + } } /*! @@ -524,6 +530,17 @@ QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, int ind } } +void QQmlContextPrivate::dropDestroyedQObject(const QString &name, QObject *destroyed) +{ + const int idx = data->propertyNames().value(name); + Q_ASSERT(idx >= 0); + if (qvariant_cast<QObject *>(propertyValues[idx]) != destroyed) + return; + + propertyValues[idx] = QVariant::fromValue<QObject *>(nullptr); + QMetaObject::activate(q_func(), notifyIndex, idx, nullptr); +} + QQmlContextData::QQmlContextData() : QQmlContextData(nullptr) diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h index 1ddd04c9ff..5f7316b00c 100644 --- a/src/qml/qml/qqmlcontext_p.h +++ b/src/qml/qml/qqmlcontext_p.h @@ -104,6 +104,8 @@ public: static int context_count(QQmlListProperty<QObject> *); static QObject *context_at(QQmlListProperty<QObject> *, int); + + void dropDestroyedQObject(const QString &name, QObject *destroyed); }; class QQmlComponentAttached; diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index 5cf87f5264..c477415ef7 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -100,7 +100,12 @@ void QQmlCustomParser::clearErrors() */ void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description) { - exceptions << QQmlCompileError(location, description); + QQmlJS::DiagnosticMessage error; + error.line = location.line; + error.column = location.column; + error.message = description; + + exceptions << error; } struct StaticQtMetaObject : public QObject diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h index c8e1300a1b..94671a4f35 100644 --- a/src/qml/qml/qqmlcustomparser_p.h +++ b/src/qml/qml/qqmlcustomparser_p.h @@ -83,7 +83,7 @@ public: virtual void verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) = 0; virtual void applyBindings(QObject *, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) = 0; - QVector<QQmlCompileError> errors() const { return exceptions; } + QVector<QQmlJS::DiagnosticMessage> errors() const { return exceptions; } protected: void error(const QV4::CompiledData::Binding *binding, const QString& description) @@ -97,7 +97,7 @@ protected: const QMetaObject *resolveType(const QString&) const; private: - QVector<QQmlCompileError> exceptions; + QVector<QQmlJS::DiagnosticMessage> exceptions; QQmlEnginePrivate *engine; const QQmlPropertyValidator *validator; Flags m_flags; diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 691eb987f6..4460312e2c 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -811,9 +811,9 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in // marshalled back onto the QObject's thread and handled by QML from there. This is tested // by the qqmlecmascript::threadSignal() autotest. if (ddata->notifyList && - QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId.load()) { + QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId.loadRelaxed()) { - if (!QObjectPrivate::get(object)->threadData->thread) + if (!QObjectPrivate::get(object)->threadData->thread.loadAcquire()) return; QMetaMethod m = QMetaObjectPrivate::signal(object->metaObject(), index); @@ -849,7 +849,7 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject; mpo->target = object; - mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread); + mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread.loadAcquire()); QCoreApplication::postEvent(mpo, ev); } else { @@ -1169,6 +1169,13 @@ void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index) } } +QSharedPointer<QQmlImageProviderBase> QQmlEnginePrivate::imageProvider(const QString &providerId) const +{ + const QString providerIdLower = providerId.toLower(); + QMutexLocker locker(&mutex); + return imageProviders.value(providerIdLower); +} + #if QT_CONFIG(qml_network) /*! Sets the \a factory to use for creating QNetworkAccessManager(s). @@ -1258,8 +1265,10 @@ QNetworkAccessManager *QQmlEngine::networkAccessManager() const void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider) { Q_D(QQmlEngine); + QString providerIdLower = providerId.toLower(); + QSharedPointer<QQmlImageProviderBase> sp(provider); QMutexLocker locker(&d->mutex); - d->imageProviders.insert(providerId.toLower(), QSharedPointer<QQmlImageProviderBase>(provider)); + d->imageProviders.insert(std::move(providerIdLower), std::move(sp)); } /*! @@ -1270,8 +1279,9 @@ void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBa QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) const { Q_D(const QQmlEngine); + const QString providerIdLower = providerId.toLower(); QMutexLocker locker(&d->mutex); - return d->imageProviders.value(providerId.toLower()).data(); + return d->imageProviders.value(providerIdLower).data(); } /*! @@ -1282,8 +1292,9 @@ QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) cons void QQmlEngine::removeImageProvider(const QString &providerId) { Q_D(QQmlEngine); + const QString providerIdLower = providerId.toLower(); QMutexLocker locker(&d->mutex); - d->imageProviders.take(providerId.toLower()); + d->imageProviders.take(providerIdLower); } /*! @@ -2109,15 +2120,15 @@ QList<QQmlError> QQmlEnginePrivate::qmlErrorFromDiagnostics(const QString &fileN QList<QQmlError> errors; for (const DiagnosticMessage &m : diagnosticMessages) { if (m.isWarning()) { - qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message)); + qWarning("%s:%d : %s", qPrintable(fileName), m.line, qPrintable(m.message)); continue; } QQmlError error; error.setUrl(QUrl(fileName)); error.setDescription(m.message); - error.setLine(m.loc.startLine); - error.setColumn(m.loc.startColumn); + error.setLine(m.line); + error.setColumn(m.column); errors << error; } return errors; @@ -2245,6 +2256,7 @@ void QQmlEngine::setPluginPathList(const QStringList &paths) d->importDatabase.setPluginPathList(paths); } +#if QT_CONFIG(library) /*! Imports the plugin named \a filePath with the \a uri provided. Returns true if the plugin was successfully imported; otherwise returns false. @@ -2258,6 +2270,7 @@ bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList Q_D(QQmlEngine); return d->importDatabase.importDynamicPlugin(filePath, uri, QString(), -1, errors); } +#endif /*! \property QQmlEngine::offlineStoragePath diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index da91c8fa15..31fe3a1849 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -114,7 +114,9 @@ public: bool addNamedBundle(const QString &name, const QString &fileName); +#if QT_CONFIG(library) bool importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors); +#endif #if QT_CONFIG(qml_network) void setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *); diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 3b716683fd..e58ff554a7 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -167,6 +167,8 @@ public: mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory; #endif QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders; + QSharedPointer<QQmlImageProviderBase> imageProvider(const QString &providerId) const; + QQmlAbstractUrlInterceptor* urlInterceptor; diff --git a/src/qml/qmldirparser/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp index 5e181f7e27..739d5ce4cd 100644 --- a/src/qml/qmldirparser/qqmlerror.cpp +++ b/src/qml/qml/qqmlerror.cpp @@ -39,16 +39,15 @@ #include "qqmlerror.h" #include "qqmlsourcecoordinate_p.h" +#include <private/qqmljsdiagnosticmessage_p.h> #include <QtCore/qdebug.h> #include <QtCore/qfile.h> #include <QtCore/qstringlist.h> #include <QtCore/qvector.h> -#ifndef QT_NO_QOBJECT #include <QtCore/qobject.h> #include <QtCore/qpointer.h> -#endif QT_BEGIN_NAMESPACE @@ -77,26 +76,14 @@ QT_BEGIN_NAMESPACE \sa QQuickView::errors(), QQmlComponent::errors() */ -class QQmlErrorPrivate +class QQmlErrorPrivate : public QQmlJS::DiagnosticMessage { public: - QQmlErrorPrivate(); - + QQmlErrorPrivate() { type = QtWarningMsg; } QUrl url; - QString description; - quint16 line; - quint16 column; - QtMsgType messageType; -#ifndef QT_NO_QOBJECT QPointer<QObject> object; -#endif }; -QQmlErrorPrivate::QQmlErrorPrivate() -: line(0), column(0), messageType(QtMsgType::QtWarningMsg) -{ -} - /*! Creates an empty error object. */ @@ -126,13 +113,11 @@ QQmlError &QQmlError::operator=(const QQmlError &other) if (!d) d = new QQmlErrorPrivate; d->url = other.d->url; - d->description = other.d->description; + d->message = other.d->message; d->line = other.d->line; d->column = other.d->column; -#ifndef QT_NO_QOBJECT d->object = other.d->object; -#endif - d->messageType = other.d->messageType; + d->type = other.d->type; } return *this; } @@ -179,7 +164,7 @@ void QQmlError::setUrl(const QUrl &url) QString QQmlError::description() const { if (d) - return d->description; + return d->message; return QString(); } @@ -190,7 +175,7 @@ void QQmlError::setDescription(const QString &description) { if (!d) d = new QQmlErrorPrivate; - d->description = description; + d->message = description; } /*! @@ -199,7 +184,7 @@ void QQmlError::setDescription(const QString &description) int QQmlError::line() const { if (d) - return qmlSourceCoordinate(d->line); + return qmlConvertSourceCoordinate<quint32, int>(d->line); return -1; } @@ -210,7 +195,7 @@ void QQmlError::setLine(int line) { if (!d) d = new QQmlErrorPrivate; - d->line = qmlSourceCoordinate(line); + d->line = qmlConvertSourceCoordinate<int, quint32>(line); } /*! @@ -219,7 +204,7 @@ void QQmlError::setLine(int line) int QQmlError::column() const { if (d) - return qmlSourceCoordinate(d->column); + return qmlConvertSourceCoordinate<quint32, int>(d->column); return -1; } @@ -230,10 +215,9 @@ void QQmlError::setColumn(int column) { if (!d) d = new QQmlErrorPrivate; - d->column = qmlSourceCoordinate(column); + d->column = qmlConvertSourceCoordinate<int, quint32>(column); } -#ifndef QT_NO_QOBJECT /*! Returns the nearest object where this error occurred. Exceptions in bound property expressions set this to the object @@ -256,7 +240,6 @@ void QQmlError::setObject(QObject *object) d = new QQmlErrorPrivate; d->object = object; } -#endif // QT_NO_QOBJECT /*! \since 5.9 @@ -266,7 +249,7 @@ void QQmlError::setObject(QObject *object) QtMsgType QQmlError::messageType() const { if (d) - return d->messageType; + return d->type; return QtMsgType::QtWarningMsg; } @@ -280,7 +263,7 @@ void QQmlError::setMessageType(QtMsgType messageType) { if (!d) d = new QQmlErrorPrivate; - d->messageType = messageType; + d->type = messageType; } /*! diff --git a/src/qml/qmldirparser/qqmlerror.h b/src/qml/qml/qqmlerror.h index f4221358e9..8ea493c11d 100644 --- a/src/qml/qmldirparser/qqmlerror.h +++ b/src/qml/qml/qqmlerror.h @@ -69,10 +69,8 @@ public: int column() const; void setColumn(int); -#ifndef QT_NO_QOBJECT QObject *object() const; void setObject(QObject *); -#endif QtMsgType messageType() const; void setMessageType(QtMsgType messageType); diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index 6a11583f18..be0adc54a7 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -351,7 +351,7 @@ QString QQmlExpression::sourceFile() const int QQmlExpression::lineNumber() const { Q_D(const QQmlExpression); - return qmlSourceCoordinate(d->line); + return qmlConvertSourceCoordinate<quint16, int>(d->line); } /*! @@ -361,7 +361,7 @@ int QQmlExpression::lineNumber() const int QQmlExpression::columnNumber() const { Q_D(const QQmlExpression); - return qmlSourceCoordinate(d->column); + return qmlConvertSourceCoordinate<quint16, int>(d->column); } /*! @@ -372,8 +372,8 @@ void QQmlExpression::setSourceLocation(const QString &url, int line, int column) { Q_D(QQmlExpression); d->url = url; - d->line = qmlSourceCoordinate(line); - d->column = qmlSourceCoordinate(column); + d->line = qmlConvertSourceCoordinate<int, quint16>(line); + d->column = qmlConvertSourceCoordinate<int, quint16>(column); } /*! diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 9d5801bbc6..95ab79070d 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -1020,13 +1020,6 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res return true; } -#if defined(QT_SHARED) || !QT_CONFIG(library) -static inline QString msgCannotLoadPlugin(const QString &uri, const QString &why) -{ - return QQmlImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri, why); -} -#endif - /* Import an extension defined by a qmldir file. @@ -1075,7 +1068,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, int dynamicPluginsFound = 0; int staticPluginsFound = 0; -#if defined(QT_SHARED) +#if QT_CONFIG(library) const auto qmldirPlugins = qmldir.plugins(); for (const QQmlDirParser::Plugin &plugin : qmldirPlugins) { QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name); @@ -1086,9 +1079,11 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, // XXX TODO: should we leave the import plugin error alone? // Here, we pop it off the top and coalesce it into this error's message. // The reason is that the lower level may add url and line/column numbering information. - QQmlError poppedError = errors->takeFirst(); QQmlError error; - error.setDescription(msgCannotLoadPlugin(uri, poppedError.description())); + error.setDescription( + QQmlImportDatabase::tr( + "plugin cannot be loaded for module \"%1\": %2") + .arg(uri, errors->takeFirst().description())); error.setUrl(QUrl::fromLocalFile(qmldirFilePath)); errors->prepend(error); } @@ -1096,7 +1091,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, } } } -#endif // QT_SHARED +#endif // QT_CONFIG(library) if (dynamicPluginsFound < qmldirPluginCount) { // Check if the missing plugins can be resolved statically. We do this by looking at @@ -2020,13 +2015,13 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba return true; } +#if QT_CONFIG(library) /*! \internal */ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QString &uri, const QString &typeNamespace, int vmaj, QList<QQmlError> *errors) { -#if QT_CONFIG(library) QFileInfo fileInfo(filePath); const QString absoluteFilePath = fileInfo.absoluteFilePath(); @@ -2104,16 +2099,10 @@ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QStr } return true; -#else - Q_UNUSED(filePath); - Q_UNUSED(uri); - Q_UNUSED(typeNamespace); - Q_UNUSED(vmaj); - Q_UNUSED(errors); - return false; -#endif } +#endif // QT_CONFIG(library) + void QQmlImportDatabase::clearDirCache() { QStringHash<QmldirCache *>::ConstIterator itr = qmldirCache.constBegin(); diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index d3055b552c..ea9c2eafb5 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -44,6 +44,7 @@ #include <QtCore/qcoreapplication.h> #include <QtCore/qset.h> #include <QtCore/qstringlist.h> +#include <QtQml/qqmlerror.h> #include <private/qqmldirparser_p.h> #include <private/qqmltype_p.h> #include <private/qstringhash_p.h> @@ -211,7 +212,9 @@ public: QQmlImportDatabase(QQmlEngine *); ~QQmlImportDatabase(); +#if QT_CONFIG(library) bool importDynamicPlugin(const QString &filePath, const QString &uri, const QString &importNamespace, int vmaj, QList<QQmlError> *errors); +#endif QStringList importPathList(PathType type = LocalOrRemote) const; void setImportPathList(const QStringList &paths); diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp index 39da550d63..bc06226cbf 100644 --- a/src/qml/qml/qqmlincubator.cpp +++ b/src/qml/qml/qqmlincubator.cpp @@ -42,7 +42,6 @@ #include "qqmlincubator_p.h" #include "qqmlexpression_p.h" -#include "qqmlmemoryprofiler_p.h" #include "qqmlobjectcreator_p.h" void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext) @@ -272,8 +271,6 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i) if (!compilationUnit) return; - QML_MEMORY_SCOPE_URL(compilationUnit->finalUrl()); - QExplicitlySharedDataPointer<QQmlIncubatorPrivate> protectThis(this); QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(this); diff --git a/src/qml/qml/qqmlirloader_p.h b/src/qml/qml/qqmlirloader_p.h index aa303c923f..4812946ef0 100644 --- a/src/qml/qml/qqmlirloader_p.h +++ b/src/qml/qml/qqmlirloader_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qtqmlglobal_p.h> #include <private/qv4compileddata_p.h> #include <private/qqmljsmemorypool_p.h> diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index a5b92d14f7..67fdf8847b 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -107,7 +107,7 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el d->version_maj = type.versionMajor; d->version_min = type.versionMinor; - if (type.qobjectApi) { + if (type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi)) { if (type.version >= 1) // static metaobject added in version 1 d->baseMetaObject = type.instanceMetaObject; if (type.version >= 2) // typeId added in version 2 @@ -118,10 +118,14 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo; d->extraData.sd->singletonInstanceInfo->scriptCallback = type.scriptApi; - d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi; + if (type.version >= 3) { + d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.generalizedQobjectApi; + } else { + d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi; + } d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName); d->extraData.sd->singletonInstanceInfo->instanceMetaObject - = (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : nullptr; + = ((type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi) ) && type.version >= 1) ? type.instanceMetaObject : nullptr; return d; } @@ -281,7 +285,7 @@ void QQmlMetaType::clearTypeRegistrations() data->undeletableTypes.clear(); } -int QQmlMetaType::registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent) +int QQmlMetaType::registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &autoparent) { QQmlMetaTypeDataPtr data; @@ -290,6 +294,12 @@ int QQmlMetaType::registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &au return data->parentFunctions.count() - 1; } +void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function) +{ + QQmlMetaTypeDataPtr data; + data->parentFunctions.removeOne(function); +} + QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &type) { if (type.version > 0) @@ -1193,7 +1203,8 @@ QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVe void QQmlMetaType::unregisterType(int typeIndex) { QQmlMetaTypeDataPtr data; - if (const QQmlTypePrivate *d = data->types.value(typeIndex).priv()) { + const QQmlType type = data->types.value(typeIndex); + if (const QQmlTypePrivate *d = type.priv()) { removeQQmlTypePrivate(data->idToType, d); removeQQmlTypePrivate(data->nameToType, d); removeQQmlTypePrivate(data->urlToType, d); @@ -1203,6 +1214,7 @@ void QQmlMetaType::unregisterType(int typeIndex) module->remove(d); data->clearPropertyCachesForMinorVersion(typeIndex); data->types[typeIndex] = QQmlType(); + data->undeletableTypes.remove(type); } } @@ -1324,7 +1336,7 @@ const QV4::CompiledData::Unit *QQmlMetaType::findCachedCompilationUnit(const QUr for (const auto lookup : qAsConst(data->lookupCachedQmlUnit)) { if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri)) { QString error; - if (!unit->qmlData->verifyHeader(QDateTime(), &error)) { + if (!QV4::ExecutableCompilationUnit::verifyHeader(unit->qmlData, QDateTime(), &error)) { qCDebug(DBG_DISK_CACHE) << "Error loading pre-compiled file " << uri << ":" << error; if (status) *status = CachedUnitLookupError::VersionMismatch; diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 911e519cf2..c2535a7fd5 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -176,7 +176,9 @@ public: } } - static int registerAutoParentFunction(QQmlPrivate::RegisterAutoParent &autoparent); + static int registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &autoparent); + static void unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function); + static int registerUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration); static void clearTypeRegistrations(); diff --git a/src/qml/qml/qqmlnotifier.cpp b/src/qml/qml/qqmlnotifier.cpp index 0706b8c0cf..1359586b31 100644 --- a/src/qml/qml/qqmlnotifier.cpp +++ b/src/qml/qml/qqmlnotifier.cpp @@ -118,8 +118,8 @@ void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine disconnect(); Q_ASSERT(engine); - if (QObjectPrivate::get(source)->threadData->threadId.load() != - QObjectPrivate::get(engine)->threadData->threadId.load()) { + if (QObjectPrivate::get(source)->threadData->threadId.loadRelaxed() != + QObjectPrivate::get(engine)->threadData->threadId.loadRelaxed()) { QString sourceName; QDebug(&sourceName) << source; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index e5f376fd34..be40eeb58a 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -939,7 +939,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper auto bindingTarget = _bindingTarget; auto valueTypeProperty = _valueTypeProperty; - auto assignBinding = [qmlBinding, bindingTarget, targetProperty, subprop, bindingProperty, valueTypeProperty](QQmlObjectCreatorSharedState *sharedState) -> bool { + auto assignBinding = [qmlBinding, bindingTarget, targetProperty, subprop, bindingProperty, valueTypeProperty](QQmlObjectCreatorSharedState *sharedState) mutable -> bool { if (!qmlBinding->setTarget(bindingTarget, *targetProperty, subprop) && targetProperty->isAlias()) return false; @@ -1384,7 +1384,8 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru QQmlPropertyData::DontRemoveBinding); if (!b->isValueTypeProxy()) { QQmlBinding *binding = static_cast<QQmlBinding*>(b.data()); - if (!binding->hasError() && !binding->hasDependencies()) + if (!binding->hasError() && !binding->hasDependencies() + && binding->context() && !binding->context()->unresolvedNames) b->removeFromObject(); } diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 0766e2082e..1cbad87920 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -94,14 +94,14 @@ public: QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt); void clear(); - QQmlComponentAttached **componentAttachment() const { return &sharedState->componentAttached; } + QQmlComponentAttached **componentAttachment() { return &sharedState->componentAttached; } - QList<QQmlEnginePrivate::FinalizeCallback> *finalizeCallbacks() const { return &sharedState->finalizeCallbacks; } + QList<QQmlEnginePrivate::FinalizeCallback> *finalizeCallbacks() { return &sharedState->finalizeCallbacks; } QList<QQmlError> errors; QQmlContextData *parentContextData() const { return parentContext.contextData(); } - QFiniteStack<QPointer<QObject> > &allCreatedObjects() const { return sharedState->allCreatedObjects; } + QFiniteStack<QPointer<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; } private: QQmlObjectCreator(QQmlContextData *contextData, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState); diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index ae84803648..eff78195d9 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -51,6 +51,8 @@ // We mean it. // +#include <functional> + #include <QtQml/qtqmlglobal.h> #include <QtCore/qglobal.h> @@ -276,6 +278,7 @@ namespace QQmlPrivate const QMetaObject *instanceMetaObject; // new in version 1 int typeId; // new in version 2 int revision; // new in version 2 + std::function<QObject*(QQmlEngine *, QJSEngine *)> generalizedQobjectApi; // new in version 3 // If this is extended ensure "version" is bumped!!! }; @@ -318,6 +321,7 @@ namespace QQmlPrivate }; int Q_QML_EXPORT qmlregister(RegistrationType, void *); + void Q_QML_EXPORT qmlunregister(RegistrationType, quintptr); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp index bd4f2a0612..034ebfc743 100644 --- a/src/qml/qml/qqmlpropertycachecreator.cpp +++ b/src/qml/qml/qqmlpropertycachecreator.cpp @@ -45,6 +45,35 @@ QT_BEGIN_NAMESPACE QAtomicInt QQmlPropertyCacheCreatorBase::classIndexCounter(0); + +int QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(QV4::CompiledData::BuiltinType type) +{ + switch (type) { + case QV4::CompiledData::BuiltinType::Var: return QMetaType::QVariant; + case QV4::CompiledData::BuiltinType::Variant: return QMetaType::QVariant; + case QV4::CompiledData::BuiltinType::Int: return QMetaType::Int; + case QV4::CompiledData::BuiltinType::Bool: return QMetaType::Bool; + case QV4::CompiledData::BuiltinType::Real: return QMetaType::Double; + case QV4::CompiledData::BuiltinType::String: return QMetaType::QString; + case QV4::CompiledData::BuiltinType::Url: return QMetaType::QUrl; + case QV4::CompiledData::BuiltinType::Color: return QMetaType::QColor; + case QV4::CompiledData::BuiltinType::Font: return QMetaType::QFont; + case QV4::CompiledData::BuiltinType::Time: return QMetaType::QTime; + case QV4::CompiledData::BuiltinType::Date: return QMetaType::QDate; + case QV4::CompiledData::BuiltinType::DateTime: return QMetaType::QDateTime; + case QV4::CompiledData::BuiltinType::Rect: return QMetaType::QRectF; + case QV4::CompiledData::BuiltinType::Point: return QMetaType::QPointF; + case QV4::CompiledData::BuiltinType::Size: return QMetaType::QSizeF; + case QV4::CompiledData::BuiltinType::Vector2D: return QMetaType::QVector2D; + case QV4::CompiledData::BuiltinType::Vector3D: return QMetaType::QVector3D; + case QV4::CompiledData::BuiltinType::Vector4D: return QMetaType::QVector4D; + case QV4::CompiledData::BuiltinType::Matrix4x4: return QMetaType::QMatrix4x4; + case QV4::CompiledData::BuiltinType::Quaternion: return QMetaType::QQuaternion; + case QV4::CompiledData::BuiltinType::InvalidBuiltin: break; + }; + return QMetaType::UnknownType; +} + QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding, const QString &instantiatingPropertyName, QQmlPropertyCache *referencingObjectPropertyCache) : referencingObjectIndex(referencingObjectIndex) diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h index 28eea27675..14f734277d 100644 --- a/src/qml/qml/qqmlpropertycachecreator_p.h +++ b/src/qml/qml/qqmlpropertycachecreator_p.h @@ -84,6 +84,8 @@ struct QQmlPropertyCacheCreatorBase Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreatorBase) public: static QAtomicInt classIndexCounter; + + static int metaTypeForPropertyType(QV4::CompiledData::BuiltinType type); }; template <typename ObjectContainer> @@ -97,12 +99,12 @@ public: QQmlEnginePrivate *enginePrivate, const ObjectContainer *objectContainer, const QQmlImports *imports); - QQmlCompileError buildMetaObjects(); + QQmlJS::DiagnosticMessage buildMetaObjects(); protected: - QQmlCompileError buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context); - QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const; - QQmlCompileError createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache); + QQmlJS::DiagnosticMessage buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context); + QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlJS::DiagnosticMessage *error) const; + QQmlJS::DiagnosticMessage createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache); QString stringAt(int index) const { return objectContainer->stringAt(index); } @@ -128,14 +130,14 @@ inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlP } template <typename ObjectContainer> -inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects() +inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects() { QQmlBindingInstantiationContext context; return buildMetaObjectRecursively(/*root object*/0, context); } template <typename ObjectContainer> -inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context) +inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context) { const CompiledObject *obj = objectContainer->objectAt(objectIndex); @@ -155,8 +157,8 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObje auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); QQmlRefPointer<QQmlPropertyCache> baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); - QQmlCompileError error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache); - if (error.isSet()) + QQmlJS::DiagnosticMessage error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache); + if (error.isValid()) return error; } } else { @@ -170,16 +172,16 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObje QQmlRefPointer<QQmlPropertyCache> baseTypeCache; { - QQmlCompileError error; + QQmlJS::DiagnosticMessage error; baseTypeCache = propertyCacheForObject(obj, context, &error); - if (error.isSet()) + if (error.isValid()) return error; } if (baseTypeCache) { if (needVMEMetaObject) { - QQmlCompileError error = createMetaObject(objectIndex, obj, baseTypeCache); - if (error.isSet()) + QQmlJS::DiagnosticMessage error = createMetaObject(objectIndex, obj, baseTypeCache); + if (error.isValid()) return error; } else { propertyCaches->set(objectIndex, baseTypeCache); @@ -200,18 +202,18 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObje if (!context.resolveInstantiatingProperty()) pendingGroupPropertyBindings->append(context); - QQmlCompileError error = buildMetaObjectRecursively(binding->value.objectIndex, context); - if (error.isSet()) + QQmlJS::DiagnosticMessage error = buildMetaObjectRecursively(binding->value.objectIndex, context); + if (error.isValid()) return error; } } - QQmlCompileError noError; + QQmlJS::DiagnosticMessage noError; return noError; } template <typename ObjectContainer> -inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const +inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlJS::DiagnosticMessage *error) const { if (context.instantiatingProperty) { return context.instantiatingPropertyCache(enginePrivate); @@ -221,15 +223,15 @@ inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContaine if (typeRef->isFullyDynamicType) { if (obj->propertyCount() > 0 || obj->aliasCount() > 0) { - *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new properties.")); + *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new properties.")); return nullptr; } if (obj->signalCount() > 0) { - *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new signals.")); + *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new signals.")); return nullptr; } if (obj->functionCount() > 0) { - *error = QQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully Dynamic types cannot declare new functions.")); + *error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully Dynamic types cannot declare new functions.")); return nullptr; } } @@ -256,7 +258,7 @@ inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContaine const QMetaObject *attachedMo = qmltype.attachedPropertiesType(enginePrivate); if (!attachedMo) { - *error = QQmlCompileError(context.instantiatingBinding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object")); + *error = qQmlCompileError(context.instantiatingBinding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object")); return nullptr; } return enginePrivate->cache(attachedMo); @@ -265,7 +267,7 @@ inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContaine } template <typename ObjectContainer> -inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache) +inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache) { QQmlRefPointer<QQmlPropertyCache> cache; cache.adopt(baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(), @@ -275,33 +277,6 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj propertyCaches->set(objectIndex, cache); propertyCaches->setNeedsVMEMetaObject(objectIndex); - struct TypeData { - QV4::CompiledData::Property::Type dtype; - int metaType; - } builtinTypes[] = { - { QV4::CompiledData::Property::Var, QMetaType::QVariant }, - { QV4::CompiledData::Property::Variant, QMetaType::QVariant }, - { QV4::CompiledData::Property::Int, QMetaType::Int }, - { QV4::CompiledData::Property::Bool, QMetaType::Bool }, - { QV4::CompiledData::Property::Real, QMetaType::Double }, - { QV4::CompiledData::Property::String, QMetaType::QString }, - { QV4::CompiledData::Property::Url, QMetaType::QUrl }, - { QV4::CompiledData::Property::Color, QMetaType::QColor }, - { QV4::CompiledData::Property::Font, QMetaType::QFont }, - { QV4::CompiledData::Property::Time, QMetaType::QTime }, - { QV4::CompiledData::Property::Date, QMetaType::QDate }, - { QV4::CompiledData::Property::DateTime, QMetaType::QDateTime }, - { QV4::CompiledData::Property::Rect, QMetaType::QRectF }, - { QV4::CompiledData::Property::Point, QMetaType::QPointF }, - { QV4::CompiledData::Property::Size, QMetaType::QSizeF }, - { QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D }, - { QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D }, - { QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D }, - { QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 }, - { QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion } -}; - static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData); - QByteArray newClassName; if (objectIndex == /*root object*/0) { @@ -329,13 +304,13 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj auto p = obj->propertiesBegin(); auto pend = obj->propertiesEnd(); for ( ; p != pend; ++p) { - if (p->type == QV4::CompiledData::Property::Var) + if (p->builtinType() == QV4::CompiledData::BuiltinType::Var) varPropCount++; bool notInRevision = false; QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), ¬InRevision); if (d && d->isFinal()) - return QQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property")); + return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property")); } auto a = obj->aliasesBegin(); @@ -344,7 +319,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj bool notInRevision = false; QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), ¬InRevision); if (d && d->isFinal()) - return QQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property")); + return qQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property")); } int effectivePropertyIndex = cache->propertyIndexCacheStart; @@ -429,16 +404,15 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj auto end = s->parametersEnd(); for ( ; param != end; ++param, ++i) { names.append(stringAt(param->nameIndex).toUtf8()); - if (param->type < builtinTypeCount) { + if (param->indexIsBuiltinType) { // built-in type - paramTypes[i + 1] = builtinTypes[param->type].metaType; + paramTypes[i + 1] = metaTypeForPropertyType(static_cast<QV4::CompiledData::BuiltinType>(int(param->typeNameIndexOrBuiltinType))); } else { // lazily resolved type - Q_ASSERT(param->type == QV4::CompiledData::Property::Custom); - const QString customTypeName = stringAt(param->customTypeNameIndex); + const QString customTypeName = stringAt(param->typeNameIndexOrBuiltinType); QQmlType qmltype; if (!imports->resolveType(customTypeName, &qmltype, nullptr, nullptr, nullptr)) - return QQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName)); + return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName)); if (qmltype.isComposite()) { QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl()); @@ -461,7 +435,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj QString signalName = stringAt(s->nameIndex); if (seenSignals.contains(signalName)) - return QQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Duplicate signal name: invalid override of property change signal or superclass signal")); + return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Duplicate signal name: invalid override of property change signal or superclass signal")); seenSignals.insert(signalName); cache->appendSignal(signalName, flags, effectiveMethodIndex++, @@ -477,7 +451,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj const QString slotName = stringAt(function->nameIndex); if (seenSignals.contains(slotName)) - return QQmlCompileError(function->location, QQmlPropertyCacheCreatorBase::tr("Duplicate method name: invalid override of property change signal or superclass signal")); + return qQmlCompileError(function->location, QQmlPropertyCacheCreatorBase::tr("Duplicate method name: invalid override of property change signal or superclass signal")); // Note: we don't append slotName to the seenSignals list, since we don't // protect against overriding change signals or methods with properties. @@ -503,21 +477,23 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj int propertTypeMinorVersion = 0; QQmlPropertyData::Flags propertyFlags; - if (p->type == QV4::CompiledData::Property::Var) { - propertyType = QMetaType::QVariant; + const QV4::CompiledData::BuiltinType type = p->builtinType(); + + if (type == QV4::CompiledData::BuiltinType::Var) propertyFlags.type = QQmlPropertyData::Flags::VarPropertyType; - } else if (p->type < builtinTypeCount) { - propertyType = builtinTypes[p->type].metaType; - if (p->type == QV4::CompiledData::Property::Variant) + + if (type != QV4::CompiledData::BuiltinType::InvalidBuiltin) { + propertyType = metaTypeForPropertyType(type); + + if (type == QV4::CompiledData::BuiltinType::Variant) propertyFlags.type = QQmlPropertyData::Flags::QVariantType; } else { - Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList || - p->type == QV4::CompiledData::Property::Custom); + Q_ASSERT(!p->isBuiltinType); QQmlType qmltype; - if (!imports->resolveType(stringAt(p->customTypeNameIndex), &qmltype, nullptr, nullptr, nullptr)) { - return QQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type")); + if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex), &qmltype, nullptr, nullptr, nullptr)) { + return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type")); } Q_ASSERT(qmltype.isValid()); @@ -528,27 +504,27 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj auto compilationUnit = tdata->compilationUnit(); - if (p->type == QV4::CompiledData::Property::Custom) { - propertyType = compilationUnit->metaTypeId; - } else { + if (p->isList) { propertyType = compilationUnit->listMetaTypeId; + } else { + propertyType = compilationUnit->metaTypeId; } } else { - if (p->type == QV4::CompiledData::Property::Custom) { + if (p->isList) { + propertyType = qmltype.qListTypeId(); + } else { propertyType = qmltype.typeId(); propertTypeMinorVersion = qmltype.minorVersion(); - } else { - propertyType = qmltype.qListTypeId(); } } - if (p->type == QV4::CompiledData::Property::Custom) - propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType; - else + if (p->isList) propertyFlags.type = QQmlPropertyData::Flags::QListType; + else + propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType; } - if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList) + if (!p->isReadOnly && !p->isList) propertyFlags.isWritable = true; @@ -561,7 +537,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj effectiveSignalIndex++; } - QQmlCompileError noError; + QQmlJS::DiagnosticMessage noError; return noError; } @@ -575,11 +551,11 @@ public: void appendAliasPropertiesToMetaObjects(); - QQmlCompileError appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex); + QQmlJS::DiagnosticMessage appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex); private: void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex); - QQmlCompileError propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *rev, QQmlPropertyData::Flags *propertyFlags); + QQmlJS::DiagnosticMessage propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *rev, QQmlPropertyData::Flags *propertyFlags); void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const; @@ -690,7 +666,7 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAl } template <typename ObjectContainer> -inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias( +inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias( const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *minorVersion, QQmlPropertyData::Flags *propertyFlags) { @@ -716,7 +692,7 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::property const QV4::CompiledData::Alias *targetAlias = &(*nextAlias); if (seenAliases.contains(targetAlias)) { - return QQmlCompileError(targetAlias->location, + return qQmlCompileError(targetAlias->location, QQmlPropertyCacheCreatorBase::tr("Cyclic alias")); } @@ -738,7 +714,8 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::property // Can be caused by the alias target not being a valid id or property. E.g.: // property alias dataValue: dataVal // invalidAliasComponent { id: dataVal } - return QQmlCompileError(targetObject.location, QQmlPropertyCacheCreatorBase::tr("Invalid alias target")); + return qQmlCompileError(targetObject.location, + QQmlPropertyCacheCreatorBase::tr("Invalid alias target")); } if (typeRef->type.isValid()) @@ -782,18 +759,18 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::property } } - propertyFlags->isWritable = !(alias.flags & QV4::CompiledData::Property::IsReadOnly) && writable; + propertyFlags->isWritable = !(alias.flags & QV4::CompiledData::Alias::IsReadOnly) && writable; propertyFlags->isResettable = resettable; - return QQmlCompileError(); + return QQmlJS::DiagnosticMessage(); } template <typename ObjectContainer> -inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache( +inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache( const CompiledObject &component, int objectIndex) { const CompiledObject &object = *objectContainer->objectAt(objectIndex); if (!object.aliasCount()) - return QQmlCompileError(); + return QQmlJS::DiagnosticMessage(); QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex); Q_ASSERT(propertyCache); @@ -810,8 +787,8 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAl int type = 0; int minorVersion = 0; QQmlPropertyData::Flags propertyFlags; - QQmlCompileError error = propertyDataForAlias(component, *alias, &type, &minorVersion, &propertyFlags); - if (error.isSet()) + QQmlJS::DiagnosticMessage error = propertyDataForAlias(component, *alias, &type, &minorVersion, &propertyFlags); + if (error.isValid()) return error; const QString propertyName = objectContainer->stringAt(alias->nameIndex); @@ -823,7 +800,7 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAl type, minorVersion, effectiveSignalIndex++); } - return QQmlCompileError(); + return QQmlJS::DiagnosticMessage(); } template <typename ObjectContainer> diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp index 71d5318652..6bb00e438d 100644 --- a/src/qml/qml/qqmlpropertyvalidator.cpp +++ b/src/qml/qml/qqmlpropertyvalidator.cpp @@ -57,7 +57,7 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, c bindingPropertyDataPerObject->resize(compilationUnit->objectCount()); } -QVector<QQmlCompileError> QQmlPropertyValidator::validate() +QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validate() { return validateObject(/*root object*/0, /*instantiatingBinding*/nullptr); } @@ -80,7 +80,8 @@ struct BindingFinder } }; -QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const +QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject( + int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const { const QV4::CompiledData::Object *obj = compilationUnit->objectAt(objectIndex); @@ -93,7 +94,7 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex); if (!propertyCache) - return QVector<QQmlCompileError>(); + return QVector<QQmlJS::DiagnosticMessage>(); QQmlCustomParser *customParser = nullptr; if (auto typeRef = resolvedType(obj->inheritedTypeNameIndex)) { @@ -203,7 +204,7 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, = pd && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType()) && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment); - const QVector<QQmlCompileError> subObjectValidatorErrors + const QVector<QQmlJS::DiagnosticMessage> subObjectValidatorErrors = validateObject(binding->value.objectIndex, binding, populatingValueTypeGroupProperty); if (!subObjectValidatorErrors.isEmpty()) @@ -260,12 +261,12 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, } if (binding->type < QV4::CompiledData::Binding::Type_Script) { - QQmlCompileError bindingError = validateLiteralBinding(propertyCache, pd, binding); - if (bindingError.isSet()) + QQmlJS::DiagnosticMessage bindingError = validateLiteralBinding(propertyCache, pd, binding); + if (bindingError.isValid()) return recordError(bindingError); } else if (binding->type == QV4::CompiledData::Binding::Type_Object) { - QQmlCompileError bindingError = validateObjectBinding(pd, name, binding); - if (bindingError.isSet()) + QQmlJS::DiagnosticMessage bindingError = validateObjectBinding(pd, name, binding); + if (bindingError.isValid()) return recordError(bindingError); } else if (binding->isGroupProperty()) { if (QQmlValueTypeFactory::isValueType(pd->propType())) { @@ -316,24 +317,24 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, customParser->validator = nullptr; customParser->engine = nullptr; customParser->imports = (QQmlImports*)nullptr; - QVector<QQmlCompileError> parserErrors = customParser->errors(); + QVector<QQmlJS::DiagnosticMessage> parserErrors = customParser->errors(); if (!parserErrors.isEmpty()) return parserErrors; } (*bindingPropertyDataPerObject)[objectIndex] = collectedBindingPropertyData; - QVector<QQmlCompileError> noError; + QVector<QQmlJS::DiagnosticMessage> noError; return noError; } -QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const +QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const { if (property->isQList()) { - return QQmlCompileError(binding->valueLocation, tr("Cannot assign primitives to lists")); + return qQmlCompileError(binding->valueLocation, tr("Cannot assign primitives to lists")); } - QQmlCompileError noError; + QQmlJS::DiagnosticMessage noError; if (property->isEnum()) { if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum) @@ -348,7 +349,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache p.enumerator().keyToValue(value.toUtf8().constData(), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration")); + return qQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration")); } return noError; } @@ -365,7 +366,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache enginePrivate->warning(warning); return noError; } - return QQmlCompileError(binding->valueLocation, error); + return qQmlCompileError(binding->valueLocation, error); }; switch (property->propType()) { @@ -629,23 +630,23 @@ bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const return false; } -QVector<QQmlCompileError> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const +QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const { - QVector<QQmlCompileError> errors; - errors.append(QQmlCompileError(location, description)); + QVector<QQmlJS::DiagnosticMessage> errors; + errors.append(qQmlCompileError(location, description)); return errors; } -QVector<QQmlCompileError> QQmlPropertyValidator::recordError(const QQmlCompileError &error) const +QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::recordError(const QQmlJS::DiagnosticMessage &error) const { - QVector<QQmlCompileError> errors; + QVector<QQmlJS::DiagnosticMessage> errors; errors.append(error); return errors; } -QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const +QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const { - QQmlCompileError noError; + QQmlJS::DiagnosticMessage noError; if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object); @@ -669,7 +670,7 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData * } if (!isValueSource && !isPropertyInterceptor) { - return QQmlCompileError(binding->valueLocation, tr("\"%1\" cannot operate on \"%2\"").arg(stringAt(targetObject->inheritedTypeNameIndex)).arg(propertyName)); + return qQmlCompileError(binding->valueLocation, tr("\"%1\" cannot operate on \"%2\"").arg(stringAt(targetObject->inheritedTypeNameIndex)).arg(propertyName)); } return noError; @@ -687,7 +688,7 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData * if (!QQmlMetaType::isInterface(listType)) { QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex); if (!canCoerce(listType, source)) { - return QQmlCompileError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName)); + return qQmlCompileError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName)); } } return noError; @@ -695,11 +696,11 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData * return noError; } else if (QQmlValueTypeFactory::isValueType(property->propType())) { auto typeName = QMetaType::typeName(property->propType()); - return QQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting an object") + return qQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting an object") .arg(typeName ? QString::fromLatin1(typeName) : QString::fromLatin1("<unknown type>")) .arg(propertyName)); } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected")); + return qQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected")); } else { // We want to use the raw metaObject here as the raw metaobject is the // actual property type before we applied any extensions that might @@ -719,7 +720,7 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData * } if (!isAssignable) { - return QQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.") + return qQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.") .arg(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex)).arg(QLatin1String(QMetaType::typeName(property->propType())))); } } diff --git a/src/qml/qml/qqmlpropertyvalidator_p.h b/src/qml/qml/qqmlpropertyvalidator_p.h index 8244b2df21..f2b892e978 100644 --- a/src/qml/qml/qqmlpropertyvalidator_p.h +++ b/src/qml/qml/qqmlpropertyvalidator_p.h @@ -60,17 +60,25 @@ class QQmlPropertyValidator public: QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit); - QVector<QQmlCompileError> validate(); + QVector<QQmlJS::DiagnosticMessage> validate(); private: - QVector<QQmlCompileError> validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false) const; - QQmlCompileError validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const; - QQmlCompileError validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const; + QVector<QQmlJS::DiagnosticMessage> validateObject( + int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, + bool populatingValueTypeGroupProperty = false) const; + QQmlJS::DiagnosticMessage validateLiteralBinding( + QQmlPropertyCache *propertyCache, QQmlPropertyData *property, + const QV4::CompiledData::Binding *binding) const; + QQmlJS::DiagnosticMessage validateObjectBinding( + QQmlPropertyData *property, const QString &propertyName, + const QV4::CompiledData::Binding *binding) const; bool canCoerce(int to, QQmlPropertyCache *fromMo) const; - Q_REQUIRED_RESULT QVector<QQmlCompileError> recordError(const QV4::CompiledData::Location &location, const QString &description) const; - Q_REQUIRED_RESULT QVector<QQmlCompileError> recordError(const QQmlCompileError &error) const; + Q_REQUIRED_RESULT QVector<QQmlJS::DiagnosticMessage> recordError( + const QV4::CompiledData::Location &location, const QString &description) const; + Q_REQUIRED_RESULT QVector<QQmlJS::DiagnosticMessage> recordError( + const QQmlJS::DiagnosticMessage &error) const; QString stringAt(int index) const { return compilationUnit->stringAt(index); } QV4::ResolvedTypeReference *resolvedType(int id) const { diff --git a/src/qml/qml/qqmlsourcecoordinate_p.h b/src/qml/qml/qqmlsourcecoordinate_p.h new file mode 100644 index 0000000000..55e11fd147 --- /dev/null +++ b/src/qml/qml/qqmlsourcecoordinate_p.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLSOURCECOORDINATE_P_H +#define QQMLSOURCECOORDINATE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +#include <limits> + +QT_BEGIN_NAMESPACE + +// These methods are needed because in some public methods we historically interpret -1 as the +// invalid line or column, even though all the lines and columns are 1-based. Also, the different +// integer ranges may turn certain large values into invalid ones on conversion. + +template<typename From, typename To> +To qmlConvertSourceCoordinate(From n); + +template<> +inline quint16 qmlConvertSourceCoordinate<int, quint16>(int n) +{ + return (n > 0 && n <= int(std::numeric_limits<quint16>::max())) ? quint16(n) : 0; +} + +template<> +inline quint32 qmlConvertSourceCoordinate<int, quint32>(int n) +{ + return n > 0 ? quint32(n) : 0u; +} + +// TODO: In Qt6, change behavior and make the invalid coordinate 0 for the following two methods. + +template<> +inline int qmlConvertSourceCoordinate<quint16, int>(quint16 n) +{ + return (n == 0u) ? -1 : int(n); +} + +template<> +inline int qmlConvertSourceCoordinate<quint32, int>(quint32 n) +{ + return (n == 0u || n > quint32(std::numeric_limits<int>::max())) ? -1 : int(n); +} + +QT_END_NAMESPACE + +#endif // QQMLSOURCECOORDINATE_P_H diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h index 1d65a08c8f..158fefad2c 100644 --- a/src/qml/qml/qqmltype_p.h +++ b/src/qml/qml/qqmltype_p.h @@ -51,6 +51,8 @@ // We mean it. // +#include <functional> + #include <private/qtqmlglobal_p.h> #include <private/qqmlrefcount_p.h> @@ -145,7 +147,7 @@ public: struct Q_QML_PRIVATE_EXPORT SingletonInstanceInfo { QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *) = nullptr; - QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *) = nullptr; + std::function<QObject *(QQmlEngine *, QJSEngine *)> qobjectCallback = {}; const QMetaObject *instanceMetaObject = nullptr; QString typeName; QUrl url; // used by composite singletons diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp index 66320b8db9..6cbe81b4b8 100644 --- a/src/qml/qml/qqmltypecompiler.cpp +++ b/src/qml/qml/qqmltypecompiler.cpp @@ -83,8 +83,8 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile() { QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, &pendingGroupPropertyBindings, engine, this, imports()); - QQmlCompileError error = propertyCacheBuilder.buildMetaObjects(); - if (error.isSet()) { + QQmlJS::DiagnosticMessage error = propertyCacheBuilder.buildMetaObjects(); + if (error.isValid()) { recordError(error); return nullptr; } @@ -173,12 +173,6 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile() return nullptr; } -void QQmlTypeCompiler::recordError(QQmlError error) -{ - error.setUrl(url()); - errors << error; -} - void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description) { QQmlError error; @@ -189,9 +183,14 @@ void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, errors << error; } -void QQmlTypeCompiler::recordError(const QQmlCompileError &error) +void QQmlTypeCompiler::recordError(const QQmlJS::DiagnosticMessage &message) { - recordError(error.location, error.description); + QQmlError error; + error.setDescription(message.message); + error.setLine(message.line); + error.setColumn(message.column); + error.setUrl(url()); + errors << error; } QString QQmlTypeCompiler::stringAt(int idx) const @@ -1020,17 +1019,17 @@ bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex) for (int objectIndex: qAsConst(_objectsWithAliases)) { - QQmlCompileError error; + QQmlJS::DiagnosticMessage error; const auto result = resolveAliasesInObject(objectIndex, &error); - if (error.isSet()) { + if (error.isValid()) { recordError(error); return false; } if (result == AllAliasesResolved) { - QQmlCompileError error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex); - if (error.isSet()) { + QQmlJS::DiagnosticMessage error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex); + if (error.isValid()) { recordError(error); return false; } @@ -1058,7 +1057,9 @@ bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex) return true; } -QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, QQmlCompileError *error) +QQmlComponentAndAliasResolver::AliasResolutionResult +QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, + QQmlJS::DiagnosticMessage *error) { const QmlIR::Object * const obj = qmlObjects->at(objectIndex); if (!obj->aliasCount()) @@ -1076,7 +1077,9 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv const int idIndex = alias->idIndex; const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1); if (targetObjectIndex == -1) { - *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex))); + *error = qQmlCompileError( + alias->referenceLocation, + tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex))); break; } @@ -1104,7 +1107,9 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv } else { QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex); if (!targetCache) { - *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString())); + *error = qQmlCompileError( + alias->referenceLocation, + tr("Invalid alias target location: %1").arg(property.toString())); break; } @@ -1139,7 +1144,9 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv } if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) { - *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString())); + *error = qQmlCompileError( + alias->referenceLocation, + tr("Invalid alias target location: %1").arg(property.toString())); break; } @@ -1148,14 +1155,18 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv if (!subProperty.isEmpty()) { const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(targetProperty->propType()); if (!valueTypeMetaObject) { - *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); + *error = qQmlCompileError( + alias->referenceLocation, + tr("Invalid alias target location: %1").arg(subProperty.toString())); break; } int valueTypeIndex = valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData()); if (valueTypeIndex == -1) { - *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); + *error = qQmlCompileError( + alias->referenceLocation, + tr("Invalid alias target location: %1").arg(subProperty.toString())); break; } Q_ASSERT(valueTypeIndex <= 0x0000FFFF); @@ -1345,10 +1356,8 @@ bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIn for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next) functionsToCompile << *foe; const QVector<int> runtimeFunctionIndices = v4CodeGen->generateJSCodeForFunctionsAndBindings(functionsToCompile); - const QList<QQmlError> jsErrors = v4CodeGen->qmlErrors(); - if (!jsErrors.isEmpty()) { - for (const QQmlError &e : jsErrors) - compiler->recordError(e); + if (v4CodeGen->hasError()) { + compiler->recordError(v4CodeGen->error()); return false; } diff --git a/src/qml/qml/qqmltypecompiler_p.h b/src/qml/qml/qqmltypecompiler_p.h index f588909c42..615694d4bc 100644 --- a/src/qml/qml/qqmltypecompiler_p.h +++ b/src/qml/qml/qqmltypecompiler_p.h @@ -97,9 +97,8 @@ public: QQmlRefPointer<QV4::ExecutableCompilationUnit> compile(); QList<QQmlError> compilationErrors() const { return errors; } - void recordError(QQmlError error); void recordError(const QV4::CompiledData::Location &location, const QString &description); - void recordError(const QQmlCompileError &error); + void recordError(const QQmlJS::DiagnosticMessage &error); int registerString(const QString &str); int registerConstant(QV4::ReturnedValue v); @@ -153,7 +152,7 @@ struct QQmlCompilePass protected: void recordError(const QV4::CompiledData::Location &location, const QString &description) const { compiler->recordError(location, description); } - void recordError(const QQmlCompileError &error) + void recordError(const QQmlJS::DiagnosticMessage &error) { compiler->recordError(error); } QV4::ResolvedTypeReference *resolvedType(int id) const @@ -276,7 +275,7 @@ protected: AllAliasesResolved }; - AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlCompileError *error); + AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlJS::DiagnosticMessage *error); QQmlEnginePrivate *enginePrivate; QQmlJS::MemoryPool *pool; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 1022412292..0bfdbdd2fa 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -47,7 +47,6 @@ #include <private/qv4codegen_p.h> #include <private/qqmlcomponent_p.h> #include <private/qqmlprofiler_p.h> -#include <private/qqmlmemoryprofiler_p.h> #include <private/qqmltypecompiler_p.h> #include <private/qqmlpropertyvalidator_p.h> #include <private/qqmlpropertycachecreator_p.h> @@ -459,25 +458,25 @@ void QQmlDataBlob::setError(const QList<QQmlError> &errors) tryDone(); } -void QQmlDataBlob::setError(const QQmlCompileError &error) +void QQmlDataBlob::setError(const QQmlJS::DiagnosticMessage &error) { QQmlError e; - e.setColumn(error.location.column); - e.setLine(error.location.line); - e.setDescription(error.description); + e.setColumn(error.column); + e.setLine(error.line); + e.setDescription(error.message); e.setUrl(url()); setError(e); } -void QQmlDataBlob::setError(const QVector<QQmlCompileError> &errors) +void QQmlDataBlob::setError(const QVector<QQmlJS::DiagnosticMessage> &errors) { QList<QQmlError> finalErrors; finalErrors.reserve(errors.count()); - for (const QQmlCompileError &error: errors) { + for (const auto &error : errors) { QQmlError e; - e.setColumn(error.location.column); - e.setLine(error.location.line); - e.setDescription(error.description); + e.setColumn(error.column); + e.setLine(error.line); + e.setDescription(error.message); e.setUrl(url()); finalErrors << e; } @@ -757,13 +756,13 @@ QQmlDataBlob::ThreadData::ThreadData() QQmlDataBlob::Status QQmlDataBlob::ThreadData::status() const { - return QQmlDataBlob::Status((_p.load() & TD_STATUS_MASK) >> TD_STATUS_SHIFT); + return QQmlDataBlob::Status((_p.loadRelaxed() & TD_STATUS_MASK) >> TD_STATUS_SHIFT); } void QQmlDataBlob::ThreadData::setStatus(QQmlDataBlob::Status status) { while (true) { - int d = _p.load(); + int d = _p.loadRelaxed(); int nd = (d & ~TD_STATUS_MASK) | ((status << TD_STATUS_SHIFT) & TD_STATUS_MASK); if (d == nd || _p.testAndSetOrdered(d, nd)) return; } @@ -771,13 +770,13 @@ void QQmlDataBlob::ThreadData::setStatus(QQmlDataBlob::Status status) bool QQmlDataBlob::ThreadData::isAsync() const { - return _p.load() & TD_ASYNC_MASK; + return _p.loadRelaxed() & TD_ASYNC_MASK; } void QQmlDataBlob::ThreadData::setIsAsync(bool v) { while (true) { - int d = _p.load(); + int d = _p.loadRelaxed(); int nd = (d & ~TD_ASYNC_MASK) | (v?TD_ASYNC_MASK:0); if (d == nd || _p.testAndSetOrdered(d, nd)) return; } @@ -785,13 +784,13 @@ void QQmlDataBlob::ThreadData::setIsAsync(bool v) quint8 QQmlDataBlob::ThreadData::progress() const { - return quint8((_p.load() & TD_PROGRESS_MASK) >> TD_PROGRESS_SHIFT); + return quint8((_p.loadRelaxed() & TD_PROGRESS_MASK) >> TD_PROGRESS_SHIFT); } void QQmlDataBlob::ThreadData::setProgress(quint8 v) { while (true) { - int d = _p.load(); + int d = _p.loadRelaxed(); int nd = (d & ~TD_PROGRESS_MASK) | ((v << TD_PROGRESS_SHIFT) & TD_PROGRESS_MASK); if (d == nd || _p.testAndSetOrdered(d, nd)) return; } @@ -921,7 +920,6 @@ void QQmlTypeLoaderThread::loadWithCachedUnitThread(QQmlDataBlob *b, const QV4:: void QQmlTypeLoaderThread::callCompletedMain(QQmlDataBlob *b) { - QML_MEMORY_SCOPE_URL(b->url()); #ifdef DATABLOB_DEBUG qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->urlString())); #endif @@ -1147,8 +1145,6 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob) return; } - QML_MEMORY_SCOPE_URL(blob->m_url); - if (QQmlFile::isSynchronous(blob->m_url)) { const QString fileName = QQmlFile::urlToLocalFileOrQrc(blob->m_url); if (!QQml_isFileCaseCorrect(fileName)) { @@ -1278,7 +1274,6 @@ void QQmlTypeLoader::initializeEngine(QQmlExtensionInterface *iface, void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data) { - QML_MEMORY_SCOPE_URL(blob->url()); QQmlDataBlob::SourceCodeData d; d.inlineSourceCode = QString::fromUtf8(data); d.hasInlineSourceCode = true; @@ -1287,7 +1282,6 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data) void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName) { - QML_MEMORY_SCOPE_URL(blob->url()); QQmlDataBlob::SourceCodeData d; d.fileInfo = QFileInfo(fileName); setData(blob, d); @@ -1295,7 +1289,6 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName) void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeData &d) { - QML_MEMORY_SCOPE_URL(blob->url()); QQmlCompilingProfiler prof(profiler(), blob); blob->m_inCallback = true; @@ -1315,7 +1308,6 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeD void QQmlTypeLoader::setCachedUnit(QQmlDataBlob *blob, const QV4::CompiledData::Unit *unit) { - QML_MEMORY_SCOPE_URL(blob->url()); QQmlCompilingProfiler prof(profiler(), blob); blob->m_inCallback = true; @@ -1584,7 +1576,17 @@ bool QQmlTypeLoaderQmldirContent::hasError() const QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri) const { - return m_parser.errors(uri); + QList<QQmlError> errors; + const QUrl url(uri); + for (const auto parseError : m_parser.errors(uri)) { + QQmlError error; + error.setUrl(url); + error.setLine(parseError.line); + error.setColumn(parseError.column); + error.setDescription(parseError.message); + errors.append(error); + } + return errors; } QString QQmlTypeLoaderQmldirContent::typeNamespace() const @@ -1601,7 +1603,11 @@ void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QStr void QQmlTypeLoaderQmldirContent::setError(const QQmlError &error) { - m_parser.setError(error); + QQmlJS::DiagnosticMessage parseError; + parseError.line = error.line(); + parseError.column = error.column(); + parseError.message = error.description(); + m_parser.setError(parseError); } QQmlDirComponents QQmlTypeLoaderQmldirContent::components() const @@ -2248,8 +2254,8 @@ void QQmlTypeData::createTypeAndPropertyCaches( QQmlPropertyCacheCreator<QV4::ExecutableCompilationUnit> propertyCacheCreator( &m_compiledData->propertyCaches, &pendingGroupPropertyBindings, engine, m_compiledData.data(), &m_importCache); - QQmlCompileError error = propertyCacheCreator.buildMetaObjects(); - if (error.isSet()) { + QQmlJS::DiagnosticMessage error = propertyCacheCreator.buildMetaObjects(); + if (error.isValid()) { setError(error); return; } @@ -2350,8 +2356,8 @@ void QQmlTypeData::done() QQmlRefPointer<QQmlTypeNameCache> typeNameCache; QV4::ResolvedTypeReferenceMap resolvedTypeCache; { - QQmlCompileError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache); - if (error.isSet()) { + QQmlJS::DiagnosticMessage error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache); + if (error.isValid()) { setError(error); return; } @@ -2391,7 +2397,7 @@ void QQmlTypeData::done() { // Sanity check property bindings QQmlPropertyValidator validator(enginePrivate, m_importCache, m_compiledData); - QVector<QQmlCompileError> errors = validator.validate(); + QVector<QQmlJS::DiagnosticMessage> errors = validator.validate(); if (!errors.isEmpty()) { setError(errors); return; @@ -2535,8 +2541,8 @@ bool QQmlTypeData::loadFromSource() for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) { QQmlError e; e.setUrl(url()); - e.setLine(msg.loc.startLine); - e.setColumn(msg.loc.startColumn); + e.setLine(msg.line); + e.setColumn(msg.column); e.setDescription(msg.message); errors << e; } @@ -2775,7 +2781,7 @@ void QQmlTypeData::resolveTypes() loadImplicitImport(); } -QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( +QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches( QQmlRefPointer<QQmlTypeNameCache> *typeNameCache, QV4::ResolvedTypeReferenceMap *resolvedTypeCache ) const @@ -2798,7 +2804,7 @@ QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( QQmlType qmlType = resolvedType->type; if (resolvedType->typeData) { if (resolvedType->needsCreation && qmlType.isCompositeSingleton()) { - return QQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName())); + return qQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName())); } ref->compilationUnit = resolvedType->typeData->compilationUnit(); } else if (qmlType.isValid()) { @@ -2809,7 +2815,7 @@ QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( QString reason = ref->type.noCreationReason(); if (reason.isEmpty()) reason = tr("Element is not creatable."); - return QQmlCompileError(resolvedType->location, reason); + return qQmlCompileError(resolvedType->location, reason); } if (ref->type.containsRevisionedAttributes()) { @@ -2822,7 +2828,7 @@ QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( ref->doDynamicTypeCheck(); resolvedTypeCache->insert(resolvedType.key(), ref.take()); } - QQmlCompileError noError; + QQmlJS::DiagnosticMessage noError; return noError; } diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index d87812d48e..3330d52e56 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -86,7 +86,6 @@ class QQmlTypeData; class QQmlTypeLoader; class QQmlExtensionInterface; class QQmlProfiler; -struct QQmlCompileError; namespace QmlIR { struct Document; @@ -154,8 +153,8 @@ protected: // Can be called from within callbacks void setError(const QQmlError &); void setError(const QList<QQmlError> &errors); - void setError(const QQmlCompileError &error); - void setError(const QVector<QQmlCompileError> &errors); + void setError(const QQmlJS::DiagnosticMessage &error); + void setError(const QVector<QQmlJS::DiagnosticMessage> &errors); void setError(const QString &description); void addDependency(QQmlDataBlob *); @@ -481,7 +480,7 @@ private: void restoreIR(QV4::CompiledData::CompilationUnit &&unit); void continueLoadFromIR(); void resolveTypes(); - QQmlCompileError buildTypeResolutionCaches( + QQmlJS::DiagnosticMessage buildTypeResolutionCaches( QQmlRefPointer<QQmlTypeNameCache> *typeNameCache, QV4::ResolvedTypeReferenceMap *resolvedTypeCache ) const; diff --git a/src/qml/qml/qqmltypemodule.cpp b/src/qml/qml/qqmltypemodule.cpp index 4d7553fbab..9c9bf3e48f 100644 --- a/src/qml/qml/qqmltypemodule.cpp +++ b/src/qml/qml/qqmltypemodule.cpp @@ -69,24 +69,24 @@ int QQmlTypeModule::majorVersion() const int QQmlTypeModule::minimumMinorVersion() const { - return d->minMinorVersion.load(); + return d->minMinorVersion.loadRelaxed(); } int QQmlTypeModule::maximumMinorVersion() const { - return d->maxMinorVersion.load(); + return d->maxMinorVersion.loadRelaxed(); } void QQmlTypeModule::addMinorVersion(int version) { - for (int oldVersion = d->minMinorVersion.load(); + for (int oldVersion = d->minMinorVersion.loadRelaxed(); oldVersion > version && !d->minMinorVersion.testAndSetOrdered(oldVersion, version); - oldVersion = d->minMinorVersion.load()) { + oldVersion = d->minMinorVersion.loadRelaxed()) { } - for (int oldVersion = d->maxMinorVersion.load(); + for (int oldVersion = d->maxMinorVersion.loadRelaxed(); oldVersion < version && !d->maxMinorVersion.testAndSetOrdered(oldVersion, version); - oldVersion = d->maxMinorVersion.load()) { + oldVersion = d->maxMinorVersion.loadRelaxed()) { } } @@ -125,12 +125,12 @@ void QQmlTypeModule::remove(const QQmlTypePrivate *type) bool QQmlTypeModule::isLocked() const { - return d->locked.load() != 0; + return d->locked.loadRelaxed() != 0; } void QQmlTypeModule::lock() { - d->locked.store(1); + d->locked.storeRelaxed(1); } QQmlType QQmlTypeModule::type(const QHashedStringRef &name, int minor) const diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 9db089c330..57c4eec879 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -454,16 +454,16 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, if (!includeEnums || !name->startsWithUpper()) { QQmlData *ddata = QQmlData::get(qobjectSingleton, false); if (ddata && ddata->propertyCache) { - ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton))); QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext); if (property) { - lookup->qobjectLookup.ic = This->internalClass(); - lookup->qobjectLookup.staticQObject = static_cast<Heap::QObjectWrapper *>(val->heapObject()); + ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton))); + lookup->qobjectLookup.qmlTypeIc = This->internalClass(); + lookup->qobjectLookup.ic = val->objectValue()->internalClass(); lookup->qobjectLookup.propertyCache = ddata->propertyCache; lookup->qobjectLookup.propertyCache->addref(); lookup->qobjectLookup.propertyData = property; - lookup->getter = QV4::QObjectWrapper::lookupGetter; - return lookup->getter(lookup, engine, *This); + lookup->getter = QQmlTypeWrapper::lookupSingletonProperty; + return lookup->getter(lookup, engine, *object); } // Fall through to base implementation } @@ -485,6 +485,39 @@ bool QQmlTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine return Object::virtualResolveLookupSetter(object, engine, lookup, value); } +ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &object) +{ + const auto revertLookup = [l, engine, &object]() { + l->qobjectLookup.propertyCache->release(); + l->qobjectLookup.propertyCache = nullptr; + l->getter = Lookup::getterGeneric; + return Lookup::getterGeneric(l, engine, object); + }; + + // we can safely cast to a QV4::Object here. If object is something else, + // the internal class won't match + Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); + if (!o || o->internalClass != l->qobjectLookup.qmlTypeIc) + return revertLookup(); + + Heap::QQmlTypeWrapper *This = static_cast<Heap::QQmlTypeWrapper *>(o); + + QQmlType type = This->type(); + if (!type.isValid()) + return revertLookup(); + + if (!type.isQObjectSingleton() && !type.isCompositeSingleton()) + return revertLookup(); + + QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine()); + QObject *qobjectSingleton = e->singletonInstance<QObject *>(type); + Q_ASSERT(qobjectSingleton); + + Scope scope(engine); + ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, qobjectSingleton)); + return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup); +} + void Heap::QQmlScopedEnumWrapper::destroy() { QQmlType::derefHandle(typePrivate); diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index c797a4ac10..6b51f421b3 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -114,6 +114,8 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup); static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value); + static ReturnedValue lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &base); + protected: static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty); static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver); diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 2881e71805..458f26b465 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -57,6 +57,7 @@ #include <private/qv4scopedvalue_p.h> #include <private/qv4jscall_p.h> #include <private/qv4qobjectwrapper_p.h> +#include <private/qqmlpropertycachecreator_p.h> QT_BEGIN_NAMESPACE @@ -638,205 +639,170 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * id -= propOffset(); if (id < propertyCount) { - const QV4::CompiledData::Property::Type t = static_cast<QV4::CompiledData::Property::Type>(qint32(compiledObject->propertyTable()[id].type)); - bool needActivate = false; - - if (t == QV4::CompiledData::Property::Var) { - // the context can be null if accessing var properties from cpp after re-parenting an item. - QQmlEnginePrivate *ep = (ctxt == nullptr || ctxt->engine == nullptr) ? nullptr : QQmlEnginePrivate::get(ctxt->engine); - if (ep) { - if (c == QMetaObject::ReadProperty) { - *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id); - } else if (c == QMetaObject::WriteProperty) { - writeProperty(id, *reinterpret_cast<QVariant *>(a[0])); - } - } else if (c == QMetaObject::ReadProperty) { - // if the context was disposed, we just return an invalid variant from read. - *reinterpret_cast<QVariant *>(a[0]) = QVariant(); - } + const QV4::CompiledData::Property &property = compiledObject->propertyTable()[id]; + const QV4::CompiledData::BuiltinType t = property.builtinType(); - } else { - int fallbackMetaType = QMetaType::UnknownType; + // the context can be null if accessing var properties from cpp after re-parenting an item. + QQmlEnginePrivate *ep = (ctxt == nullptr || ctxt->engine == nullptr) ? nullptr : QQmlEnginePrivate::get(ctxt->engine); + + const int fallbackMetaType = QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(t); + + if (c == QMetaObject::ReadProperty) { switch (t) { - case QV4::CompiledData::Property::Font: - fallbackMetaType = QMetaType::QFont; + case QV4::CompiledData::BuiltinType::Int: + *reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id); break; - case QV4::CompiledData::Property::Time: - fallbackMetaType = QMetaType::QTime; + case QV4::CompiledData::BuiltinType::Bool: + *reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id); break; - case QV4::CompiledData::Property::Color: - fallbackMetaType = QMetaType::QColor; + case QV4::CompiledData::BuiltinType::Real: + *reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id); break; - case QV4::CompiledData::Property::Vector2D: - fallbackMetaType = QMetaType::QVector2D; + case QV4::CompiledData::BuiltinType::String: + *reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id); break; - case QV4::CompiledData::Property::Vector3D: - fallbackMetaType = QMetaType::QVector3D; + case QV4::CompiledData::BuiltinType::Url: + *reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id); break; - case QV4::CompiledData::Property::Vector4D: - fallbackMetaType = QMetaType::QVector4D; + case QV4::CompiledData::BuiltinType::Date: + *reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id); break; - case QV4::CompiledData::Property::Matrix4x4: - fallbackMetaType = QMetaType::QMatrix4x4; + case QV4::CompiledData::BuiltinType::DateTime: + *reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id); break; - case QV4::CompiledData::Property::Quaternion: - fallbackMetaType = QMetaType::QQuaternion; + case QV4::CompiledData::BuiltinType::Rect: + *reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id); break; - default: break; - } - - - if (c == QMetaObject::ReadProperty) { - switch (t) { - case QV4::CompiledData::Property::Int: - *reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id); - break; - case QV4::CompiledData::Property::Bool: - *reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id); - break; - case QV4::CompiledData::Property::Real: - *reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id); - break; - case QV4::CompiledData::Property::String: - *reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id); - break; - case QV4::CompiledData::Property::Url: - *reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id); - break; - case QV4::CompiledData::Property::Date: - *reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id); - break; - case QV4::CompiledData::Property::DateTime: - *reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id); - break; - case QV4::CompiledData::Property::Rect: - *reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id); - break; - case QV4::CompiledData::Property::Size: - *reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id); - break; - case QV4::CompiledData::Property::Point: - *reinterpret_cast<QPointF *>(a[0]) = readPropertyAsPointF(id); - break; - case QV4::CompiledData::Property::Custom: - *reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id); - break; - case QV4::CompiledData::Property::Variant: + case QV4::CompiledData::BuiltinType::Size: + *reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id); + break; + case QV4::CompiledData::BuiltinType::Point: + *reinterpret_cast<QPointF *>(a[0]) = readPropertyAsPointF(id); + break; + case QV4::CompiledData::BuiltinType::Variant: + *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id); + break; + case QV4::CompiledData::BuiltinType::Font: + case QV4::CompiledData::BuiltinType::Time: + case QV4::CompiledData::BuiltinType::Color: + case QV4::CompiledData::BuiltinType::Vector2D: + case QV4::CompiledData::BuiltinType::Vector3D: + case QV4::CompiledData::BuiltinType::Vector4D: + case QV4::CompiledData::BuiltinType::Matrix4x4: + case QV4::CompiledData::BuiltinType::Quaternion: + Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); + if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { + QVariant propertyAsVariant; + if (const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>()) + propertyAsVariant = v->d()->data(); + QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType); + } + break; + case QV4::CompiledData::BuiltinType::Var: + if (ep) { *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id); - break; - case QV4::CompiledData::Property::CustomList: { + } else { + // if the context was disposed, we just return an invalid variant from read. + *reinterpret_cast<QVariant *>(a[0]) = QVariant(); + } + break; + case QV4::CompiledData::BuiltinType::InvalidBuiltin: + if (property.isList) { QList<QObject *> *list = readPropertyAsList(id); QQmlListProperty<QObject> *p = static_cast<QQmlListProperty<QObject> *>(a[0]); *p = QQmlListProperty<QObject>(object, list, - list_append, list_count, list_at, - list_clear); + list_append, list_count, list_at, + list_clear); p->dummy1 = this; p->dummy2 = reinterpret_cast<void *>(quintptr(methodOffset() + id)); - break; + } else { + *reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id); } - case QV4::CompiledData::Property::Font: - case QV4::CompiledData::Property::Time: - case QV4::CompiledData::Property::Color: - case QV4::CompiledData::Property::Vector2D: - case QV4::CompiledData::Property::Vector3D: - case QV4::CompiledData::Property::Vector4D: - case QV4::CompiledData::Property::Matrix4x4: - case QV4::CompiledData::Property::Quaternion: - Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); - if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { - QVariant propertyAsVariant; - if (const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>()) - propertyAsVariant = v->d()->data(); - QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType); + } + + } else if (c == QMetaObject::WriteProperty) { + bool needActivate = false; + switch (t) { + case QV4::CompiledData::BuiltinType::Int: + needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id); + writeProperty(id, *reinterpret_cast<int *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Bool: + needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id); + writeProperty(id, *reinterpret_cast<bool *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Real: + needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id); + writeProperty(id, *reinterpret_cast<double *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::String: + needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id); + writeProperty(id, *reinterpret_cast<QString *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Url: + needActivate = *reinterpret_cast<QUrl *>(a[0]) != readPropertyAsUrl(id); + writeProperty(id, *reinterpret_cast<QUrl *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Date: + needActivate = *reinterpret_cast<QDate *>(a[0]) != readPropertyAsDate(id); + writeProperty(id, *reinterpret_cast<QDate *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::DateTime: + needActivate = *reinterpret_cast<QDateTime *>(a[0]) != readPropertyAsDateTime(id); + writeProperty(id, *reinterpret_cast<QDateTime *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Rect: + needActivate = *reinterpret_cast<QRectF *>(a[0]) != readPropertyAsRectF(id); + writeProperty(id, *reinterpret_cast<QRectF *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Size: + needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id); + writeProperty(id, *reinterpret_cast<QSizeF *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Point: + needActivate = *reinterpret_cast<QPointF *>(a[0]) != readPropertyAsPointF(id); + writeProperty(id, *reinterpret_cast<QPointF *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Variant: + writeProperty(id, *reinterpret_cast<QVariant *>(a[0])); + break; + case QV4::CompiledData::BuiltinType::Font: + case QV4::CompiledData::BuiltinType::Time: + case QV4::CompiledData::BuiltinType::Color: + case QV4::CompiledData::BuiltinType::Vector2D: + case QV4::CompiledData::BuiltinType::Vector3D: + case QV4::CompiledData::BuiltinType::Vector4D: + case QV4::CompiledData::BuiltinType::Matrix4x4: + case QV4::CompiledData::BuiltinType::Quaternion: + Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); + if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { + const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); + if (!v) { + md->set(engine, id, engine->newVariantObject(QVariant())); + v = (md->data() + id)->as<QV4::VariantObject>(); + QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data()); } - break; - case QV4::CompiledData::Property::Var: - Q_UNREACHABLE(); + needActivate = !QQml_valueTypeProvider()->equalValueType(fallbackMetaType, a[0], v->d()->data()); + QQml_valueTypeProvider()->writeValueType(fallbackMetaType, a[0], v->d()->data()); } - - } else if (c == QMetaObject::WriteProperty) { - - switch(t) { - case QV4::CompiledData::Property::Int: - needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id); - writeProperty(id, *reinterpret_cast<int *>(a[0])); - break; - case QV4::CompiledData::Property::Bool: - needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id); - writeProperty(id, *reinterpret_cast<bool *>(a[0])); - break; - case QV4::CompiledData::Property::Real: - needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id); - writeProperty(id, *reinterpret_cast<double *>(a[0])); - break; - case QV4::CompiledData::Property::String: - needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id); - writeProperty(id, *reinterpret_cast<QString *>(a[0])); - break; - case QV4::CompiledData::Property::Url: - needActivate = *reinterpret_cast<QUrl *>(a[0]) != readPropertyAsUrl(id); - writeProperty(id, *reinterpret_cast<QUrl *>(a[0])); - break; - case QV4::CompiledData::Property::Date: - needActivate = *reinterpret_cast<QDate *>(a[0]) != readPropertyAsDate(id); - writeProperty(id, *reinterpret_cast<QDate *>(a[0])); - break; - case QV4::CompiledData::Property::DateTime: - needActivate = *reinterpret_cast<QDateTime *>(a[0]) != readPropertyAsDateTime(id); - writeProperty(id, *reinterpret_cast<QDateTime *>(a[0])); - break; - case QV4::CompiledData::Property::Rect: - needActivate = *reinterpret_cast<QRectF *>(a[0]) != readPropertyAsRectF(id); - writeProperty(id, *reinterpret_cast<QRectF *>(a[0])); - break; - case QV4::CompiledData::Property::Size: - needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id); - writeProperty(id, *reinterpret_cast<QSizeF *>(a[0])); - break; - case QV4::CompiledData::Property::Point: - needActivate = *reinterpret_cast<QPointF *>(a[0]) != readPropertyAsPointF(id); - writeProperty(id, *reinterpret_cast<QPointF *>(a[0])); - break; - case QV4::CompiledData::Property::Custom: - needActivate = *reinterpret_cast<QObject **>(a[0]) != readPropertyAsQObject(id); - writeProperty(id, *reinterpret_cast<QObject **>(a[0])); - break; - case QV4::CompiledData::Property::Variant: + break; + case QV4::CompiledData::BuiltinType::Var: + if (ep) writeProperty(id, *reinterpret_cast<QVariant *>(a[0])); - break; - case QV4::CompiledData::Property::CustomList: + break; + case QV4::CompiledData::BuiltinType::InvalidBuiltin: + if (property.isList) { // Writing such a property is not supported. Content is added through the list property // methods. - break; - case QV4::CompiledData::Property::Font: - case QV4::CompiledData::Property::Time: - case QV4::CompiledData::Property::Color: - case QV4::CompiledData::Property::Vector2D: - case QV4::CompiledData::Property::Vector3D: - case QV4::CompiledData::Property::Vector4D: - case QV4::CompiledData::Property::Matrix4x4: - case QV4::CompiledData::Property::Quaternion: - Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); - if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { - const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); - if (!v) { - md->set(engine, id, engine->newVariantObject(QVariant())); - v = (md->data() + id)->as<QV4::VariantObject>(); - QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data()); - } - needActivate = !QQml_valueTypeProvider()->equalValueType(fallbackMetaType, a[0], v->d()->data()); - QQml_valueTypeProvider()->writeValueType(fallbackMetaType, a[0], v->d()->data()); - } - break; - case QV4::CompiledData::Property::Var: - Q_UNREACHABLE(); + } else { + needActivate = *reinterpret_cast<QObject **>(a[0]) != readPropertyAsQObject(id); + writeProperty(id, *reinterpret_cast<QObject **>(a[0])); } - } - } + } - if (c == QMetaObject::WriteProperty && needActivate) { - activate(object, methodOffset() + id, nullptr); + if (needActivate) + activate(object, methodOffset() + id, nullptr); } return -1; @@ -1000,7 +966,7 @@ QV4::ReturnedValue QQmlVMEMetaObject::method(int index) const QV4::ReturnedValue QQmlVMEMetaObject::readVarProperty(int id) const { - Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var); + Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var); QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) @@ -1025,7 +991,7 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id) const void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) { - Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var); + Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var); QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) @@ -1065,7 +1031,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) { - if (compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var) { + if (compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return; diff --git a/src/qml/qmldirparser/qmldirparser.pri b/src/qml/qmldirparser/qmldirparser.pri index 660e7b395a..fefe2e75be 100644 --- a/src/qml/qmldirparser/qmldirparser.pri +++ b/src/qml/qmldirparser/qmldirparser.pri @@ -2,10 +2,7 @@ INCLUDEPATH += $$PWD INCLUDEPATH += $$OUT_PWD HEADERS += \ - $$PWD/qqmldirparser_p.h \ - $$PWD/qqmlerror.h \ - $$PWD/qqmlsourcecoordinate_p.h + $$PWD/qqmldirparser_p.h SOURCES += \ - $$PWD/qqmldirparser.cpp \ - $$PWD/qqmlerror.cpp + $$PWD/qqmldirparser.cpp diff --git a/src/qml/qmldirparser/qqmldirparser.cpp b/src/qml/qmldirparser/qqmldirparser.cpp index e944b52e47..d7662b11f5 100644 --- a/src/qml/qmldirparser/qqmldirparser.cpp +++ b/src/qml/qmldirparser/qqmldirparser.cpp @@ -38,7 +38,6 @@ ****************************************************************************/ #include "qqmldirparser_p.h" -#include "qqmlerror.h" #include <QtCore/QtDebug> @@ -297,8 +296,8 @@ bool QQmlDirParser::parse(const QString &source) void QQmlDirParser::reportError(quint16 line, quint16 column, const QString &description) { QQmlJS::DiagnosticMessage error; - error.loc.startLine = line; - error.loc.startColumn = column; + error.line = line; + error.column = column; error.message = description; _errors.append(error); } @@ -311,27 +310,20 @@ bool QQmlDirParser::hasError() const return false; } -void QQmlDirParser::setError(const QQmlError &e) +void QQmlDirParser::setError(const QQmlJS::DiagnosticMessage &e) { _errors.clear(); - reportError(e.line(), e.column(), e.description()); + reportError(e.line, e.column, e.message); } -QList<QQmlError> QQmlDirParser::errors(const QString &uri) const +QList<QQmlJS::DiagnosticMessage> QQmlDirParser::errors(const QString &uri) const { - QUrl url(uri); - QList<QQmlError> errors; + QList<QQmlJS::DiagnosticMessage> errors; const int numErrors = _errors.size(); errors.reserve(numErrors); for (int i = 0; i < numErrors; ++i) { - const QQmlJS::DiagnosticMessage &msg = _errors.at(i); - QQmlError e; - QString description = msg.message; - description.replace(QLatin1String("$$URI$$"), uri); - e.setDescription(description); - e.setUrl(url); - e.setLine(msg.loc.startLine); - e.setColumn(msg.loc.startColumn); + QQmlJS::DiagnosticMessage e = _errors.at(i); + e.message.replace(QLatin1String("$$URI$$"), uri); errors << e; } return errors; diff --git a/src/qml/qmldirparser/qqmldirparser_p.h b/src/qml/qmldirparser/qqmldirparser_p.h index cff9cb11a4..0957c8373a 100644 --- a/src/qml/qmldirparser/qqmldirparser_p.h +++ b/src/qml/qmldirparser/qqmldirparser_p.h @@ -56,10 +56,10 @@ #include <QtCore/QDebug> #include <private/qqmljsengine_p.h> #include <private/qv4global_p.h> +#include <private/qqmljsdiagnosticmessage_p.h> QT_BEGIN_NAMESPACE -class QQmlError; class QQmlEngine; class Q_QML_PRIVATE_EXPORT QQmlDirParser { @@ -70,18 +70,30 @@ public: bool parse(const QString &source); bool hasError() const; - void setError(const QQmlError &); - QList<QQmlError> errors(const QString &uri) const; + void setError(const QQmlJS::DiagnosticMessage &); + QList<QQmlJS::DiagnosticMessage> errors(const QString &uri) const; QString typeNamespace() const; void setTypeNamespace(const QString &s); + static void checkNonRelative(const char *item, const QString &typeName, const QString &fileName) + { + if (fileName.startsWith(QLatin1Char('/')) || fileName.contains(QLatin1Char(':'))) { + qWarning() << item << typeName + << "is specified with non-relative URL" << fileName << "in a qmldir file." + << "URLs in qmldir files should be relative to the qmldir file's directory."; + } + } + struct Plugin { Plugin() {} Plugin(const QString &name, const QString &path) - : name(name), path(path) {} + : name(name), path(path) + { + checkNonRelative("Plugin", name, path); + } QString name; QString path; @@ -93,7 +105,10 @@ public: Component(const QString &typeName, const QString &fileName, int majorVersion, int minorVersion) : typeName(typeName), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion), - internal(false), singleton(false) {} + internal(false), singleton(false) + { + checkNonRelative("Component", typeName, fileName); + } QString typeName; QString fileName; @@ -108,7 +123,10 @@ public: Script() {} Script(const QString &nameSpace, const QString &fileName, int majorVersion, int minorVersion) - : nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion) {} + : nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion) + { + checkNonRelative("Script", nameSpace, fileName); + } QString nameSpace; QString fileName; diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h index 46f0e3f409..9ca0cf2abe 100644 --- a/src/qml/qtqmlglobal_p.h +++ b/src/qml/qtqmlglobal_p.h @@ -56,8 +56,7 @@ #ifndef QT_QML_BOOTSTRAPPED # include <QtQml/private/qtqml-config_p.h> #endif - -#define Q_QML_PRIVATE_API_VERSION 4 +#include <private/qqmlapiversion_p.h> #define Q_QML_PRIVATE_EXPORT Q_QML_EXPORT diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp index 1ba015f796..5067b6a02e 100644 --- a/src/qml/types/qqmlbind.cpp +++ b/src/qml/types/qqmlbind.cpp @@ -241,7 +241,7 @@ void QQmlBind::setObject(QObject *obj) } d->obj = obj; if (d->componentComplete) { - d->prop = QQmlProperty(d->obj, d->propName); + d->prop = QQmlProperty(d->obj, d->propName, qmlContext(this)); d->validate(this); } eval(); @@ -287,7 +287,7 @@ void QQmlBind::setProperty(const QString &p) } d->propName = p; if (d->componentComplete) { - d->prop = QQmlProperty(d->obj, d->propName); + d->prop = QQmlProperty(d->obj, d->propName, qmlContext(this)); d->validate(this); } eval(); @@ -416,7 +416,7 @@ void QQmlBind::componentComplete() Q_D(QQmlBind); d->componentComplete = true; if (!d->prop.isValid()) { - d->prop = QQmlProperty(d->obj, d->propName); + d->prop = QQmlProperty(d->obj, d->propName, qmlContext(this)); d->validate(this); } eval(); diff --git a/src/qmldevtools/.prev_CMakeLists.txt b/src/qmldevtools/.prev_CMakeLists.txt index 24b87902ea..9f3587f2a0 100644 --- a/src/qmldevtools/.prev_CMakeL |