From 6a8eb9ef8d1f310c470ab0bfcdd35ded15c42607 Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Sat, 21 Jan 2017 00:37:35 +0900 Subject: Fix build without features.temporaryfile Change-Id: I31bcf56ee0c4ec9285dccb356b03b89e8ce8356a Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4compileddata.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 6aac111897..d8ff22e9ed 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -356,6 +356,7 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString) return false; } +#if QT_CONFIG(temporaryfile) // Foo.qml -> Foo.qmlc QSaveFile cacheFile(cacheFilePath(unitUrl)); if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { @@ -388,6 +389,10 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString) } return true; +#else + *errorString = QStringLiteral("features.temporaryfile is disabled."); + return false; +#endif // QT_CONFIG(temporaryfile) } bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString) -- cgit v1.2.3 From fdf94daed26175d7cf1d5abf59acff5437ad68a1 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Fri, 20 Jan 2017 13:04:28 +0100 Subject: Doc: reinserted hello.qml which had been deleted by mistake During the update of plugin.cpp this file was deleted by mistake. plugin.cpp still refers to it and it needs to be reinserted in src/quick/doc/snippets. Change-Id: Ie23c926ff6096392da96f0063c767009a3965a30 Reviewed-by: Venugopal Shivashankar --- src/imports/localstorage/plugin.cpp | 2 +- src/quick/doc/snippets/qml/localstorage/hello.qml | 76 +++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/quick/doc/snippets/qml/localstorage/hello.qml (limited to 'src') diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index 6704283cb9..9191700b45 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -581,7 +581,7 @@ Database connections are automatically closed during Javascript garbage collecti The API can be used from JavaScript functions in your QML: -\snippet localstorage/localstorage/hello.qml 0 +\snippet qml/localstorage/hello.qml 0 The API conforms to the Synchronous API of the HTML5 Web Database API, \link http://www.w3.org/TR/2009/WD-webdatabase-20091029/ W3C Working Draft 29 October 2009\endlink. diff --git a/src/quick/doc/snippets/qml/localstorage/hello.qml b/src/quick/doc/snippets/qml/localstorage/hello.qml new file mode 100644 index 0000000000..959895c82a --- /dev/null +++ b/src/quick/doc/snippets/qml/localstorage/hello.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//![0] +import QtQuick 2.0 + +Rectangle { + color: "white" + width: 200 + height: 100 + + Text { + text: "?" + anchors.horizontalCenter: parent.horizontalCenter + function findGreetings() { + var db = openDatabaseSync("QDeclarativeExampleDB", "1.0", "The Example QML SQL!", 1000000); + + db.transaction( + function(tx) { + // Create the database if it doesn't already exist + tx.executeSql('CREATE TABLE IF NOT EXISTS Greeting(salutation TEXT, salutee TEXT)'); + + // Add (another) greeting row + tx.executeSql('INSERT INTO Greeting VALUES(?, ?)', [ 'hello', 'world' ]); + + // Show all added greetings + var rs = tx.executeSql('SELECT * FROM Greeting'); + + var r = "" + for (var i = 0; i < rs.rows.length; i++) { + r += rs.rows.item(i).salutation + ", " + rs.rows.item(i).salutee + "\n" + } + text = r + } + ) + } + Component.onCompleted: findGreetings() + } +} +//![0] -- cgit v1.2.3 From fa4bb3d4e6902babfab0b1a89c9bf76d1c953252 Mon Sep 17 00:00:00 2001 From: Kavindra Palaraja Date: Sun, 8 Jan 2017 11:44:20 +0100 Subject: Mention that QVariantList is also a supported model type Also added a section with more info that asks the reader to refer to the QStringList example above. Task-number: QTBUG-47768 Change-Id: I4e99b81ac242f7df1ddc412f85c9c1b822080514 Reviewed-by: Robin Burchell --- .../doc/src/concepts/modelviewsdata/cppmodels.qdoc | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc index a764402c2f..12a107491a 100644 --- a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc +++ b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc @@ -36,10 +36,10 @@ Models can be defined in C++ and then made available to QML. This is useful for exposing existing C++ data models or otherwise complex datasets to QML. -A C++ model class can be defined as a \l QStringList, a QObjectList or a -\l QAbstractItemModel. The first two are useful for exposing simpler datasets, -while QAbstractItemModel provides a more flexible solution for more complex -models. +A C++ model class can be defined as a \l QStringList, a \l QVariantList, a +QObjectList or a \l QAbstractItemModel. The first three are useful for exposing +simpler datasets, while QAbstractItemModel provides a more flexible solution for +more complex models. \section2 QStringList-based Model @@ -60,10 +60,20 @@ The complete source code for this example is available in \l {models/stringlistmodel}{examples/quick/models/stringlistmodel} within the Qt install directory. -\b{Note:} There is no way for the view to know that the contents of a QStringList -have changed. If the QStringList changes, it will be necessary to reset +\note There is no way for the view to know that the contents of a QStringList +have changed. If the QStringList changes, it will be necessary to reset the model by calling QQmlContext::setContextProperty() again. +\section2 QVariantList-based Model + +A model may be a single \l QVariantList, which provides the contents of the list +via the \e modelData role. + +The API works just like with \l QStringList, as shown in the previous section. + +\note There is no way for the view to know that the contents of a QVariantList +have changed. If the QVariantList changes, it will be necessary to reset +the model. \section2 QObjectList-based model -- cgit v1.2.3 From c873a176a147cf35c235e395b8797ce42d17188a Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Fri, 27 Jan 2017 21:01:59 +0100 Subject: QQmlTypeCompiler: Fix read after free in tst_qqmllanguage invalidAlias.11 revealed a problem with the loop here, in that the vector was modified while it was being iterated. There isn't any need to modify the vector being iterated, as it'll be put into pendingObjects for the next loop. Change-Id: If9b537c4ac00697237d12e4b0be67ef39cc8b3c4 Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmltypecompiler.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 393616dfac..b7262e4333 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -1108,10 +1108,9 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv continue; } - // Try again later and resolve the target alias first. - _objectsWithAliases.append(objectIndex); // restore alias->idIndex = idIndex; + // Try again later and resolve the target alias first. break; } } -- cgit v1.2.3 From 0a5de1435271155fb3ec7780325e8c33b382da0a Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Fri, 27 Jan 2017 11:49:16 +0900 Subject: Fix build without animation by disabling quick Change-Id: I3b9bc6aa69dbf2a780765ba935b76be6a22280e6 Reviewed-by: Laszlo Agocs Reviewed-by: Robin Burchell --- src/src.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/src.pro b/src/src.pro index c2a58c3757..4e2de8da14 100644 --- a/src/src.pro +++ b/src/src.pro @@ -5,7 +5,7 @@ QT_FOR_CONFIG += network quick-private SUBDIRS += \ qml -qtHaveModule(gui) { +qtHaveModule(gui):qtConfig(animation) { SUBDIRS += \ quick \ qmltest -- cgit v1.2.3 From 65d3a7e15307844a9afcc8fd6cefc8c88079450c Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Thu, 26 Jan 2017 15:19:18 +0100 Subject: Doc: Fix documentation warnings src/qml/jsapi/qjsengine.cpp:524: warning: Undocumented parameter 'metaObject' in QJSEngine::newQMetaObject() src/qml/qml/qqmlengine.cpp:1023: warning: Undocumented parameter 'retCode' in QQmlEngine::exit() src/qml/doc/src/qmlfunctions.qdoc:182: warning: Undocumented parameter 'reason' in qmlRegisterUncreatableMetaObject() src/qml/qml/qqmllist.cpp:393: warning: Undocumented parameter 'at' in QQmlListProperty::QQmlListProperty() src/qml/qml/qqmllist.cpp:393: warning: Undocumented parameter 'count' in QQmlListProperty::QQmlListProperty() src/qml/qml/qqmllist.cpp:402: warning: Undocumented parameter 'at' in QQmlListProperty::QQmlListProperty() src/qml/qml/qqmllist.cpp:402: warning: Undocumented parameter 'count' in QQmlListProperty::QQmlListProperty() src/qml/qml/qqmllist.cpp:402: warning: Undocumented parameter 'append' in QQmlListProperty::QQmlListProperty() src/qml/qml/qqmllist.cpp:402: warning: Undocumented parameter 'clear' in QQmlListProperty::QQmlListProperty() src/quick/items/qquickwindow.cpp:4461: warning: No such parameter 'backend' in QQuickWindow::setSceneGraphBackend() Also do some minor language editing. Change-Id: I2e806d1a77e3c4264d709c27d2bfc4542a782716 Reviewed-by: Mitch Curtis --- src/qml/doc/src/qmlfunctions.qdoc | 14 +++++++++----- src/qml/jsapi/qjsengine.cpp | 2 +- src/qml/qml/qqmlengine.cpp | 2 +- src/qml/qml/qqmllist.cpp | 10 ++++++---- src/qml/qml/qqmlproperty.cpp | 12 +++++++++--- src/quick/items/qquickwindow.cpp | 4 ++-- 6 files changed, 28 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc index 8b24d19891..8f9ac116d4 100644 --- a/src/qml/doc/src/qmlfunctions.qdoc +++ b/src/qml/doc/src/qmlfunctions.qdoc @@ -168,8 +168,9 @@ from \a uri having version number composed from \a versionMajor and \a versionMinor. - While the type has a name and a type, it cannot be created, and the - given error \a reason will result if creation is attempted. + While the type has a name and a type, it cannot be created. An error + message with the given \a reason is printed if the user attempts to + create an instance of this type. This is useful where the type is only intended for providing attached properties, enum values or an abstract base class with its extension. @@ -189,11 +190,14 @@ from \a uri having version number composed from \a versionMajor and \a versionMinor. - This function is useful to register Q_NAMESPACE namespaces. + An instance of the meta object cannot be created. An error message with + the given \a reason is printed if the user attempts to create it. + + This function is useful for registering Q_NAMESPACE namespaces. Returns the QML type id. - Example: + For example: \code namespace MyNamespace { @@ -209,7 +213,7 @@ qmlRegisterUncreatableMetaObject(MyNamespace::staticMetaObject, "io.qt", 1, 0, "MyNamespace", "Access to enums & flags only"); \endcode - Now on QML side you can use the registered enums: + On the QML side, you can now use the registered enums: \code Component.onCompleted: console.log(MyNamespace.Key2) \endcode diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index 4404a5d79f..e4c150057a 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -525,7 +525,7 @@ QJSValue QJSEngine::newQObject(QObject *object) \since 5.8 Creates a JavaScript object that wraps the given QMetaObject - The metaObject must outlive the script engine. It is recommended to only + The \a metaObject must outlive the script engine. It is recommended to only use this method with static metaobjects. diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 2a439bde98..c800641f1c 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1022,7 +1022,7 @@ QQmlEngine::~QQmlEngine() /*! \fn void QQmlEngine::exit(int retCode) This signal is emitted when the QML loaded by the engine would like to exit - from the event loop with the specified return code. + from the event loop with the specified return code \a retCode. \since 5.8 \sa quit() diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp index edd93ef03d..2c71293363 100644 --- a/src/qml/qml/qqmllist.cpp +++ b/src/qml/qml/qqmllist.cpp @@ -394,8 +394,9 @@ can be very useful while prototyping. \fn QQmlListProperty::QQmlListProperty(QObject *object, void *data, CountFunction count, AtFunction at) -Construct a readonly QQmlListProperty from a set of operation functions. An opaque \a data handle -may be passed which can be accessed from within the operation functions. The list property +Construct a readonly QQmlListProperty from a set of operation functions +\a count and \a at. An opaque \a data handle may be passed which can be +accessed from within the operation functions. The list property remains valid while \a object exists. */ @@ -404,8 +405,9 @@ remains valid while \a object exists. CountFunction count, AtFunction at, ClearFunction clear) -Construct a QQmlListProperty from a set of operation functions. An opaque \a data handle -may be passed which can be accessed from within the operation functions. The list property +Construct a QQmlListProperty from a set of operation functions \a append, +\a count, \a at, and \a clear. An opaque \a data handle may be passed which +can be accessed from within the operation functions. The list property remains valid while \a object exists. Null pointers can be passed for any function. If any null pointers are passed in, the list diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index c62fef7c3d..0b8eb677cb 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -1400,9 +1400,9 @@ QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engi } /*! - Sets the property value to \a value and returns true. - Returns false if the property can't be set because the - \a value is the wrong type, for example. + Sets the property value to \a value. Returns \c true on success, or + \c false if the property can't be set because the \a value is the + wrong type, for example. */ bool QQmlProperty::write(const QVariant &value) const { @@ -1417,6 +1417,8 @@ bool QQmlProperty::write(const QVariant &value) const QQmlProperty p(object, name); p.write(value); \endcode + + Returns \c true on success, \c false otherwise. */ bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value) { @@ -1433,6 +1435,8 @@ bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &v QQmlProperty p(object, name, ctxt); p.write(value); \endcode + + Returns \c true on success, \c false otherwise. */ bool QQmlProperty::write(QObject *object, const QString &name, @@ -1453,6 +1457,8 @@ bool QQmlProperty::write(QObject *object, QQmlProperty p(object, name, engine); p.write(value); \endcode + + Returns \c true on success, \c false otherwise. */ bool QQmlProperty::write(QObject *object, const QString &name, const QVariant &value, QQmlEngine *engine) diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index a58912e38f..5edfd619ec 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -4466,8 +4466,8 @@ QSGRendererInterface *QQuickWindow::rendererInterface() const \note The call to the function must happen before constructing the first QQuickWindow in the application. It cannot be changed afterwards. - If \a backend is invalid or an error occurs, the default backend (OpenGL or - software, depending on the Qt configuration) is used. + If the selected backend is invalid or an error occurs, the default backend + (OpenGL or software, depending on the Qt configuration) is used. \since 5.8 */ -- cgit v1.2.3 From 7e663871e63aaf601f8483f224c33cfbe5245f4e Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 30 Jan 2017 11:08:38 +0100 Subject: Quick: Check fbo msaa related extensions via QtGui GL_EXT_xxxx is not sufficient here. QOpenGLFunctions already has support for the ANGLE and some other variants of the framebuffer multisample and blit extensions, so use that instead of the manual checks. Change-Id: I2d8e0850d3b0b9a9cfd9e55aa38adad07a0ba45d Reviewed-by: Andy Nichols --- src/quick/items/context2d/qquickcontext2dtexture.cpp | 7 ++++--- src/quick/scenegraph/qsgdefaultlayer.cpp | 7 ++++--- src/quick/scenegraph/util/qsgdefaultpainternode.cpp | 6 +++--- 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp index 38b5f054bf..d90f527486 100644 --- a/src/quick/items/context2d/qquickcontext2dtexture.cpp +++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #endif #include #include @@ -499,9 +500,9 @@ bool QQuickContext2DFBOTexture::doMultisampling() const static bool multisamplingSupported = false; if (!extensionsChecked) { - const QSet extensions = QOpenGLContext::currentContext()->extensions(); - multisamplingSupported = extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_multisample")) - && extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_blit")); + QOpenGLExtensions *e = static_cast(QOpenGLContext::currentContext()->functions()); + multisamplingSupported = e->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample) + && e->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit); extensionsChecked = true; } diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp index ad5b57ff83..78037a2fde 100644 --- a/src/quick/scenegraph/qsgdefaultlayer.cpp +++ b/src/quick/scenegraph/qsgdefaultlayer.cpp @@ -44,6 +44,7 @@ #include #include +#include #include @@ -320,9 +321,9 @@ void QSGDefaultLayer::grab() if (m_context->openglContext()->format().samples() <= 1) { m_multisampling = false; } else { - const QSet extensions = m_context->openglContext()->extensions(); - m_multisampling = extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_multisample")) - && extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_blit")); + QOpenGLExtensions *e = static_cast(funcs); + m_multisampling = e->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample) + && e->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit); } m_multisamplingChecked = true; } diff --git a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp index 389b9e0b4e..9ffd1b4b08 100644 --- a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp +++ b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp @@ -238,9 +238,9 @@ void QSGDefaultPainterNode::updateGeometry() void QSGDefaultPainterNode::updateRenderTarget() { if (!m_extensionsChecked) { - const QSet extensions = m_context->openglContext()->extensions(); - m_multisamplingSupported = extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_multisample")) - && extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_blit")); + QOpenGLExtensions *e = static_cast(QOpenGLContext::currentContext()->functions()); + m_multisamplingSupported = e->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample) + && e->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit); m_extensionsChecked = true; } -- cgit v1.2.3 From 1380d07b1e60d9a4efec4e15d510271ed210a61a Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 25 Jan 2017 14:51:16 +0100 Subject: Fix -no-qmldebug debug build with MSVC [Platform Specific Changes][Windows] Fixed compilation on MSVC with -no-qml-debug configure argument. Task-number: QTBUG-58412 Change-Id: I915ed3d345b3f1e4e5863456522784ab6c9b15cf Reviewed-by: Ulf Hermann --- src/qml/debugger/qqmldebugserviceinterfaces_p.h | 18 +++++++++++------- src/qml/debugger/qqmlprofiler_p.h | 2 +- src/qml/jsruntime/qv4debugging_p.h | 3 ++- src/qml/jsruntime/qv4profiling_p.h | 2 +- 4 files changed, 15 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/qml/debugger/qqmldebugserviceinterfaces_p.h b/src/qml/debugger/qqmldebugserviceinterfaces_p.h index ca6293c3ec..99ec525f29 100644 --- a/src/qml/debugger/qqmldebugserviceinterfaces_p.h +++ b/src/qml/debugger/qqmldebugserviceinterfaces_p.h @@ -67,13 +67,15 @@ class QQuickWindow; #ifdef QT_NO_QML_DEBUGGER -struct QV4DebugService +class QV4DebugService { +public: void signalEmitted(const QString &) {} }; -struct QQmlProfilerService +class QQmlProfilerService { +public: void startProfiling(QJSEngine *engine, quint64 features = std::numeric_limits::max()) { Q_UNUSED(engine); @@ -83,21 +85,23 @@ struct QQmlProfilerService void stopProfiling(QJSEngine *) {} }; -struct QQmlEngineDebugService +class QQmlEngineDebugService { +public: void objectCreated(QJSEngine *, QObject *) {} virtual void setStatesDelegate(QQmlDebugStatesDelegate *) {} }; -struct QQmlInspectorService { +class QQmlInspectorService { +public: void addWindow(QQuickWindow *) {} void setParentWindow(QQuickWindow *, QWindow *) {} void removeWindow(QQuickWindow *) {} }; -struct QDebugMessageService {}; -struct QQmlEngineControlService {}; -struct QQmlNativeDebugService {}; +class QDebugMessageService {}; +class QQmlEngineControlService {}; +class QQmlNativeDebugService {}; #else diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h index 41fb2c5b7b..88f8e94f25 100644 --- a/src/qml/debugger/qqmlprofiler_p.h +++ b/src/qml/debugger/qqmlprofiler_p.h @@ -69,7 +69,7 @@ QT_BEGIN_NAMESPACE #define Q_QML_PROFILE(feature, profiler, Method) #define Q_QML_OC_PROFILE(member, Code) -struct QQmlProfiler {}; +class QQmlProfiler {}; struct QQmlBindingProfiler { diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h index 3b589a41f1..8e2eec03d2 100644 --- a/src/qml/jsruntime/qv4debugging_p.h +++ b/src/qml/jsruntime/qv4debugging_p.h @@ -61,8 +61,9 @@ namespace Debugging { #ifdef QT_NO_QML_DEBUGGER -struct Debugger +class Debugger { +public: bool pauseAtNextOpportunity() const { return false; } void maybeBreakAtInstruction() {} void enteringFunction() {} diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index f75ac4d33a..9de597ad0e 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE namespace QV4 { namespace Profiling { -struct Profiler {}; +class Profiler {}; } } -- cgit v1.2.3 From 5dd9c684e0a9a36a3cde047f77b5da93907e96be Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 18 Jan 2017 09:30:47 +0100 Subject: Doc: Improve introduction to Qt Quick SceneGraph Renderer Mention that the new backends are introduced with Qt 5.8. Also remove some details that rather belong in subsections, in particular the mentioning that the Qt Quick API's originally were designed for OpenGL. It is unclear what consequences this has for the user. Limitations on backends should be rather spelled out in the respective subsections. Change-Id: I21239ea99b89b4c7771e3d79a38c6aa39007d0ea Reviewed-by: Laszlo Agocs Reviewed-by: Andy Nichols Reviewed-by: Leena Miettinen --- src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc index 9ce26e1bb8..c9ad9d8065 100644 --- a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc +++ b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc @@ -31,18 +31,14 @@ \section1 Scene Graph Adaptations in Qt Quick -Originally Qt Quick only had one available renderer for parsing the scene graph -and rendering the results to a render target. This renderer is now the default -OpenGL Renderer which supports rendering either using the OpenGL ES 2.0 or -OpenGL 2.0 (with framebuffer object extensions) APIs. The Qt Quick APIs have -originally been designed with the assumption that OpenGL is always available. -However, it is now possible to use other graphics API's to render Qt Quick -scenes using the scene graph APIs. +Originally Qt Quick always relied on OpenGL (OpenGL ES 2.0 or OpenGL 2.0) for parsing +the scene graph and rendering the results to a render target. From Qt 5.8 onwards +Qt Quick also supports rendering in software and with Direct3D 12. \section1 Switching between the adaptation used by the application -The default of the OpenGL, or - in Qt builds with disabled OpenGL support - the -software adaptation, can be overridden either by using an environment variable +The default rendering backend is still OpenGL, or - in Qt builds with disabled OpenGL support - +the software renderer. This can be overridden either by using an environment variable or a C++ API. The former consists of setting the \c{QT_QUICK_BACKEND} or the legacy \c{QMLSCENE_DEVICE} environment variable before launching applications. The latter is done by calling QQuickWindow::setSceneGraphBackend() early in the -- cgit v1.2.3 From 814d15c5255cf4a46419c21d5f193bb1a499f9f4 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 1 Feb 2017 12:06:26 +0100 Subject: fix memory leak in QQuickWindowPrivate::deliverTouchAsMouse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A QTouchEvent is allocated with a reduced subset of TouchPoints for each Item to which we attempt to deliver it, and thrown away afterwards. (Ιt's not efficient to heap-allocate it, but we can't avoid doing it at all without changing behavior.) So now it's stored in a QScopedPointer. Change-Id: I48badb493610d0a715e582a2eedae95e2006eb2b Reviewed-by: Jan Arve Sæther --- src/quick/items/qquickwindow.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 5edfd619ec..e9108b7bda 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -628,8 +628,8 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve // FIXME: make this work for mouse events too and get rid of the asTouchEvent in here. Q_ASSERT(pointerEvent->asPointerTouchEvent()); - QTouchEvent *event = pointerEvent->asPointerTouchEvent()->touchEventForItem(item); - if (!event) + QScopedPointer event(pointerEvent->asPointerTouchEvent()->touchEventForItem(item)); + if (event.isNull()) return false; // For each point, check if it is accepted, if not, try the next point. @@ -646,7 +646,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve break; qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << p.id() << "->" << item; - QScopedPointer mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event, item, false)); + QScopedPointer mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event.data(), item, false)); // Send a single press and see if that's accepted QCoreApplication::sendEvent(item, mousePress.data()); @@ -660,7 +660,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve pointerEventPoint->setGrabber(item); if (checkIfDoubleClicked(event->timestamp())) { - QScopedPointer mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event, item, false)); + QScopedPointer mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event.data(), item, false)); QCoreApplication::sendEvent(item, mouseDoubleClick.data()); event->setAccepted(mouseDoubleClick->isAccepted()); if (!mouseDoubleClick->isAccepted()) { @@ -677,7 +677,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve } else if (touchMouseDevice == device && p.id() == touchMouseId) { if (p.state() & Qt::TouchPointMoved) { if (QQuickItem *mouseGrabberItem = q->mouseGrabberItem()) { - QScopedPointer me(touchToMouseEvent(QEvent::MouseMove, p, event, mouseGrabberItem, false)); + QScopedPointer me(touchToMouseEvent(QEvent::MouseMove, p, event.data(), mouseGrabberItem, false)); QCoreApplication::sendEvent(item, me.data()); event->setAccepted(me->isAccepted()); if (me->isAccepted()) { @@ -688,7 +688,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve // no grabber, check if we care about mouse hover // FIXME: this should only happen once, not recursively... I'll ignore it just ignore hover now. // hover for touch??? - QScopedPointer me(touchToMouseEvent(QEvent::MouseMove, p, event, item, false)); + QScopedPointer me(touchToMouseEvent(QEvent::MouseMove, p, event.data(), item, false)); if (lastMousePosition.isNull()) lastMousePosition = me->windowPos(); QPointF last = lastMousePosition; @@ -706,7 +706,7 @@ bool QQuickWindowPrivate::deliverTouchAsMouse(QQuickItem *item, QQuickPointerEve } else if (p.state() & Qt::TouchPointReleased) { // currently handled point was released if (QQuickItem *mouseGrabberItem = q->mouseGrabberItem()) { - QScopedPointer me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event, mouseGrabberItem, false)); + QScopedPointer me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event.data(), mouseGrabberItem, false)); QCoreApplication::sendEvent(item, me.data()); if (item->acceptHoverEvents() && p.screenPos() != QGuiApplicationPrivate::lastCursorPosition) { -- cgit v1.2.3 From 29a278ed0222c70b4ac4d00ccf44b4cf0d66360c Mon Sep 17 00:00:00 2001 From: Joni Poikelin Date: Wed, 1 Feb 2017 08:56:34 +0200 Subject: Fix regression with UniformAnimator target property validation Task-number: QTBUG-58549 Change-Id: Iaa2a9cd8b86e8c2bb7e20b99fabad99d0bd51799 Reviewed-by: Laszlo Agocs --- src/quick/items/qquickshadereffect.cpp | 5 +++++ src/quick/items/qquickshadereffect_p.h | 2 ++ src/quick/util/qquickanimatorjob.cpp | 4 +++- 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp index 7926607e33..436d7b33ce 100644 --- a/src/quick/items/qquickshadereffect.cpp +++ b/src/quick/items/qquickshadereffect.cpp @@ -873,4 +873,9 @@ void QQuickShaderEffectPrivate::updatePolish() q->m_impl->maybeUpdateShaders(); } +bool QQuickShaderEffect::isOpenGLShaderEffect() const +{ + return m_glImpl != Q_NULLPTR; +} + QT_END_NAMESPACE diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h index 7885daffbb..d269dc5e50 100644 --- a/src/quick/items/qquickshadereffect_p.h +++ b/src/quick/items/qquickshadereffect_p.h @@ -117,6 +117,8 @@ public: bool isComponentComplete() const; QString parseLog(); + bool isOpenGLShaderEffect() const; + Q_SIGNALS: void fragmentShaderChanged(); void vertexShaderChanged(); diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp index 1176cf1ff7..33569c4784 100644 --- a/src/quick/util/qquickanimatorjob.cpp +++ b/src/quick/util/qquickanimatorjob.cpp @@ -46,6 +46,7 @@ #if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl) # include # include +# include #endif #include @@ -558,7 +559,8 @@ QQuickUniformAnimatorJob::QQuickUniformAnimatorJob() void QQuickUniformAnimatorJob::setTarget(QQuickItem *target) { - if (qobject_cast(target) != 0) + QQuickShaderEffect* effect = qobject_cast(target); + if (effect && effect->isOpenGLShaderEffect()) m_target = target; } -- cgit v1.2.3 From 53074cdc43ad3a78efd2349fc819d187cb92c5cc Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Wed, 1 Feb 2017 19:50:11 +0800 Subject: Fix libs build with msvc on Chinese locale on Windows Chinese locale means Code Page 936 here. It's also related with removing C4819 warnings. And it's also following Conventions in Qt source code: All code is ascii only (7-bit characters only, run man ascii if unsure) See also http://wiki.qt.io/Coding_Conventions Task-number: QTBUG-56155 Task-number: QTBUG-58161 Change-Id: I1c38a6ce74670716f730663edbcdec3919b438c2 Reviewed-by: Friedemann Kleint --- src/qml/compiler/qv4ssa.cpp | 4 ++-- src/qml/jit/qv4regalloc.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index deba41ef9d..27e53e580a 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -5727,10 +5727,10 @@ MoveMapping::Action MoveMapping::schedule(const Move &m, QList &todo, QLis // References: // [Wimmer1] C. Wimmer and M. Franz. Linear Scan Register Allocation on SSA Form. In Proceedings of -// CGO’10, ACM Press, 2010 +// CGO'10, ACM Press, 2010 // [Wimmer2] C. Wimmer and H. Mossenbock. Optimized Interval Splitting in a Linear Scan Register // Allocator. In Proceedings of the ACM/USENIX International Conference on Virtual -// Execution Environments, pages 132–141. ACM Press, 2005. +// Execution Environments, pages 132-141. ACM Press, 2005. // [Briggs] P. Briggs, K.D. Cooper, T.J. Harvey, and L.T. Simpson. Practical Improvements to the // Construction and Destruction of Static Single Assignment Form. // [Appel] A.W. Appel. Modern Compiler Implementation in Java. Second edition, Cambridge diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp index b168a1e2ba..124717680c 100644 --- a/src/qml/jit/qv4regalloc.cpp +++ b/src/qml/jit/qv4regalloc.cpp @@ -1954,10 +1954,10 @@ void RegisterAllocator::dump(IR::Function *function) const // References: // [Wimmer1] C. Wimmer and M. Franz. Linear Scan Register Allocation on SSA Form. In Proceedings of -// CGO’10, ACM Press, 2010 +// CGO'10, ACM Press, 2010 // [Wimmer2] C. Wimmer and H. Mossenbock. Optimized Interval Splitting in a Linear Scan Register // Allocator. In Proceedings of the ACM/USENIX International Conference on Virtual -// Execution Environments, pages 132–141. ACM Press, 2005. +// Execution Environments, pages 132-141. ACM Press, 2005. // [Traub] Omri Traub, Glenn Holloway, and Michael D. Smith. Quality and Speed in Linear-scan // Register Allocation. In Proceedings of the ACM SIGPLAN 1998 Conference on Programming -// Language Design and Implementation, pages 142–151, June 1998. +// Language Design and Implementation, pages 142-151, June 1998. -- cgit v1.2.3 From 9a009ccde8bfc522578533a114396a5e762d6d8f Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 1 Feb 2017 14:55:03 +0100 Subject: Prevent propagating results of a phi node into another phi node .. of the same basic block. Phi nodes are "executed in parallel", so such a situation will lead to interesting results. Task-number: QTBUG-58553 Change-Id: Ibed439df91d46ea416dcb0a20457310e91dce8b4 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4ssa.cpp | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 27e53e580a..220bdc10b4 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -3580,16 +3580,43 @@ public: , _replacement(0) {} - void operator()(Temp *toReplace, Expr *replacement, StatementWorklist &W, QVector *newUses = 0) + bool operator()(Temp *toReplace, Expr *replacement, StatementWorklist &W, QVector *newUses = 0) { Q_ASSERT(replacement->asTemp() || replacement->asConst() || replacement->asName()); -// qout << "Replacing ";toReplace->dump(qout);qout<<" by ";replacement->dump(qout);qout< &uses = _defUses.uses(*_toReplace); + + // Prevent the following: + // L3: + // %1 = phi L1: %2, L2: %3 + // %4 = phi L1: %5, L2: %6 + // %6 = %1 + // From turning into: + // L3: + // %1 = phi L1: %2, L2: %3 + // %4 = phi L1: %5, L2: %1 + // + // Because both phi nodes are "executed in parallel", we cannot replace %6 by %1 in the + // second phi node. So, if the defining statement for a temp is a phi node, and one of the + // uses of the to-be-replaced statement is a phi node in the same block as the defining + // statement, bail out. + if (Temp *r = _replacement->asTemp()) { + if (_defUses.defStmt(*r)->asPhi()) { + BasicBlock *replacementDefBlock = _defUses.defStmtBlock(*r); + foreach (Stmt *use, uses) { + if (Phi *usePhi = use->asPhi()) { + if (_defUses.defStmtBlock(*usePhi->targetTemp) == replacementDefBlock) + return false; + } + } + } + } + +// qout << "Replacing ";toReplace->dump(qout);qout<<" by ";replacement->dump(qout);qout<reserve(uses.size()); @@ -3605,6 +3632,7 @@ public: qSwap(_replacement, replacement); qSwap(_toReplace, toReplace); + return true; } private: @@ -4081,11 +4109,12 @@ void optimizeSSA(StatementWorklist &W, DefUses &defUses, DominatorTree &df) // copy propagation: if (Temp *sourceTemp = m->source->asTemp()) { QVector newT2Uses; - replaceUses(targetTemp, sourceTemp, W, &newT2Uses); - defUses.removeUse(s, *sourceTemp); - defUses.addUses(*sourceTemp, newT2Uses); - defUses.removeDef(*targetTemp); - W.remove(s); + if (replaceUses(targetTemp, sourceTemp, W, &newT2Uses)) { + defUses.removeUse(s, *sourceTemp); + defUses.addUses(*sourceTemp, newT2Uses); + defUses.removeDef(*targetTemp); + W.remove(s); + } continue; } -- cgit v1.2.3 From 22b03fd6d3efdfa0385ced2450c6c7dfcf555d6e Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Mon, 30 Jan 2017 16:36:46 -0600 Subject: Enable PropertyChanges to correctly restore binding on alias Change-Id: I88ffdd1d1224705e980e449b6c799c9f186143b1 Task-number: QTBUG-58271 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlproperty.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 0b8eb677cb..7df8336f51 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -790,12 +790,12 @@ void QQmlPropertyPrivate::removeBinding(const QQmlProperty &that) QQmlAbstractBinding * QQmlPropertyPrivate::binding(QObject *object, QQmlPropertyIndex index) { + findAliasTarget(object, index, &object, &index); + QQmlData *data = QQmlData::get(object); if (!data) return 0; - findAliasTarget(object, index, &object, &index); - const int coreIndex = index.coreIndex(); const int valueTypeIndex = index.valueTypeIndex(); -- cgit v1.2.3 From bf19d3294f83fc061eddc719bc608bb19e500a5a Mon Sep 17 00:00:00 2001 From: Oleg Yadrov Date: Tue, 24 Jan 2017 16:39:28 -0800 Subject: MouseArea: fix bug preventing dragging from start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The same bounded dragPos values were used for - moving the target item to new position; and - if dragging didn’t start yet, determining whether cursor moved over the threshold distance. It is right for moving the target item, but in the second case it led to that dragging did not start if the distance between item's left border and minimumX (right border and maximumX, top border and minimumY, bottom border and maximumY accordingly) was less than drag.threshold. Task-number: QTBUG-58347 Change-Id: If61a98bf734739323ef19dee6709560b754b2456 Reviewed-by: Andrew den Exter --- src/quick/items/qquickmousearea.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp index 3160495332..2fbca26408 100644 --- a/src/quick/items/qquickmousearea.cpp +++ b/src/quick/items/qquickmousearea.cpp @@ -734,23 +734,34 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event) bool dragY = drag()->axis() & QQuickDrag::YAxis; QPointF dragPos = d->drag->target()->position(); + QPointF boundedDragPos = dragPos; if (dragX) { - dragPos.setX(qBound( + dragPos.setX(startPos.x() + curLocalPos.x() - startLocalPos.x()); + boundedDragPos.setX(qBound( d->drag->xmin(), - startPos.x() + curLocalPos.x() - startLocalPos.x(), + dragPos.x(), d->drag->xmax())); } if (dragY) { - dragPos.setY(qBound( + dragPos.setY(startPos.y() + curLocalPos.y() - startLocalPos.y()); + boundedDragPos.setY(qBound( d->drag->ymin(), - startPos.y() + curLocalPos.y() - startLocalPos.y(), + dragPos.y(), d->drag->ymax())); } + + QPointF targetPos = d->drag->target()->position(); + if (d->drag->active()) - d->drag->target()->setPosition(dragPos); + d->drag->target()->setPosition(boundedDragPos); + + bool dragOverThresholdX = QQuickWindowPrivate::dragOverThreshold(dragPos.x() - startPos.x(), + Qt::XAxis, event, d->drag->threshold()); + bool dragOverThresholdY = QQuickWindowPrivate::dragOverThreshold(dragPos.y() - startPos.y(), + Qt::YAxis, event, d->drag->threshold()); - if (!d->overThreshold && (QQuickWindowPrivate::dragOverThreshold(dragPos.x() - startPos.x(), Qt::XAxis, event, d->drag->threshold()) - || QQuickWindowPrivate::dragOverThreshold(dragPos.y() - startPos.y(), Qt::YAxis, event, d->drag->threshold()))) + if (!d->overThreshold && (((targetPos.x() != boundedDragPos.x()) && dragOverThresholdX) || + ((targetPos.y() != boundedDragPos.y()) && dragOverThresholdY))) { d->overThreshold = true; if (d->drag->smoothed()) -- cgit v1.2.3 From 04c98022d934b5ba0a6492e3556416386ce5d70e Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Fri, 3 Feb 2017 15:42:08 +0100 Subject: Fix move ordering while resolving edges in register allocation When register allocation on an IR in SSA form is done, the last step is to turn the Phi nodes into moves and swaps and put those instructions in the predecessors. As the Phi nodes are conceptually "executed in parallel", this can result in cycles: r1 <- r0 r0 <- r1 These have to be turned into a swap instruction. Also, the moves have to be ordered in order to make sure that no values are overwritten: r1 <- r0 r2 <- r1 Here the two moves need to be switched. The comments in the code document the algorithm. Change-Id: I4151988681f7554b00a3eb70d224e6e2f29ebf04 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4jsir_p.h | 10 +++ src/qml/compiler/qv4ssa.cpp | 146 +++++++++++++++++++++++++------------------ src/qml/compiler/qv4ssa_p.h | 13 ++-- src/qml/jit/qv4regalloc.cpp | 2 + 4 files changed, 104 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 73aa6c4975..a614d3fe1c 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -507,6 +507,16 @@ struct Q_AUTOTEST_EXPORT Temp: Expr { , memberResolver(0) {} + Temp(Type type, Kind kind, unsigned index) + : Expr(TempExpr) + , index(index) + , isReadOnly(0) + , kind(kind) + , memberResolver(0) + { + this->type = type; + } + void init(unsigned kind, unsigned index) { this->index = index; diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 220bdc10b4..45ca56584f 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -5646,25 +5646,97 @@ void MoveMapping::add(Expr *from, Temp *to) { _moves.append(m); } +// Order the moves that are generated when resolving edges during register allocation (see [Wimmer1] +// section 6 for details). Now these moves form one or more graphs, so we have to output them in +// such an order that values don't get overwritten: +// r1 <- r0 +// r2 <- r1 +// That input has to be ordered as follows in order to prevent the value in r1 from being lost: +// r2 <- r1 +// r1 <- r0 +// +// So, the algorithm is to output the leaves first, and take them out of the input. This will result +// in some moves to become leaves (in the above example: when leaf r2 <- r1 is generated and taken +// away, the r1 <- r0 is now a leaf), so we can output those and take those out, and repeat until +// there are no more leafs. +// +// The tricky part is that there might be cycles: +// r4 <- r5 +// r5 <- r4 +// These have to be turned into a "register swap": +// r4 <=> r5 +// +// So after running the above algorithm where we progressively remove the leaves, we are left with +// zero or more cycles. To resolve those, we break one of the edges of the cycle, and for all other +// edges we generate swaps. Note that the swaps will always occur as the last couple of moves, +// because otherwise they might clobber sources for moves: +// r4 <=> r5 +// r6 <- r5 +// Here, the value of r5 is already overwritten with the one in r4, so the correct order is: +// r6 <- r5 +// r4 <=> r5 void MoveMapping::order() { - QList todo = _moves; - QList output, swaps; + QList output; output.reserve(_moves.size()); - QList delayed; - delayed.reserve(_moves.size()); - while (!todo.isEmpty()) { - const Move m = todo.first(); - todo.removeFirst(); - schedule(m, todo, delayed, output, swaps); - } + while (!_moves.isEmpty()) { + // Take out all leaf edges, because we can output them without any problems. + int nextLeaf = findLeaf(); + if (nextLeaf == -1) + break; // No more leafs left, we're done here. + output.append(_moves.takeAt(nextLeaf)); + // Now there might be new leaf edges: any move that had the input of the previously found + // leaf as an output, so loop around. + } + + while (!_moves.isEmpty()) { + // We're now left with one or more cycles. + // Step one: break the/a cycle. + _moves.removeFirst(); + // Step two: find the other edges of the cycle, starting with the one of that is now a leaf. + while (!_moves.isEmpty()) { + int nextLeaf = findLeaf(); + if (nextLeaf == -1) + break; // We're done with this cycle. + Move m = _moves.takeAt(nextLeaf); + // Step three: get the edges from the cycle and turn it into a swap + m.needsSwap = true; + output.append(m); + // Because we took out a leaf, find the next one. + } + // We're done with the cycle, let's see if there are more. + } + + _moves = output; +} - output += swaps; +int MoveMapping::findLeaf() const +{ + for (int i = 0, e = _moves.size(); i != e; ++i) { + // Take an edge from the list... + const Temp *target = _moves.at(i).to; + // ... and see if its target is used as a source... + bool targetUsedAsSource = false; + for (int j = 0; j != e; ++j) { + if (i == j) + continue; - Q_ASSERT(todo.isEmpty()); - Q_ASSERT(delayed.isEmpty()); - qSwap(_moves, output); + Expr *source = _moves.at(j).from; + if (const Temp *sourceTemp = source->asTemp()) { + if (overlappingStorage(*target, *sourceTemp)) { + targetUsedAsSource = true; + break; + } + } + } + // ... if not, we have a leaf edge ... + if (!targetUsedAsSource) + return i; + // .. otherwise we try the next one. + } + + return -1; // No leaf found } QList MoveMapping::insertMoves(BasicBlock *bb, IR::Function *function, bool atEnd) const @@ -5706,54 +5778,6 @@ void MoveMapping::dump() const } } -MoveMapping::Action MoveMapping::schedule(const Move &m, QList &todo, QList &delayed, - QList &output, QList &swaps) const -{ - Moves usages = sourceUsages(m.to, todo) + sourceUsages(m.to, delayed); - foreach (const Move &dependency, usages) { - if (!output.contains(dependency)) { - if (delayed.contains(dependency)) { - // We have a cycle! Break it by swapping instead of assigning. - if (DebugMoveMapping) { - delayed += m; - QBuffer buf; - buf.open(QIODevice::WriteOnly); - QTextStream out(&buf); - IRPrinter printer(&out); - out<<"we have a cycle! temps:" << endl; - foreach (const Move &m, delayed) { - out<<"\t"; - printer.print(m.to); - out<<" <- "; - printer.print(m.from); - out< startEndLoops; }; -class MoveMapping +class Q_AUTOTEST_EXPORT MoveMapping { +#ifdef V4_AUTOTEST +public: +#endif struct Move { Expr *from; Temp *to; bool needsSwap; - Move(Expr *from, Temp *to) - : from(from), to(to), needsSwap(false) + Move(Expr *from, Temp *to, bool needsSwap = false) + : from(from), to(to), needsSwap(needsSwap) {} bool operator==(const Move &other) const @@ -284,9 +287,7 @@ public: void dump() const; private: - enum Action { NormalMove, NeedsSwap }; - Action schedule(const Move &m, QList &todo, QList &delayed, QList &output, - QList &swaps) const; + int findLeaf() const; }; /* diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp index 124717680c..d49fae3096 100644 --- a/src/qml/jit/qv4regalloc.cpp +++ b/src/qml/jit/qv4regalloc.cpp @@ -1134,6 +1134,8 @@ private: mapping.add(moveFrom, moveTo); } + if (DebugRegAlloc) + mapping.dump(); mapping.order(); if (DebugRegAlloc) mapping.dump(); -- cgit v1.2.3 From be96a21a3706d46f00a1f8609fcd19ee5760c121 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Sun, 5 Feb 2017 10:33:43 +0100 Subject: Implement QAccessibleQuickWindow::focusChild MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we post a focus change notification, VoiceOver verifies what the application thinks is focused. Without this function, when moving the keyboard focus (e.g. by pressing tab) the VO focus will not follow. [ChangeLog][QtQuick][Accessibility] Fixed focus handling so that keyboard and VoiceOver's virtual focus are in sync (QTBUG-58340). Task-number: QTBUG-58340 Change-Id: I7d4871c13b36c3ab9241614ca8a06452461e3cd1 Reviewed-by: Timur Pocheptsov Reviewed-by: Jan Arve Sæther --- src/quick/accessible/qaccessiblequickview.cpp | 8 ++++++++ src/quick/accessible/qaccessiblequickview_p.h | 1 + 2 files changed, 9 insertions(+) (limited to 'src') diff --git a/src/quick/accessible/qaccessiblequickview.cpp b/src/quick/accessible/qaccessiblequickview.cpp index 222690e4f2..b3d1b6fc0f 100644 --- a/src/quick/accessible/qaccessiblequickview.cpp +++ b/src/quick/accessible/qaccessiblequickview.cpp @@ -81,6 +81,14 @@ QAccessibleInterface *QAccessibleQuickWindow::child(int index) const return 0; } +QAccessibleInterface *QAccessibleQuickWindow::focusChild() const +{ + QObject *focusObject = window()->focusObject(); + if (focusObject) + return QAccessible::queryAccessibleInterface(focusObject); + return nullptr; +} + QAccessible::Role QAccessibleQuickWindow::role() const { return QAccessible::Window; // FIXME diff --git a/src/quick/accessible/qaccessiblequickview_p.h b/src/quick/accessible/qaccessiblequickview_p.h index 007a6fd990..fcd0bec85e 100644 --- a/src/quick/accessible/qaccessiblequickview_p.h +++ b/src/quick/accessible/qaccessiblequickview_p.h @@ -65,6 +65,7 @@ public: QAccessibleInterface *parent() const; QAccessibleInterface *child(int index) const; + QAccessibleInterface *focusChild() const override; QAccessible::Role role() const; QAccessible::State state() const; -- cgit v1.2.3 From ce15c3af57858b9b8b0621398121691b20c6f638 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Wed, 25 Jan 2017 15:49:34 +0100 Subject: QQuickMouseArea: only start pressAndHoldTimer for accepted events Most likely because of changes done to mouse event handling in 5.8, a QQuickMouseArea can now get a mousePressEvent call without a subsequent mouseReleaseEvent call if the press event was rejected. A regression seen from this is that QQuickMouseArea starts a pressAndHold timer upon receiving mouse press, which will never be 'cancelled' since the following mouse release is sent elsewhere. As a result, TextArea in QtQuickControls will e.g receive a pressAndHold signal each time the user touches the control, which again will cause weird behavior like selecting words and messing with focus on iOS. This patch will instead change this so that we only start the pressAndHold timer if QQuickMouseArea accepts the mouse press event. Change-Id: I43e2f02e2b4f75e7b6761e326e3fec54ea97683a Reviewed-by: Shawn Rutledge Reviewed-by: Frederik Gladhorn --- src/quick/items/qquickmousearea.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp index 2fbca26408..4dcefc700d 100644 --- a/src/quick/items/qquickmousearea.cpp +++ b/src/quick/items/qquickmousearea.cpp @@ -685,9 +685,10 @@ void QQuickMouseArea::mousePressEvent(QMouseEvent *event) #endif setHovered(true); d->startScene = event->windowPos(); - d->pressAndHoldTimer.start(QGuiApplication::styleHints()->mousePressAndHoldInterval(), this); setKeepMouseGrab(d->stealMouse); event->setAccepted(setPressed(event->button(), true, event->source())); + if (event->isAccepted()) + d->pressAndHoldTimer.start(QGuiApplication::styleHints()->mousePressAndHoldInterval(), this); } } -- cgit v1.2.3 From 6cfeabe92db25a10812a657f7f4fdadfb505204d Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 26 Jan 2017 16:44:55 +0100 Subject: Flickable: handle child mouse ungrab when hidden or disabled If Flickable got hidden while a child had mouse grab, it ignored the mouse ungrab event of the child mouse grabber, and got therefore stuck in pressed state. Consequently, item view transitions were not executed since the item view though it was being pressed. Task-number: QTBUG-58453 Change-Id: I76f9f3190c3a95a2fafdce036d69ea1dc8127434 Reviewed-by: Qt CI Bot Reviewed-by: Frederik Gladhorn --- src/quick/items/qquickflickable.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 1e778306e0..537367b3a3 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -2307,8 +2307,11 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event) bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e) { Q_D(QQuickFlickable); - if (!isVisible() || !isEnabled() || !isInteractive()) + if (!isVisible() || !isEnabled() || !isInteractive()) { + d->cancelInteraction(); return QQuickItem::childMouseEventFilter(i, e); + } + switch (e->type()) { case QEvent::MouseButtonPress: case QEvent::MouseMove: -- cgit v1.2.3 From ade0ed7fa9ad06a1dc1312e7abad8baf20f7b756 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 6 Feb 2017 09:37:13 +0100 Subject: Improve QQuickAsyncImageProvider example Also link it from more places Change-Id: Ib5fbf89f4a039f885e918d57ee477e9788049d8d Reviewed-by: Robin Burchell --- src/quick/util/qquickimageprovider.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp index 0c245d2b23..d2a8a5097c 100644 --- a/src/quick/util/qquickimageprovider.cpp +++ b/src/quick/util/qquickimageprovider.cpp @@ -158,6 +158,8 @@ QQuickTextureFactory *QQuickTextureFactory::textureFactoryForImage(const QImage If you are using QRunnable as base for your QQuickImageResponse ensure automatic deletion is disabled. + See the \l {imageresponseprovider}{Image Response Provider Example} for a complete implementation. + \sa QQuickImageProvider */ @@ -472,6 +474,8 @@ QQuickTextureFactory *QQuickImageProvider::requestTexture(const QString &id, QSi \inmodule QtQuick \brief The QQuickAsyncImageProvider class provides an interface for for asynchronous control of QML image requests. + See the \l {imageresponseprovider}{Image Response Provider Example} for a complete implementation. + \sa QQuickImageProvider */ QQuickAsyncImageProvider::QQuickAsyncImageProvider() -- cgit v1.2.3 From fedcd26ce80451e113b963d09cad97a3d21e4ab8 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 8 Feb 2017 16:53:58 +0100 Subject: Use QQmlType for looking up enums, even on singletons QQmlType has more information than the bare QMetaType. The optimizer already uses it for looking up enums, so some code would behave differently, depending on whether the optimizer was enabled or not. In some cases we cannot use QQmlType for lookup of enums because QQmlType might have been created with only a callback. The object only shows up later in that case. Then the only thing we can do is query the metatype. We can test this by adding an eval() because eval() disables optimization for the surrounding code. Task-number: QTBUG-58394 Change-Id: I8c90591b19fe1ed3e5339d877f9e6ec7c6f9aa73 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmltypewrapper.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index fd1e9cc2be..be4ab68831 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -129,15 +129,20 @@ ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, Q return w.asReturnedValue(); } -static int enumForSingleton(String *name, QObject *qobjectSingleton) +static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qobjectSingleton, + QQmlType *type) { + bool ok; + int value = type->enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); + if (ok) + return value; + // ### Optimize QByteArray enumName = name->toQString().toUtf8(); const QMetaObject *metaObject = qobjectSingleton->metaObject(); for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) { QMetaEnum e = metaObject->enumerator(ii); - bool ok; - int value = e.keyToValue(enumName.constData(), &ok); + value = e.keyToValue(enumName.constData(), &ok); if (ok) return value; } @@ -183,7 +188,7 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope // check for enum value const bool includeEnums = w->d()->mode == Heap::QmlTypeWrapper::IncludeEnums; if (includeEnums && name->startsWithUpper()) { - const int value = enumForSingleton(name, qobjectSingleton); + const int value = enumForSingleton(v4, name, qobjectSingleton, type); if (value != -1) return QV4::Primitive::fromInt32(value).asReturnedValue(); } @@ -196,7 +201,7 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope // Warn when attempting to access a lowercased enum value, singleton case if (!ok && includeEnums && !name->startsWithUpper()) { - const int value = enumForSingleton(name, qobjectSingleton); + const int value = enumForSingleton(v4, name, qobjectSingleton, type); if (value != -1) return throwLowercaseEnumError(v4, name, type); } -- cgit v1.2.3 From aaa8b16bbda4e18c6afce50d91d81bc5ee862f64 Mon Sep 17 00:00:00 2001 From: Frederik Schwarzer Date: Mon, 9 Jan 2017 16:42:59 +0100 Subject: Minor wording issues and typo fixes in docs Change-Id: I60af106607dca02fafc1df2d21d16053d64742b6 Reviewed-by: Leena Miettinen --- src/quick/doc/src/concepts/positioning/topic.qdoc | 2 +- src/quick/doc/src/concepts/visualcanvas/visualparent.qdoc | 2 +- src/quick/items/qquickitem.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/quick/doc/src/concepts/positioning/topic.qdoc b/src/quick/doc/src/concepts/positioning/topic.qdoc index 92113ece54..b28acd1f89 100644 --- a/src/quick/doc/src/concepts/positioning/topic.qdoc +++ b/src/quick/doc/src/concepts/positioning/topic.qdoc @@ -112,7 +112,7 @@ them, and where possible, pristine Anchor layouts should be preferred. \section1 Anchors -Anchors allows an item to be placed either adjacent to or inside of another, +Anchors allow an item to be placed either adjacent to or inside of another, by attaching one or more of the item's anchor-points (boundaries) to an anchor-point of the other. These anchors will remain even if the dimensions or location of one of the items changes, allowing for highly dynamic diff --git a/src/quick/doc/src/concepts/visualcanvas/visualparent.qdoc b/src/quick/doc/src/concepts/visualcanvas/visualparent.qdoc index fd5bf51307..f971043b58 100644 --- a/src/quick/doc/src/concepts/visualcanvas/visualparent.qdoc +++ b/src/quick/doc/src/concepts/visualcanvas/visualparent.qdoc @@ -125,7 +125,7 @@ the blue rectangle and beneath any of the blue rectangle's children. Stacking order can be influenced with the \l Item::z property. Z values below 0 will stack below the parent, and if z values are assigned then siblings will stack in z-order (with creation order used to break ties). Z values only affect -stacking compared to siblings and the parent item. If you have an item who is obscured by a subtree rooted above its +stacking compared to siblings and the parent item. If you have an item which is obscured by a subtree rooted above its parent item, no z value on that item will increase its stacking order to stack above that subtree. To stack that item above the other subtree you'll have to alter z values farther up in the hierarchy, or re-arrange the visual item hierarchy. diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index cbfd776941..98dee17291 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -3751,10 +3751,10 @@ QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData() /*! This function is called when an item should release graphics - resources which are not already managed by the nodes returend from + resources which are not already managed by the nodes returned from QQuickItem::updatePaintNode(). - This happens when the item is about to be removed from window it + This happens when the item is about to be removed from the window it was previously rendering to. The item is guaranteed to have a \l {QQuickItem::window()}{window} when the function is called. -- cgit v1.2.3 From 6a2cf39758249d790f642d677c7bc7cad2a70eae Mon Sep 17 00:00:00 2001 From: Frederik Schwarzer Date: Thu, 5 Jan 2017 17:15:48 +0100 Subject: Finish sentence properly in documentation Change-Id: I9bdae64a2d1b38c0b3f1b7f4cf460b3466d45dad Reviewed-by: Leena Miettinen --- src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc b/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc index 20a6d131f5..e5834eb5c8 100644 --- a/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc +++ b/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc @@ -64,7 +64,7 @@ In addition to the above features, GridLayout adds these features: \list \li \l{Layout::row}{Grid coordinates} can be specified with the \l{Layout::row}{Layout.row} and - \l{Layout::column}{Layout.column}. + \l{Layout::column}{Layout.column} properties. \li \l{GridLayout::flow}{Automatic grid coordinates} used together with the \l{GridLayout::flow}{flow}, \l{GridLayout::rows}{rows}, and \l{GridLayout::columns}{columns} properties. -- cgit v1.2.3 From 7454ad3ce1895eae7409df28752739cc912abcac Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 15 Feb 2017 12:50:38 +0100 Subject: Shaders: Fix crash when disconnecting shaders from item properties The disconnect was done with a signal index local to the item, instead of 'global' to the item and all its parents. The index also had to be a method index, not a signal index. Together this resulted in a failing disconnect, which would keep SlotObjects alive with outdated data. Any subsequent use would result in a crash. Task-number: QTBUG-58336 Change-Id: I26b1868b2f8c61a4ffab1c72c85178632ca87599 Reviewed-by: Simon Hausmann --- src/quick/items/qquickopenglshadereffect.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickopenglshadereffect.cpp b/src/quick/items/qquickopenglshadereffect.cpp index b974641cca..c7b851d33e 100644 --- a/src/quick/items/qquickopenglshadereffect.cpp +++ b/src/quick/items/qquickopenglshadereffect.cpp @@ -256,10 +256,14 @@ void QQuickOpenGLShaderEffectCommon::connectPropertySignals(QQuickItem *item, qWarning("QQuickOpenGLShaderEffect: property '%s' does not have notification method!", d.name.constData()); } else { auto *mapper = signalMappers[shaderType].at(i); - mapper->setSignalIndex(pd->notifyIndex()); + mapper->setSignalIndex(itemMetaObject->property(d.propertyIndex).notifySignal().methodIndex()); Q_ASSERT(item->metaObject() == itemMetaObject); - QObjectPrivate::connectImpl(item, mapper->signalIndex(), item, nullptr, mapper, - Qt::AutoConnection, nullptr, itemMetaObject); + bool ok = QObjectPrivate::connectImpl(item, pd->notifyIndex(), item, nullptr, mapper, + Qt::AutoConnection, nullptr, itemMetaObject); + if (!ok) + qWarning() << "Failed to connect to property" << itemMetaObject->property(d.propertyIndex).name() + << "(" << d.propertyIndex << ", signal index" << pd->notifyIndex() + << ") of item" << item; } } else { // If the source is set via a dynamic property, like the layer is, then we need this -- cgit v1.2.3 From c934c5a2d2b32e7657ca1b79b1a70f96e1019f8a Mon Sep 17 00:00:00 2001 From: Stephan Binner Date: Mon, 20 Feb 2017 13:39:03 +0100 Subject: Fix build without features.cursor Change-Id: I20821e5fd4d2154aa49ef90015d512dd09c134f3 Reviewed-by: Simon Hausmann --- src/quick/items/qquickitem.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 98dee17291..021ca9b64b 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2855,14 +2855,15 @@ void QQuickItemPrivate::addChild(QQuickItem *child) childItems.append(child); -#if QT_CONFIG(cursor) QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child); +#if QT_CONFIG(cursor) // if the added child has a cursor and we do not currently have any children // with cursors, bubble the notification up if (childPrivate->subtreeCursorEnabled && !subtreeCursorEnabled) setHasCursorInChild(true); #endif + if (childPrivate->subtreeHoverEnabled && !subtreeHoverEnabled) setHasHoverInChild(true); @@ -2883,13 +2884,14 @@ void QQuickItemPrivate::removeChild(QQuickItem *child) childItems.removeOne(child); Q_ASSERT(!childItems.contains(child)); -#if QT_CONFIG(cursor) QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child); +#if QT_CONFIG(cursor) // turn it off, if nothing else is using it if (childPrivate->subtreeCursorEnabled && subtreeCursorEnabled) setHasCursorInChild(false); #endif + if (childPrivate->subtreeHoverEnabled && subtreeHoverEnabled) setHasHoverInChild(false); -- cgit v1.2.3 From 74ba609f0e1a903ce516b56544916fbd06f5b7a6 Mon Sep 17 00:00:00 2001 From: Stephan Binner Date: Wed, 22 Feb 2017 13:04:22 +0100 Subject: Fix build for -no-feature-quick-sprite Change-Id: I864b436b7cb1e1fedb15555f53951987dc74012c Reviewed-by: Simon Hausmann --- src/imports/imports.pro | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/imports/imports.pro b/src/imports/imports.pro index c49c05956d..b030cbcf73 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -1,5 +1,7 @@ TEMPLATE = subdirs +QT_FOR_CONFIG += quick-private + SUBDIRS += \ builtins \ qtqml \ @@ -17,7 +19,7 @@ qtHaveModule(quick) { window \ testlib - qtConfig(opengl(es1|es2)?): \ + qtConfig(quick-sprite):qtConfig(opengl(es1|es2)?): \ SUBDIRS += particles } -- cgit v1.2.3 From fe5d69669197a51662061b014810f0242eec5ca7 Mon Sep 17 00:00:00 2001 From: Robert Griebl Date: Thu, 23 Feb 2017 15:11:13 +0100 Subject: Fix QQmlExpression leaking QQmlError objects If the user doesn't clear any potential errors manually via clearError(), then do it automatically in the destructor. Found with valgrind. [ChangeLog][QtQml][QQmlExpression] Fixed memory leak Change-Id: If5b1181850c7463c939a7ba536d74e7054c53d60 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlexpression.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index 94b1eaab52..adfa1c2674 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -202,6 +202,7 @@ QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope, */ QQmlExpression::~QQmlExpression() { + clearError(); } /*! -- cgit v1.2.3 From aa0e51beaba1a338db42391c575212b4aac815b1 Mon Sep 17 00:00:00 2001 From: Stephan Binner Date: Fri, 24 Feb 2017 09:50:25 +0100 Subject: Add feature.qml-profiler with extended build dependencies Change-Id: If165cea6f176e7a7066f50b73261baf97634a0bb Reviewed-by: Ulf Hermann --- src/qml/configure.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src') diff --git a/src/qml/configure.json b/src/qml/configure.json index d22ba3b8f0..2c4887365f 100644 --- a/src/qml/configure.json +++ b/src/qml/configure.json @@ -22,6 +22,19 @@ "label": "QML network support", "purpose": "Provides network transparency for QML", "output": [ "publicFeature" ] + }, + "qml-profiler": { + "label": "Command line QML Profiler", + "purpose": "The QML Profiler retrieves QML tracing data from an application.", + "condition": [ + "features.commandlineparser", + "features.localserver", + "features.process", + "features.qml-debug", + "features.qml-network", + "features.xmlstreamwriter" + ], + "output": [ "privateFeature" ] } }, -- cgit v1.2.3 From 4e6bd8456fb5b20239f7a2a8597edfa05dfc6071 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 15 Feb 2017 15:21:21 +0100 Subject: V4 JIT: Store the NaNEncodeMask in a register on 64bit When a callee saved register is available on 64bit platforms, put the Value::NaNEncodeMask in it. This saves one instruction for every load or store of doubles. Change-Id: I57262988610996e6a912e97d3026d4bb8ce26fe8 Reviewed-by: Simon Hausmann Reviewed-by: Qt CI Bot --- src/qml/jit/qv4assembler.cpp | 2 ++ src/qml/jit/qv4assembler_p.h | 23 ++++++++--------------- src/qml/jit/qv4targetplatform_p.h | 28 +++++++++++++++++++++++++--- 3 files changed, 35 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index a2cb56abbe..ad8a5823e2 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -356,6 +356,8 @@ void Assembler::enterStandardStackFrame(const RegisterInfor slotAddr.offset -= RegisterSize; storePtr(regularRegistersToSave.at(i).reg(), slotAddr); } + + platformFinishEnteringStandardStackFrame(this); } template diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index fd65c9b3d2..720c522e1d 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -387,32 +387,28 @@ struct RegisterSizeDependentAssemblerload64(addr, TargetPlatform::ReturnValueRegister); - as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister); - as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister); + as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister); as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest); } static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr) { as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister); - as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister); - as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister); + as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister); as->store64(TargetPlatform::ReturnValueRegister, addr); } static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target) { as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister); - as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister); - as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister); + as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister); Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target); as->store64(TargetPlatform::ReturnValueRegister, ptr); } static void storeReturnValue(JITAssembler *as, FPRegisterID dest) { - as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister); - as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister); + as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister); as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest); } @@ -427,16 +423,13 @@ struct RegisterSizeDependentAssemblertype == IR::DoubleType) { as->moveDoubleTo64((FPRegisterID) t->index, TargetPlatform::ReturnValueRegister); - as->move(TrustedImm64(QV4::Value::NaNEncodeMask), - TargetPlatform::ScratchRegister); - as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister); + as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister); } else if (t->type == IR::UInt32Type) { RegisterID srcReg = (RegisterID) t->index; Jump intRange = as->branch32(RelationalCondition::GreaterThanOrEqual, srcReg, TrustedImm32(0)); as->convertUInt32ToDouble(srcReg, TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister); as->moveDoubleTo64(TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister); - as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister); - as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister); + as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister); Jump done = as->jump(); intRange.link(as); as->zeroExtend32ToPtr(srcReg, TargetPlatform::ReturnValueRegister); @@ -611,8 +604,7 @@ struct RegisterSizeDependentAssemblerbranch32(RelationalCondition::GreaterThan, TargetPlatform::ScratchRegister, TrustedImm32(0)); // it's a double - as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister); - as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister); + as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister); as->move64ToDouble(TargetPlatform::ReturnValueRegister, TargetPlatform::FPGpr0); Jump success = as->branchTruncateDoubleToInt32(TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister, @@ -718,6 +710,7 @@ public: using JITTargetPlatform::registerForArgument; using JITTargetPlatform::FPGpr0; using JITTargetPlatform::platformEnterStandardStackFrame; + using JITTargetPlatform::platformFinishEnteringStandardStackFrame; using JITTargetPlatform::platformLeaveStandardStackFrame; using RegisterSizeDependentOps = RegisterSizeDependentAssembler, MacroAssembler, JITTargetPlatform, RegisterSize>; diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h index fcc600eb2e..d9f8034b1f 100644 --- a/src/qml/jit/qv4targetplatform_p.h +++ b/src/qml/jit/qv4targetplatform_p.h @@ -55,6 +55,7 @@ #if ENABLE(ASSEMBLER) +#include #include "qv4registerinfo_p.h" #include @@ -140,6 +141,7 @@ public: static const int StackShadowSpace = 0; static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU. static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); } + static void platformFinishEnteringStandardStackFrame(PlatformAssembler *) {} static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize) { if (frameSize > 0) @@ -194,6 +196,7 @@ public: static const RegisterID EngineRegister = JSC::X86Registers::r14; static const RegisterID ReturnValueRegister = JSC::X86Registers::eax; static const RegisterID ScratchRegister = JSC::X86Registers::r10; + static const RegisterID DoubleMaskRegister = JSC::X86Registers::r13; static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0; static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1; @@ -209,7 +212,7 @@ public: << RI(JSC::X86Registers::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) // r11 is used as scratch register by the macro assembler << RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) - << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) << RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) << RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) << RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) @@ -244,6 +247,10 @@ public: static const int StackShadowSpace = 0; static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU. static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); } + static void platformFinishEnteringStandardStackFrame(PlatformAssembler *as) + { + as->move(PlatformAssembler::TrustedImm64(QV4::Value::NaNEncodeMask), DoubleMaskRegister); + } static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize) { if (frameSize > 0) @@ -274,6 +281,7 @@ public: static const RegisterID EngineRegister = JSC::X86Registers::r14; static const RegisterID ReturnValueRegister = JSC::X86Registers::eax; static const RegisterID ScratchRegister = JSC::X86Registers::r10; + static const RegisterID DoubleMaskRegister = JSC::X86Registers::r13; static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0; static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1; @@ -289,7 +297,7 @@ public: << RI(JSC::X86Registers::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) // r11 is used as scratch register by the macro assembler << RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) - << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) << RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) << RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) << RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) @@ -322,6 +330,10 @@ public: static const int StackShadowSpace = 32; static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU. static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); } + static void platformFinishEnteringStandardStackFrame(PlatformAssembler *as) + { + as->move(PlatformAssembler::TrustedImm64(QV4::Value::NaNEncodeMask), DoubleMaskRegister); + } static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize) { if (frameSize > 0) @@ -440,6 +452,8 @@ public: as->push(FramePointerRegister); } + static void platformFinishEnteringStandardStackFrame(PlatformAssembler *) {} + static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize) { if (frameSize > 0) { @@ -475,6 +489,7 @@ public: static const RegisterID ScratchRegister = JSC::ARM64Registers::x9; static const RegisterID EngineRegister = JSC::ARM64Registers::x27; static const RegisterID ReturnValueRegister = JSC::ARM64Registers::x0; + static const RegisterID DoubleMaskRegister = JSC::ARM64Registers::x26; static const FPRegisterID FPGpr0 = JSC::ARM64Registers::q0; static const FPRegisterID FPGpr1 = JSC::ARM64Registers::q1; @@ -505,7 +520,7 @@ public: << RI(JSC::ARM64Registers::x23, QStringLiteral("x23"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) << RI(JSC::ARM64Registers::x24, QStringLiteral("x24"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) << RI(JSC::ARM64Registers::x25, QStringLiteral("x25"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) - << RI(JSC::ARM64Registers::x26, QStringLiteral("x26"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::ARM64Registers::x26, QStringLiteral("x26"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) << RI(JSC::ARM64Registers::x27, QStringLiteral("x27"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) << RI(JSC::ARM64Registers::x28, QStringLiteral("x28"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) @@ -572,6 +587,11 @@ public: as->pushPair(FramePointerRegister, JSC::ARM64Registers::lr); } + static void platformFinishEnteringStandardStackFrame(PlatformAssembler *as) + { + as->move(PlatformAssembler::TrustedImm64(QV4::Value::NaNEncodeMask), DoubleMaskRegister); + } + static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize) { if (frameSize > 0) @@ -661,6 +681,8 @@ public: as->push(FramePointerRegister); } + static void platformFinishEnteringStandardStackFrame(PlatformAssembler *) {} + static void platformLeaveStandardStackFrame(PlatformAssembler *as, int frameSize) { if (frameSize > 0) -- cgit v1.2.3 From c4638def5c1e163fc895d3f7991fb0b4b5be9a6d Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 27 Feb 2017 10:05:42 +0100 Subject: Fix old QML compiler builds Do a private export of the IR loader as the code is in QtQml now. Change-Id: If98c38b84d60b2904752c2adb2f9beb5e5e6d774 Reviewed-by: Lars Knoll --- src/qml/compiler/qqmlirbuilder_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 2022112e07..b579a963a1 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -622,7 +622,7 @@ private: int _importedScriptsTemp; }; -struct IRLoader { +struct Q_QML_PRIVATE_EXPORT IRLoader { IRLoader(const QV4::CompiledData::Unit *unit, QmlIR::Document *output); void load(); -- cgit v1.2.3 From 4f3cadfe6c966ab8b7c50bc69343589589f7291c Mon Sep 17 00:00:00 2001 From: Stephan Binner Date: Sat, 25 Feb 2017 13:49:36 +0100 Subject: Fix build for -no-feature-quick-shadereffect Change-Id: I334603209818a8030ddb5b5b316cab596c328bf1 Reviewed-by: Lars Knoll --- src/particles/particles.pri | 10 ++++++++-- src/particles/qquickparticlesmodule.cpp | 6 ++++++ src/quick/items/context2d/qquickcanvasitem.cpp | 1 + src/quick/items/context2d/qquickcontext2d.cpp | 2 ++ src/quick/items/qquickpainteditem_p.h | 1 + 5 files changed, 18 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/particles/particles.pri b/src/particles/particles.pri index af71634ec6..576d826903 100644 --- a/src/particles/particles.pri +++ b/src/particles/particles.pri @@ -1,6 +1,5 @@ HEADERS += \ $$PWD/qquickangledirection_p.h \ - $$PWD/qquickcustomparticle_p.h \ $$PWD/qquickcustomaffector_p.h \ $$PWD/qquickellipseextruder_p.h \ $$PWD/qquicktrailemitter_p.h \ @@ -33,7 +32,6 @@ HEADERS += \ SOURCES += \ $$PWD/qquickangledirection.cpp \ - $$PWD/qquickcustomparticle.cpp \ $$PWD/qquickcustomaffector.cpp \ $$PWD/qquickellipseextruder.cpp \ $$PWD/qquicktrailemitter.cpp \ @@ -63,6 +61,14 @@ SOURCES += \ $$PWD/qquickparticlegroup.cpp \ $$PWD/qquickgroupgoal.cpp +qtConfig(quick-shadereffect) { +HEADERS += \ + $$PWD/qquickcustomparticle_p.h + +SOURCES += \ + $$PWD/qquickcustomparticle.cpp +} + OTHER_FILES += \ $$PWD/shaders/customparticletemplate.vert \ $$PWD/shaders/customparticle.vert \ diff --git a/src/particles/qquickparticlesmodule.cpp b/src/particles/qquickparticlesmodule.cpp index accdb668de..03f47a3961 100644 --- a/src/particles/qquickparticlesmodule.cpp +++ b/src/particles/qquickparticlesmodule.cpp @@ -37,8 +37,12 @@ ** ****************************************************************************/ +#include + #include "qquickangledirection_p.h" +#if QT_CONFIG(quick_shadereffect) #include "qquickcustomparticle_p.h" +#endif #include "qquickellipseextruder_p.h" #include "qquicktrailemitter_p.h" #include "qquickfriction_p.h" @@ -84,7 +88,9 @@ void QQuickParticlesModule::defineModule() qmlRegisterType(uri, 2, 0, "ParticleGroup"); qmlRegisterType(uri, 2, 0, "ImageParticle"); +#if QT_CONFIG(quick_shadereffect) qmlRegisterType(uri, 2, 0, "CustomParticle"); +#endif qmlRegisterType(uri, 2, 0, "ItemParticle"); qmlRegisterType(uri, 2, 0, "Emitter"); diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp index 28e9173bf7..9dd72a40e3 100644 --- a/src/quick/items/context2d/qquickcanvasitem.cpp +++ b/src/quick/items/context2d/qquickcanvasitem.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index bcaedd67b4..05bb3681d7 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -42,7 +42,9 @@ #include "qquickcanvasitem_p.h" #include #include +#if QT_CONFIG(quick_shadereffect) #include +#endif #include #include diff --git a/src/quick/items/qquickpainteditem_p.h b/src/quick/items/qquickpainteditem_p.h index 742e786335..3d2ec631fa 100644 --- a/src/quick/items/qquickpainteditem_p.h +++ b/src/quick/items/qquickpainteditem_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include "qquickpainteditem.h" #include "qquickitem_p.h" #include -- cgit v1.2.3 From 5cd4c2ced4b153f365ececf3a7c0a4536fed9fac Mon Sep 17 00:00:00 2001 From: Stephan Binner Date: Fri, 24 Feb 2017 16:43:51 +0100 Subject: Fix build for -no-feature-quick-path Change-Id: Id57c9bc4421fc252ab02e2a0cfe00d08aef0176d Reviewed-by: Simon Hausmann Reviewed-by: Oswald Buddenhagen Reviewed-by: Ulf Hermann Reviewed-by: Laszlo Agocs --- src/quick/configure.json | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/quick/configure.json b/src/quick/configure.json index 4ed11e8318..e06cae8641 100644 --- a/src/quick/configure.json +++ b/src/quick/configure.json @@ -51,6 +51,7 @@ "quick-canvas": { "label": "Canvas item", "purpose": "Provides the Qt Quick Canvas Item", + "condition": "features.quick-path", "output": [ "privateFeature" ] -- cgit v1.2.3 From 4b949a2eb4e6ab245e8fc5214926c78eff4488da Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Fri, 24 Feb 2017 14:30:23 +0100 Subject: Doc: minor language corrections Change-Id: Ifa031002f4b67f575adebcde8b26d9332fffa8da Reviewed-by: Venugopal Shivashankar --- src/qml/types/qqmlobjectmodel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp index 21205f4490..d926ecb6ce 100644 --- a/src/qml/types/qqmlobjectmodel.cpp +++ b/src/qml/types/qqmlobjectmodel.cpp @@ -178,8 +178,8 @@ public: \ingroup qtquick-models \brief Defines a set of items to be used as a model - A ObjectModel contains the visual items to be used in a view. - When a ObjectModel is used in a view, the view does not require + An ObjectModel contains the visual items to be used in a view. + When an ObjectModel is used in a view, the view does not require a delegate since the ObjectModel already contains the visual delegate (items). -- cgit v1.2.3 From 0f9b39909fb7023f7936b4311c13dbaa571ddbe6 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Tue, 28 Feb 2017 08:54:28 +0100 Subject: winrt: Fix application startup commit() was never implemented for the WinRT version of the OS Allocator. This commits fixes this under following setup - you have to use x86 or x64 - you have to use the experimental JIT For any of the other situations followup patches will follow. Task-number: QTBUG-59198 Change-Id: Ie87012ab2879139e27d63ac4bb96fe46905f7dfd Reviewed-by: Simon Hausmann --- src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp b/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp index 0a6eda8b98..15703017f6 100644 --- a/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp +++ b/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp @@ -98,16 +98,23 @@ void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bo return result; } -void OSAllocator::commit(void*, size_t, bool, bool) +void OSAllocator::commit(void *bytes, size_t size, bool writable, bool executable) { - CRASH(); // Unimplemented + if (qt_winrt_use_jit) { + void *result = VirtualAllocFromApp(bytes, size, MEM_COMMIT, + protection(writable, executable)); + if (!result) + CRASH(); + } } -void OSAllocator::decommit(void* address, size_t) +void OSAllocator::decommit(void* address, size_t bytes) { - if (qt_winrt_use_jit) - Q_UNREACHABLE(); - else + if (qt_winrt_use_jit) { + bool result = VirtualFree(address, bytes, MEM_DECOMMIT); + if (!result) + CRASH(); + } else _aligned_free(address); } -- cgit v1.2.3 From d1ae334077aeb948ca191e22231d20b54ea5f956 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Tue, 28 Feb 2017 10:04:11 +0100 Subject: winrt: Switch to always use VirtualAllocFromApp In latest versions of Windows, one can use VirtualAllocFromApp also without CodeGeneration flag being set. In conjunction with the new garbage collector that let to the situtation that the gc tried to reserve using VirtualAlloc, then the V4Engine constructor checked for JIT availability and disable JIT. This lead to VirtualAllocFromApp alloced memory could not be used anymore and caused to a crash latest when trying to commit or release. With WinRT 8.1 being removed, we do not need the mem_align version anymore and can stick with VirtualAllocFromApp/Free, with the JIT check only testing VirtualProtectFromApp. Task-number: QTBUG-59198 Change-Id: I57f2259c6a6298b8761d00d3abf2589c30de1f63 Reviewed-by: Simon Hausmann --- src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp | 74 +++++++++--------------------- 1 file changed, 22 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp b/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp index 15703017f6..4cebc35cce 100644 --- a/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp +++ b/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp @@ -55,78 +55,48 @@ static inline DWORD protection(bool writable, bool executable) void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool writable, bool executable) { - void *result; - if (qt_winrt_use_jit) { - result = VirtualAllocFromApp(0, bytes, MEM_RESERVE, protection(writable, executable)); - if (!result) { - qt_winrt_use_jit = false; - return reserveUncommitted(bytes, UnknownUsage, writable, executable); - } - } else { - static const size_t pageSize = getPageSize(); - result = _aligned_malloc(bytes, pageSize); - if (!result) - CRASH(); - memset(result, 0, bytes); - } + void *result = VirtualAllocFromApp(0, bytes, MEM_RESERVE, protection(writable, executable)); return result; } -void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages) +void* OSAllocator::reserveAndCommit(size_t bytes, Usage, bool writable, bool executable, bool includesGuardPages) { void *result; - if (qt_winrt_use_jit) { - result = VirtualAllocFromApp(0, bytes, MEM_RESERVE | MEM_COMMIT, - protection(writable, executable)); - if (!result) { - qt_winrt_use_jit = false; - return reserveAndCommit(bytes, usage, writable, executable, includesGuardPages); - } + result = VirtualAllocFromApp(0, bytes, MEM_RESERVE | MEM_COMMIT, + protection(writable, executable)); - if (includesGuardPages) { - size_t guardSize = pageSize(); - DWORD oldProtect; - if (!VirtualProtectFromApp(result, guardSize, protection(false, false), &oldProtect) || - !VirtualProtectFromApp(static_cast(result) + bytes - guardSize, guardSize, - protection(false, false), &oldProtect)) { - CRASH(); - } + if (includesGuardPages && qt_winrt_use_jit) { + size_t guardSize = pageSize(); + DWORD oldProtect; + if (!VirtualProtectFromApp(result, guardSize, protection(false, false), &oldProtect) || + !VirtualProtectFromApp(static_cast(result) + bytes - guardSize, guardSize, + protection(false, false), &oldProtect)) { + CRASH(); } - } else { - result = reserveUncommitted(bytes, usage, writable, executable); } return result; } void OSAllocator::commit(void *bytes, size_t size, bool writable, bool executable) { - if (qt_winrt_use_jit) { - void *result = VirtualAllocFromApp(bytes, size, MEM_COMMIT, - protection(writable, executable)); - if (!result) - CRASH(); - } + void *result = VirtualAllocFromApp(bytes, size, MEM_COMMIT, + protection(writable, executable)); + if (!result) + CRASH(); } void OSAllocator::decommit(void* address, size_t bytes) { - if (qt_winrt_use_jit) { - bool result = VirtualFree(address, bytes, MEM_DECOMMIT); - if (!result) - CRASH(); - } else - _aligned_free(address); + bool result = VirtualFree(address, bytes, MEM_DECOMMIT); + if (!result) + CRASH(); } -void OSAllocator::releaseDecommitted(void* address, size_t bytes) +void OSAllocator::releaseDecommitted(void* address, size_t) { - if (qt_winrt_use_jit) { - bool result = VirtualFree(address, 0, MEM_RELEASE); - if (!result) - CRASH(); - } else { - decommit(address, bytes); - } + bool result = VirtualFree(address, 0, MEM_RELEASE); + if (!result) + CRASH(); } bool OSAllocator::canAllocateExecutableMemory() -- cgit v1.2.3 From 16389a1f247f14965ed0286e4fdab6bc2b1621bc Mon Sep 17 00:00:00 2001 From: Michael Dippold Date: Wed, 22 Feb 2017 20:58:16 -0800 Subject: Ensure mouse ungrab is called when touch is also true Currently when removeGrabber is called with both mouse true and touch true, the touch logic blocks the ungrab mouse from being triggered as q->mouseGrabberItem() is then null. Task-number: QTBUG-57797 Task-number: QTBUG-59098 Change-Id: Icb4d00cf876c9fd0930b50f927f68dfba172dc29 Reviewed-by: Shawn Rutledge --- src/quick/items/qquickwindow.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index f90384b3b6..4dc8cd0a37 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -811,6 +811,10 @@ void QQuickWindowPrivate::grabTouchPoints(QQuickItem *grabber, const QVectormouseGrabberItem() == grabber) { + qCDebug(DBG_MOUSE_TARGET) << "removeGrabber" << q->mouseGrabberItem() << "-> null"; + setMouseGrabber(nullptr); + } if (Q_LIKELY(touch)) { const auto touchDevices = QQuickPointerDevice::touchDevices(); for (auto device : touchDevices) { @@ -824,10 +828,6 @@ void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool to } } } - if (Q_LIKELY(mouse) && q->mouseGrabberItem() == grabber) { - qCDebug(DBG_MOUSE_TARGET) << "removeGrabber" << q->mouseGrabberItem() << "-> null"; - setMouseGrabber(nullptr); - } } /*! -- cgit v1.2.3 From 5a9fd4f49ec48c91c70699fc40af8f843c51b4ab Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 28 Feb 2017 15:55:39 +0100 Subject: V4 Debugger: Don't crash when stepping to the end of a script The last instruction is a return, which leads to an invalid context. Don't try to save that context, but rather clear the current one. Change-Id: I468b7420c4ca0842209c9b00478f99cc4dc69726 Reviewed-by: Simon Hausmann --- src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp index 5cc2043cb1..75cbc9eba1 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp @@ -230,7 +230,12 @@ void QV4Debugger::leavingFunction(const QV4::ReturnedValue &retVal) QMutexLocker locker(&m_lock); if (m_stepping != NotStepping && m_currentContext.asManaged()->d() == m_engine->current) { - m_currentContext.set(m_engine, *m_engine->parentContext(m_engine->currentContext)); + if (QV4::ExecutionContext *parentContext + = m_engine->parentContext(m_engine->currentContext)) { + m_currentContext.set(m_engine, *parentContext); + } else { + m_currentContext.clear(); + } m_stepping = StepOver; m_returnedValue.set(m_engine, retVal); } -- cgit v1.2.3 From c67d33db5b4e78027181be492d4757ac786e5c1f Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 28 Feb 2017 15:07:42 +0100 Subject: Add a source location to the final Jump in a for loop Otherwise it will assume the last statement as the location of the jump, and that might be a statement that is never hit. Task-number: QTBUG-59204 Change-Id: I66019a284b061358939b23e649ca0832b5442388 Reviewed-by: hjk Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4codegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 8d0126ebb3..819f4615f2 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -2499,7 +2499,7 @@ bool Codegen::visit(LocalForStatement *ast) _block = forbody; statement(ast->statement); - _block->JUMP(forstep); + setLocation(_block->JUMP(forstep), ast->lastSourceLocation()); _block = forstep; statement(ast->expression); -- cgit v1.2.3 From 9bd2705a2f02d1c54f179aa096142c151046c642 Mon Sep 17 00:00:00 2001 From: Andy Nichols Date: Mon, 27 Feb 2017 13:50:32 +0100 Subject: OpenVG: Fix glyph cache to actually ref count In my haste to add the code to cleanup unused glyphs I neglected to add the coded needed to ref count the glyphs. So glyphs that were being used more than once were getting removed too early. Change-Id: If3fa083313c345beac6705956067bee0932f7f60 Reviewed-by: Laszlo Agocs --- .../scenegraph/openvg/qsgopenvgfontglyphcache.cpp | 25 ++++++++++++---------- .../scenegraph/openvg/qsgopenvgfontglyphcache.h | 3 +-- 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.cpp b/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.cpp index dd630c776f..df47e920af 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.cpp +++ b/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.cpp @@ -94,7 +94,7 @@ void QSGOpenVGFontGlyphCache::populate(const QVector &glyphs) referencedGlyphs.insert(glyphIndex); - if (!m_cachedGlyphs.contains(glyphIndex)) { + if (!m_glyphReferences.contains(glyphIndex)) { newGlyphs.insert(glyphIndex); } } @@ -119,17 +119,9 @@ void QSGOpenVGFontGlyphCache::requestGlyphs(const QSet &glyphs) { VGfloat origin[2]; VGfloat escapement[2]; - QRectF metrics; QRawFont rawFont = m_referenceFont; - // Before adding any new glyphs, remove any unused glyphs - for (auto glyph : qAsConst(m_unusedGlyphs)) { - vgClearGlyph(m_font, glyph); - } - for (auto glyph : glyphs) { - m_cachedGlyphs.insert(glyph); - // Calculate the path for the glyph and cache it. QPainterPath path = rawFont.pathForGlyph(glyph); VGPath vgPath; @@ -151,12 +143,23 @@ void QSGOpenVGFontGlyphCache::requestGlyphs(const QSet &glyphs) void QSGOpenVGFontGlyphCache::referenceGlyphs(const QSet &glyphs) { - m_unusedGlyphs -= glyphs; + for (auto glyph : glyphs) { + if (m_glyphReferences.contains(glyph)) + m_glyphReferences[glyph] += 1; + else + m_glyphReferences.insert(glyph, 1); + } } void QSGOpenVGFontGlyphCache::releaseGlyphs(const QSet &glyphs) { - m_unusedGlyphs += glyphs; + for (auto glyph : glyphs) { + int references = m_glyphReferences[glyph] -= 1; + if (references == 0) { + vgClearGlyph(m_font, glyph); + m_glyphReferences.remove(glyph); + } + } } QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h b/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h index a88d28b0fe..107ec0c892 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h +++ b/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h @@ -87,8 +87,7 @@ private: int m_glyphCount; VGFont m_font; - QSet m_cachedGlyphs; - QSet m_unusedGlyphs; + QHash m_glyphReferences; }; -- cgit v1.2.3 From 55fec6b2db17db43fc7d03ef5d482cc67b16543b Mon Sep 17 00:00:00 2001 From: Andy Nichols Date: Mon, 27 Feb 2017 16:45:44 +0100 Subject: Software: Flush whole window on Expose event The software render loop updates the window content via either an expose event or an update event. An expose event should always flush the entire backingstore, but previously only the newly updated region would be flushed. The first time a window is exposed this is fine because the whole scene would be rendered, but when hidden and shown again, the software renderer might show that nothing has changed, and nothing would be flushed. A new flag has been added that forces a full window flush for an expose event. Task-number: QTBUG-59177 Change-Id: I3700bbcc76bc97be4eb0c822e2945ebef339f11a Reviewed-by: Laszlo Agocs --- .../scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp | 9 ++++++--- .../scenegraph/adaptations/software/qsgsoftwarerenderloop_p.h | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp index 6856d34616..b3b8274a73 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp @@ -101,7 +101,7 @@ void QSGSoftwareRenderLoop::windowDestroyed(QQuickWindow *window) } } -void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window) +void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window, bool isNewExpose) { QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window); if (!m_windows.contains(window)) @@ -174,7 +174,10 @@ void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window) if (alsoSwap && window->isVisible()) { //Flush backingstore to window - m_backingStores[window]->flush(softwareRenderer->flushRegion()); + if (!isNewExpose) + m_backingStores[window]->flush(softwareRenderer->flushRegion()); + else + m_backingStores[window]->flush(QRegion(QRect(QPoint(0,0), window->size()))); cd->fireFrameSwapped(); } @@ -206,7 +209,7 @@ void QSGSoftwareRenderLoop::exposureChanged(QQuickWindow *window) { if (window->isExposed()) { m_windows[window].updatePending = true; - renderWindow(window); + renderWindow(window, true); } } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop_p.h index 02dcf4eefa..c724d18298 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop_p.h @@ -69,7 +69,7 @@ public: void windowDestroyed(QQuickWindow *window) override; - void renderWindow(QQuickWindow *window); + void renderWindow(QQuickWindow *window, bool isNewExpose = false); void exposureChanged(QQuickWindow *window) override; QImage grab(QQuickWindow *window) override; -- cgit v1.2.3 From 59c94123e3661274d14f69c3df71fae9325b7eea Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 28 Feb 2017 15:39:25 +0100 Subject: Fix memory leak in QQDMIncubationTask::statusChanged Mimic the same process we do in QQmlDelegateModelPrivate::incubatorStatusChanged i.e. there's no need to check for object before destroying contextData Change-Id: I8cb1cda6da43bada350183ae11ee9b85b7fffee5 Reviewed-by: Simon Hausmann --- src/qml/types/qqmldelegatemodel.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index a5878dcffd..34bc266cb5 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -837,10 +837,9 @@ void QQDMIncubationTask::statusChanged(Status status) } else if (isDoneIncubating(status)) { Q_ASSERT(incubating); // The model was deleted from under our feet, cleanup ourselves - if (incubating->object) { - delete incubating->object; - - incubating->object = 0; + delete incubating->object; + incubating->object = 0; + if (incubating->contextData) { incubating->contextData->destroy(); incubating->contextData = 0; } -- cgit v1.2.3 From 015dff255ff0f40c553b1dee43c6cff013df64eb Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 1 Mar 2017 14:12:57 +0100 Subject: Privately export QQuickPositionerAttached This was missed in 2556bfda. Change-Id: I088d3e36a64b4459d2376ae38796e743c783260d Reviewed-by: J-P Nurmi --- src/quick/items/qquickpositioners_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickpositioners_p.h b/src/quick/items/qquickpositioners_p.h index 8dc0d90a2f..cfe163b4c1 100644 --- a/src/quick/items/qquickpositioners_p.h +++ b/src/quick/items/qquickpositioners_p.h @@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE class QQuickBasePositionerPrivate; -class QQuickPositionerAttached : public QObject +class Q_QUICK_PRIVATE_EXPORT QQuickPositionerAttached : public QObject { Q_OBJECT -- cgit v1.2.3 From 71a2dbed467be0041b6793dda868655b2632e830 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Thu, 5 Jan 2017 16:16:43 +0100 Subject: When stealing a touchpoint as synth. mouse, ungrab touch If you use MultiPointTouchArea to make a button component, or if you do something similar by subclassing QQuickItem and handling touch events, and you place such a component inside a Flickable, when the user presses on the button and then drags far enough that the Flickable steals the grab, the MPTA or custom item did not receive the touchUngrabEvent() callback. Now it does, so now the button will go back to released state as a result of having the grab stolen. The situation here is special in that it's the only place where a touch event is transformed to be treated as mouse in the future, usually it's either treated as touch or mouse from the start. When this happens, it's not enough to call setMouseGrabber because that doesn't send touch cancel to the previous grabber. Instead we need to explicitly call touchUngrabEvent to notify the touch handling item. The explicit setting of the grabber which was there previously is not needed, since grabMouse will update the grab based on touchMouseId. tst_QQuickMultiPointTouchArea::inFlickable2 was already testing the pressed state of the touchpoint when the grab is stolen, but it was changed in 468626e99a90d6ac21cb311cde05c658ccb3b781; now that can be restored, and we can also un-blacklist inFlickable, which was deemed unstable in 6d163779711d4601931ae0f82910794fb2498136 [ChangeLog][QtQuick] MultiPointTouchArea, and any custom Item, will now properly receive touchUngrabEvent() when the touch grab is stolen by a filtering parent Item, such as a Flickable. Task-number: QTBUG-57910 Change-Id: I4e1b23ed099f01e7eca2e8a0e7ab4c652ef00cfa Reviewed-by: Frederik Gladhorn Reviewed-by: Shawn Rutledge --- src/quick/items/qquickwindow.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 4dc8cd0a37..340683f6c3 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -2593,9 +2593,14 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem qCDebug(DBG_TOUCH) << " - second chance intercepted on childMouseEventFilter by " << target; if (t != QEvent::MouseButtonRelease) { qCDebug(DBG_TOUCH_TARGET) << "TP" << tp.id() << "->" << target; - touchMouseId = tp.id(); touchMouseDevice = event->device(); - touchMouseDevice->pointerEvent()->pointById(tp.id())->setGrabber(target); + if (touchMouseId == -1) { + // the point was grabbed as a pure touch point before, now it will be treated as mouse + // but the old receiver still needs to be informed + if (auto oldGrabber = touchMouseDevice->pointerEvent()->pointById(tp.id())->grabber()) + oldGrabber->touchUngrabEvent(); + } + touchMouseId = tp.id(); target->grabMouse(); } filtered = true; -- cgit v1.2.3 From 60708ee6227df017269146d2c0cfd4238ec25b9f Mon Sep 17 00:00:00 2001 From: Jesus Fernandez Date: Thu, 2 Mar 2017 12:10:00 +0100 Subject: Fix build in clang5.0 Fixes: X86Assembler.h:281:19: error: 'm_assembler' is a protected member of 'JSC::AbstractMacroAssembler' masm->m_assembler.linkJump(m_label, masm->m_assembler.label()); AbstractMacroAssembler.h:819:19: note: declared protected here AssemblerType m_assembler; Change-Id: I04f6dc254e9826b9835a43b604a05ea4c57f661b Reviewed-by: Simon Hausmann --- src/3rdparty/masm/assembler/X86Assembler.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/3rdparty/masm/assembler/X86Assembler.h b/src/3rdparty/masm/assembler/X86Assembler.h index 24462ef38f..46f2cd714a 100644 --- a/src/3rdparty/masm/assembler/X86Assembler.h +++ b/src/3rdparty/masm/assembler/X86Assembler.h @@ -253,6 +253,7 @@ public: { } +#if defined(V4_BOOTSTRAP) template class Jump { template @@ -291,6 +292,7 @@ public: private: AssemblerLabel m_label; }; +#endif // Stack operations: -- cgit v1.2.3 From 201d9f1c62516542d4558f0d2b07542e1082b497 Mon Sep 17 00:00:00 2001 From: Kimmo Ollila Date: Fri, 3 Mar 2017 00:59:47 +0200 Subject: Allow import static plugins even when library feature is disabled Removing QT_CONFIG(library) checks around static plugin handling code Change-Id: I5408d0fee2f58b27372c59004351f37ee8f566b9 Reviewed-by: Ulf Hermann --- src/qml/qml/qqmlimport.cpp | 39 +++++---------------------------------- 1 file changed, 5 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index c07d5c740a..ee5b38717b 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -210,7 +210,6 @@ QQmlType *fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringR } // namespace -#if QT_CONFIG(library) struct RegisteredPlugin { QString uri; QPluginLoader* loader; @@ -221,21 +220,23 @@ struct StringRegisteredPluginMap : public QMap { }; Q_GLOBAL_STATIC(StringRegisteredPluginMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri and the PluginLoaders + void qmlClearEnginePlugins() { StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes(); QMutexLocker lock(&plugins->mutex); +#if QT_CONFIG(library) for (auto &plugin : qAsConst(*plugins)) { QPluginLoader* loader = plugin.loader; if (loader && !loader->unload()) qWarning("Unloading %s failed: %s", qPrintable(plugin.uri), qPrintable(loader->errorString())); delete loader; } +#endif plugins->clear(); } typedef QPair StaticPluginPair; -#endif /*! \internal @@ -332,10 +333,9 @@ public: const QString &uri, const QString &url, int vmaj, int vmin, QV4::CompiledData::Import::ImportType type, QList *errors, bool lowPrecedence = false); -#if QT_CONFIG(library) - bool populatePluginPairVector(QVector &result, const QString &uri, const QStringList &versionUris, + + bool populatePluginPairVector(QVector &result, const QString &uri, const QStringList &versionUris, const QString &qmldirPath, QList *errors); -#endif }; /*! @@ -959,7 +959,6 @@ static QStringList versionUriList(const QString &uri, int vmaj, int vmin) return result; } -#if QT_CONFIG(library) static QVector makePlugins() { QVector plugins; @@ -1009,7 +1008,6 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector &res } return true; } -#endif #if defined(QT_SHARED) || !QT_CONFIG(library) static inline QString msgCannotLoadPlugin(const QString &uri, const QString &why) @@ -1030,7 +1028,6 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, const QQmlTypeLoaderQmldirContent *qmldir, QList *errors) { -#if QT_CONFIG(library) Q_ASSERT(qmldir); if (qmlImportTrace()) @@ -1143,22 +1140,6 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, database->qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(qmldirFilePath); } - -#else - Q_UNUSED(vmaj); - Q_UNUSED(vmin); - Q_UNUSED(database); - Q_UNUSED(qmldir); - - if (errors) { - QQmlError error; - error.setDescription(msgCannotLoadPlugin(uri, QQmlImportDatabase::tr("library loading is disabled"))); - error.setUrl(QUrl::fromLocalFile(qmldirFilePath)); - errors->prepend(error); - } - - return false; -#endif // library return true; } @@ -2014,7 +1995,6 @@ bool QQmlImportDatabase::registerPluginTypes(QObject *instance, const QString &b bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &basePath, const QString &uri, const QString &typeNamespace, int vmaj, QList *errors) { -#if QT_CONFIG(library) // Dynamic plugins are differentiated by their filepath. For static plugins we // don't have that information so we use their address as key instead. const QString uniquePluginID = QString::asprintf("%p", instance); @@ -2050,15 +2030,6 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba } return true; -#else - Q_UNUSED(instance); - Q_UNUSED(basePath); - Q_UNUSED(uri); - Q_UNUSED(typeNamespace); - Q_UNUSED(vmaj); - Q_UNUSED(errors); - return false; -#endif } /*! -- cgit v1.2.3 From 05a88efb266ec3b7b16d6db0d971c21ae7f45c9d Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 27 Feb 2017 15:17:35 +0100 Subject: QQuickAnimatorProxyJob: make sure to stop when detached from a window Qt Quick Controls 2 StackView auto tests exposed an issue that animator proxy jobs keep ticking after being unassociated from a window. Change-Id: Ib9b3a0e02ac4cc3f3e98ddf05c8b01f0bbd614d3 Reviewed-by: Gunnar Sletta --- src/quick/util/qquickanimatorjob.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp index 4aacb09c97..dced8b49a9 100644 --- a/src/quick/util/qquickanimatorjob.cpp +++ b/src/quick/util/qquickanimatorjob.cpp @@ -140,6 +140,11 @@ QObject *QQuickAnimatorProxyJob::findAnimationContext(QQuickAbstractAnimation *a void QQuickAnimatorProxyJob::updateCurrentTime(int) { + // A proxy which is being ticked should be associated with a window, (see + // setWindow() below). If we get here when there is no more controller we + // have a problem. + Q_ASSERT(m_controller); + // We do a simple check here to see if the animator has run and stopped on // the render thread. isPendingStart() will perform a check against jobs // that have been scheduled for start, but that will not yet have entered @@ -167,9 +172,9 @@ void QQuickAnimatorProxyJob::updateState(QAbstractAnimationJob::State newState, } } else if (newState == Stopped) { - syncBackCurrentValues(); m_internalState = State_Stopped; if (m_controller) { + syncBackCurrentValues(); m_controller->cancel(m_job); } } @@ -193,6 +198,7 @@ void QQuickAnimatorProxyJob::setWindow(QQuickWindow *window) if (m_job && m_controller) m_controller->cancel(m_job); m_controller = nullptr; + stop(); } else if (!m_controller && m_job) { m_controller = QQuickWindowPrivate::get(window)->animationController; -- cgit v1.2.3 From 13335bdee5482ae04d5b0d4c933ca328a1100cb6 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 6 Mar 2017 13:49:42 +0100 Subject: Fix build with -no-feature-library The versionUriList() function is unused in this case, and we cannot build the extension plugins test. Change-Id: I6c2ea1c2d078e508b0752efb45f4ccdfdbcbf22e Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlimport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index f2cbf5a94f..85b7ea633d 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -876,6 +876,7 @@ QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStr return 0; } +#if QT_CONFIG(library) /*! Returns the list of possible versioned URI combinations. For example, if \a uri is QtQml.Models, \a vmaj is 2, and \a vmin is 0, this method returns the following: @@ -897,7 +898,6 @@ static QStringList versionUriList(const QString &uri, int vmaj, int vmin) return result; } -#if QT_CONFIG(library) /*! Get all static plugins that are QML plugins and has a meta data URI that matches with one of \a versionUris, which is a list of all possible versioned URI combinations - see versionUriList() -- cgit v1.2.3 From c6917f27cbb26c140d6e514ca8a268bbf41f49a2 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 6 Mar 2017 10:29:47 +0100 Subject: Fix restoring IR from cache files Commit eeb08d9537d0b4e77b91848169e0bb79ec3d912c was missing the code to restore the aliases, the AST function formals as well as the object flags/id. This also fixes crashes with the QML compiler. Change-Id: I1c50816dc77ae66edbc3ddc7146da4edfd4170f4 Reviewed-by: Lars Knoll --- src/qml/compiler/qqmlirbuilder.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 8a7507c92e..0a6efa7867 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -2116,7 +2116,8 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias; object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias; - + object->flags = serializedObject->flags; + object->id = serializedObject->id; object->location = serializedObject->location; object->locationOfIdProperty = serializedObject->locationOfIdProperty; @@ -2175,6 +2176,15 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO object->properties->append(p); } + { + const QV4::CompiledData::Alias *serializedAlias = serializedObject->aliasTable(); + for (uint i = 0; i < serializedObject->nAliases; ++i, ++serializedAlias) { + QmlIR::Alias *a = pool->New(); + *static_cast(a) = *serializedAlias; + object->aliases->append(a); + } + } + QQmlJS::Engine *jsParserEngine = &output->jsParserEngine; const QV4::CompiledData::LEUInt32 *functionIdx = serializedObject->functionOffsetTable(); @@ -2205,6 +2215,11 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO const QString name = unit->stringAt(compiledFunction->nameIndex); f->functionDeclaration = new(pool) QQmlJS::AST::FunctionDeclaration(jsParserEngine->newStringRef(name), paramList, /*body*/0); + f->formals.allocate(pool, int(compiledFunction->nFormals)); + formalNameIdx = compiledFunction->formalsTable(); + for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx) + f->formals[i] = *formalNameIdx; + object->functions->append(f); } -- cgit v1.2.3 From fb0490dd653e4856a3595bd7e49c3127215170d1 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 14 Feb 2017 15:17:16 -0800 Subject: QThreadData::threadId is now QAtomicPointer, so relax loads from Acquire operator T() does loadAcquire, to match std::atomic behavior. We don't need that, so let's use a relaxed load. Side note: why does QtQml need to access the thread ID this way? Couldn't it do object->thread()? This code comes from a pre-5.0 commit 5570040771ec610583473e2d9e8e069474364cf1 ("Permit signals to be emitted in a different thread"). Change-Id: I4139d5f93dcb4b429ae9fffd14a34a84d3255a6f Reviewed-by: Simon Hausmann Reviewed-by: Marc Mutz --- src/qml/qml/qqmlengine.cpp | 2 +- src/qml/qml/qqmlnotifier.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index c800641f1c..f1c592b632 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -774,7 +774,7 @@ 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) { + QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId.load()) { if (!QObjectPrivate::get(object)->threadData->thread) return; diff --git a/src/qml/qml/qqmlnotifier.cpp b/src/qml/qml/qqmlnotifier.cpp index 185f9687fb..538ca822ee 100644 --- a/src/qml/qml/qqmlnotifier.cpp +++ b/src/qml/qml/qqmlnotifier.cpp @@ -122,8 +122,8 @@ void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine disconnect(); Q_ASSERT(engine); - if (QObjectPrivate::get(source)->threadData->threadId != - QObjectPrivate::get(engine)->threadData->threadId) { + if (QObjectPrivate::get(source)->threadData->threadId.load() != + QObjectPrivate::get(engine)->threadData->threadId.load()) { QString sourceName; QDebug(&sourceName) << source; -- cgit v1.2.3 From 1102f6ca7f1bb09e77f100b7e2afcac9f13e322c Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 2 Mar 2017 15:52:38 +0100 Subject: Fix qmlcachegen command line parameters Add support for specifying the output file name Change-Id: I3ec3cecae2334a7640baa928c0739c5521496d2d Reviewed-by: Lars Knoll --- src/qml/compiler/qv4compileddata.cpp | 13 ++++--------- src/qml/compiler/qv4compileddata_p.h | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index a8f065210b..dba04a7187 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -77,13 +77,7 @@ namespace QV4 { namespace CompiledData { -#ifdef V4_BOOTSTRAP -static QString cacheFilePath(const QString &localSourcePath) -{ - const QString localCachePath = localSourcePath + QLatin1Char('c'); - return localCachePath; -} -#else +#if !defined(V4_BOOTSTRAP) static QString cacheFilePath(const QUrl &url) { const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url); @@ -408,7 +402,7 @@ bool CompilationUnit::memoryMapCode(QString *errorString) #endif // V4_BOOTSTRAP #if defined(V4_BOOTSTRAP) -bool CompilationUnit::saveToDisk(const QString &unitUrl, QString *errorString) +bool CompilationUnit::saveToDisk(const QString &outputFileName, QString *errorString) #else bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString) #endif @@ -425,11 +419,12 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString) *errorString = QStringLiteral("File has to be a local file."); return false; } + const QString outputFileName = cacheFilePath(unitUrl); #endif #if QT_CONFIG(temporaryfile) // Foo.qml -> Foo.qmlc - QSaveFile cacheFile(cacheFilePath(unitUrl)); + QSaveFile cacheFile(outputFileName); if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { *errorString = cacheFile.errorString(); return false; diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 13a0c4b075..8c7d0d7e19 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -908,7 +908,7 @@ protected: public: #if defined(V4_BOOTSTRAP) - bool saveToDisk(const QString &unitUrl, QString *errorString); + bool saveToDisk(const QString &outputFileName, QString *errorString); #else bool saveToDisk(const QUrl &unitUrl, QString *errorString); #endif -- cgit v1.2.3 From 7fe0d1a06830518e8ce6752e45a0a01b1b97fa73 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Tue, 7 Mar 2017 08:58:10 +0100 Subject: Revert "QQuickAnimatorProxyJob: make sure to stop when detached from a window" This reverts commit 05a88efb266ec3b7b16d6db0d971c21ae7f45c9d. It caused some test failures in qtquickcontrols and qtquickcontrols2. Task-number: QTBUG-59326 Task-number: QTBUG-59327 Change-Id: I9a26a4518bf7c106372916761aae69ba65f6df9e Reviewed-by: J-P Nurmi --- src/quick/util/qquickanimatorjob.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'src') diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp index dced8b49a9..4aacb09c97 100644 --- a/src/quick/util/qquickanimatorjob.cpp +++ b/src/quick/util/qquickanimatorjob.cpp @@ -140,11 +140,6 @@ QObject *QQuickAnimatorProxyJob::findAnimationContext(QQuickAbstractAnimation *a void QQuickAnimatorProxyJob::updateCurrentTime(int) { - // A proxy which is being ticked should be associated with a window, (see - // setWindow() below). If we get here when there is no more controller we - // have a problem. - Q_ASSERT(m_controller); - // We do a simple check here to see if the animator has run and stopped on // the render thread. isPendingStart() will perform a check against jobs // that have been scheduled for start, but that will not yet have entered @@ -172,9 +167,9 @@ void QQuickAnimatorProxyJob::updateState(QAbstractAnimationJob::State newState, } } else if (newState == Stopped) { + syncBackCurrentValues(); m_internalState = State_Stopped; if (m_controller) { - syncBackCurrentValues(); m_controller->cancel(m_job); } } @@ -198,7 +193,6 @@ void QQuickAnimatorProxyJob::setWindow(QQuickWindow *window) if (m_job && m_controller) m_controller->cancel(m_job); m_controller = nullptr; - stop(); } else if (!m_controller && m_job) { m_controller = QQuickWindowPrivate::get(window)->animationController; -- cgit v1.2.3 From d5d12e1d6fb9aaa5a8cee7924555f0d4d19ffabc Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 1 Mar 2017 10:42:47 +0100 Subject: Set source location for all loop body-to-front jumps Task-number: QTBUG-59204 Change-Id: Id1a73b228cd3386c7fcc7712c2485f387238b65e Reviewed-by: hjk Reviewed-by: Erik Verbruggen --- src/qml/compiler/qv4codegen.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 819f4615f2..2c1b5c57cc 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -2256,7 +2256,7 @@ bool Codegen::visit(DoWhileStatement *ast) _block = loopbody; statement(ast->statement); - _block->JUMP(loopcond); + setLocation(_block->JUMP(loopcond), ast->statement->lastSourceLocation()); _block = loopcond; condition(ast->expression, loopbody, loopend); @@ -2321,7 +2321,7 @@ bool Codegen::visit(ForEachStatement *ast) return false; move(*init, _block->TEMP(temp)); statement(ast->statement); - _block->JUMP(foreachin); + setLocation(_block->JUMP(foreachin), ast->lastSourceLocation()); _block = foreachin; @@ -2360,7 +2360,7 @@ bool Codegen::visit(ForStatement *ast) _block = forbody; statement(ast->statement); - _block->JUMP(forstep); + setLocation(_block->JUMP(forstep), ast->lastSourceLocation()); _block = forstep; statement(ast->expression); @@ -2460,7 +2460,7 @@ bool Codegen::visit(LocalForEachStatement *ast) int temp = _block->newTemp(); move(identifier(ast->declaration->name.toString()), _block->TEMP(temp)); statement(ast->statement); - _block->JUMP(foreachin); + setLocation(_block->JUMP(foreachin), ast->lastSourceLocation()); _block = foreachin; @@ -2800,7 +2800,7 @@ bool Codegen::visit(WhileStatement *ast) _block = whilebody; statement(ast->statement); - _block->JUMP(whilecond); + setLocation(_block->JUMP(whilecond), ast->lastSourceLocation()); _block = whileend; leaveLoop(); -- cgit v1.2.3 From 84a07bebc94e9f92d4d596550317a89403ed291f Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 6 Mar 2017 15:06:59 +0100 Subject: Fix crash when loading cache files generated ahead of time The offset of the runtimeStrings array differed between a V4_BOOTSTRAP build and the regular library build. This is an intermediate fix until QTBUG-58666 is fixed properly. Change-Id: Id1310ffa82f1079c1acef7730db41186fa62610f Reviewed-by: hjk Reviewed-by: Lars Knoll --- src/qml/compiler/qv4compileddata.cpp | 2 +- src/qml/compiler/qv4compileddata_p.h | 6 ++---- src/qml/debugger/qqmldebug.cpp | 10 +++++++--- 3 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index dba04a7187..70a03c2c1f 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -95,8 +95,8 @@ static QString cacheFilePath(const QUrl &url) #ifndef V4_BOOTSTRAP CompilationUnit::CompilationUnit() : data(0) - , engine(0) , runtimeStrings(0) + , engine(0) , runtimeLookups(0) , runtimeRegularExpressions(0) , runtimeClasses(0) diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 8c7d0d7e19..23139d6c8e 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -816,13 +816,11 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount // Called only when building QML, when we build the header for JS first and append QML data virtual QV4::CompiledData::Unit *createUnitData(QmlIR::Document *irDocument); -#ifndef V4_BOOTSTRAP - ExecutionEngine *engine; -#endif - QV4::Heap::String **runtimeStrings; // Array #ifndef V4_BOOTSTRAP + ExecutionEngine *engine; + QString fileName() const { return data->stringAt(data->sourceFileIndex); } QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; } diff --git a/src/qml/debugger/qqmldebug.cpp b/src/qml/debugger/qqmldebug.cpp index 15230d75a5..681dc06215 100644 --- a/src/qml/debugger/qqmldebug.cpp +++ b/src/qml/debugger/qqmldebug.cpp @@ -42,6 +42,7 @@ #include "qqmldebugserviceinterfaces_p.h" #include +#include QT_BEGIN_NAMESPACE @@ -181,12 +182,12 @@ bool QQmlDebuggingEnabler::startDebugConnector(const QString &pluginName, return connector ? connector->open(configuration) : false; } -enum { HookCount = 3 }; +enum { HookCount = 4 }; // Only add to the end, and bump version if you do. quintptr Q_QML_EXPORT qtDeclarativeHookData[] = { // Version of this Array. Bump if you add to end. - 1, + 2, // Number of entries in this array. HookCount, @@ -194,7 +195,10 @@ quintptr Q_QML_EXPORT qtDeclarativeHookData[] = { // TypeInformationVersion, an integral value, bumped whenever private // object sizes or member offsets that are used in Qt Creator's // data structure "pretty printing" change. - 2 + 3, + + // Version of the cache data. + QV4_DATA_STRUCTURE_VERSION }; Q_STATIC_ASSERT(HookCount == sizeof(qtDeclarativeHookData) / sizeof(qtDeclarativeHookData[0])); -- cgit v1.2.3 From 1ecefb43f250374a598bc64e8ff3d3af2aac006c Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 1 Mar 2017 10:10:05 +0100 Subject: Doc: Remove mentioning of non-existing setContents method Change-Id: I6c8c27390b6309e0d2bd0c758d04f864fce51069 Reviewed-by: Leena Miettinen --- src/quickwidgets/qquickwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index 4ed41a0c6c..ea02723db8 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -1140,7 +1140,7 @@ QSize QQuickWidget::initialSize() const /*! Returns the view's root \l {QQuickItem} {item}. Can be null - when setContents/setSource has not been called, if they were called with + when setSource() has not been called, if it was called with broken QtQuick code or while the QtQuick contents are being created. */ QQuickItem *QQuickWidget::rootObject() const -- cgit v1.2.3 From 25555238cde42daf5a73669234e737c90ef9ea5f Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Thu, 21 Jan 2016 11:40:18 +0100 Subject: Fix copied QDragMoveEvent drop action to propagate to original event Trying to set the drop action and the accepted state in a overridden dragMoveEvent handler, does not get propagated to the original QDragMoveEvent, because the event passed to the handler is a copy. This does not allow canceling the drop action in the move handler, or change the proposed action to a different one. Changing these values in the move handler is important to allow modifying the cursor when moving / hovering above a possible drop item, depending on user conditions. Fix consists in copying the drop action and accepted values to the original event, as well as removing the hard-coded setAccepted (true) call. Task-number: QTBUG-58260 Change-Id: I7a4bd4e68ee1023a36a63d3e835c282077e4187c Reviewed-by: Shawn Rutledge --- src/quick/items/qquickwindow.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 340683f6c3..e6245f90f3 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -2397,7 +2397,6 @@ void QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *e } else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) { QDragMoveEvent *moveEvent = static_cast(event); if (deliverDragEvent(grabber, **grabItem, moveEvent)) { - moveEvent->setAccepted(true); for (++grabItem; grabItem != grabber->end();) { QPointF p = (**grabItem)->mapFromScene(moveEvent->pos()); if ((**grabItem)->contains(p)) { @@ -2472,7 +2471,10 @@ bool QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickIte event->keyboardModifiers(), event->type()); QQuickDropEventEx::copyActions(&translatedEvent, *event); + translatedEvent.setAccepted(event->isAccepted()); QCoreApplication::sendEvent(item, &translatedEvent); + event->setAccepted(translatedEvent.isAccepted()); + event->setDropAction(translatedEvent.dropAction()); if (event->type() == QEvent::DragEnter) { if (translatedEvent.isAccepted()) { grabber->grab(item); -- cgit v1.2.3 From 4aabede9348d195cec2ca6c4718576aa35464e3e Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 8 Mar 2017 11:20:33 +0100 Subject: JS: Fix 0 == -0 The double representation of 0 and -0 are different in the sign bit, so the raw values are not the same. However, neither is managed, so non-strict equality comparison erroneously returned false. Task-number: QTBUG-56808 Change-Id: If966ddbc9f1a1c006dc5901aecafca063f71e404 Reviewed-by: Simon Hausmann Reviewed-by: Allan Sandfeld Jensen --- src/qml/jsruntime/qv4runtime.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 57ad181030..b31e07b979 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1758,6 +1758,8 @@ Bool Runtime::method_compareEqual(const Value &left, const Value &right) return !left.isNaN(); if (left.type() == right.type()) { + if (left.isDouble() && left.doubleValue() == 0 && right.doubleValue() == 0) + return true; // this takes care of -0 == +0 (which obviously have different raw values) if (!left.isManaged()) return false; if (left.isString() == right.isString()) -- cgit v1.2.3 From 55e558144d6d78062dd5d04f786e7fccf4eeebb7 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 8 Mar 2017 16:08:03 +0100 Subject: Fix time stamp related errors when loading AOT caches Cache files created ahead of time do not require a timestamp match towards the source file. This is because we cannot guarantee that all transport mechanism from source to deployment preserve the timestamp at the required resolution (if at all) and the source may also not be present at all (obfuscated deployment chosen). For cache files created at run-time however we'll continue to require time stamp verification. Change-Id: Ia7cdf3d063edd5bb1e6985089f1a666c970a0bd0 Reviewed-by: Lars Knoll --- src/qml/compiler/qv4compilationunitmapper.cpp | 2 +- src/qml/compiler/qv4compileddata.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compilationunitmapper.cpp b/src/qml/compiler/qv4compilationunitmapper.cpp index 2e1213464c..1ae0fb190c 100644 --- a/src/qml/compiler/qv4compilationunitmapper.cpp +++ b/src/qml/compiler/qv4compilationunitmapper.cpp @@ -76,7 +76,7 @@ bool CompilationUnitMapper::verifyHeader(const CompiledData::Unit *header, const return false; } - { + if (header->sourceTimeStamp) { QFileInfo sourceCode(sourcePath); QDateTime sourceTimeStamp; if (sourceCode.exists()) diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 70a03c2c1f..7854a49af9 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -361,7 +361,7 @@ bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr; QScopedValueRollback dataPtrChange(data, mappedUnit); - if (sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) { + if (data->sourceFileIndex != 0 && sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) { *errorString = QStringLiteral("QML source file has moved to a different location."); return false; } @@ -409,12 +409,12 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString) { errorString->clear(); +#if !defined(V4_BOOTSTRAP) if (data->sourceTimeStamp == 0) { *errorString = QStringLiteral("Missing time stamp for source file"); return false; } -#if !defined(V4_BOOTSTRAP) if (!QQmlFile::isLocalFile(unitUrl)) { *errorString = QStringLiteral("File has to be a local file."); return false; -- cgit v1.2.3 From e0add0b655941dcec483674594b63ce9775598be Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 8 Mar 2017 17:09:55 +0100 Subject: Fix relocation related errors when loading AOT caches The original directory of the source file the cache was created from - when generating ahead of time - is unlikely going to be identical to the final location for example on a deployed device. Therefore when generating caches ahead of time, don't store the source path, don't attempt to verify it when loading and don't try to save the cache file at run-time again. We still need set the sourceFileIndex at load-time though, in order to make relative path url resolution work (for example source: "my.png" in an Image element). Change-Id: I3d6952f5d0a165cfa2cb400191a9f6ffe6be69f4 Reviewed-by: Lars Knoll --- src/qml/compiler/qv4compileddata.cpp | 15 ++++++++++++++- src/qml/compiler/qv4jsir.cpp | 6 +----- src/qml/qml/qqmltypeloader.cpp | 5 ++++- 3 files changed, 19 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 7854a49af9..668f20e4f2 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -480,10 +480,22 @@ Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument) return irDocument->jsGenerator.generateUnit(QV4::Compiler::JSUnitGenerator::GenerateWithoutStringTable); QQmlRefPointer compilationUnit = irDocument->javaScriptCompilationUnit; - QV4::CompiledData::Unit *jsUnit = const_cast(irDocument->javaScriptCompilationUnit->data); + QV4::CompiledData::Unit *jsUnit = const_cast(compilationUnit->data); + auto ensureWritableUnit = [&jsUnit, &compilationUnit]() { + if (jsUnit == compilationUnit->data) { + char *unitCopy = (char*)malloc(jsUnit->unitSize); + memcpy(unitCopy, jsUnit, jsUnit->unitSize); + jsUnit = reinterpret_cast(unitCopy); + } + }; QV4::Compiler::StringTableGenerator &stringTable = irDocument->jsGenerator.stringTable; + if (jsUnit->sourceFileIndex == quint32(0) || jsUnit->stringAt(jsUnit->sourceFileIndex) != irDocument->jsModule.fileName) { + ensureWritableUnit(); + jsUnit->sourceFileIndex = stringTable.registerString(irDocument->jsModule.fileName); + } + // Collect signals that have had a change in signature (from onClicked to onClicked(mouse) for example) // and now need fixing in the QV4::CompiledData. Also register strings at the same time, to finalize // the string table. @@ -546,6 +558,7 @@ Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument) } if (!signalParameterNameTable.isEmpty()) { + ensureWritableUnit(); Q_ASSERT(jsUnit != compilationUnit->data); const uint signalParameterTableSize = signalParameterNameTable.count() * sizeof(quint32); uint newSize = jsUnit->unitSize + signalParameterTableSize; diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index 5687834b00..cc2f9b7cf2 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -348,11 +348,7 @@ Module::~Module() void Module::setFileName(const QString &name) { - if (fileName.isEmpty()) - fileName = name; - else { - Q_ASSERT(fileName == name); - } + fileName = name; } Function::Function(Module *module, Function *outer, const QString &name) diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index f4f04e12c0..68eb989c70 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2407,6 +2407,7 @@ void QQmlTypeData::restoreIR(QQmlRefPointer m_document.reset(new QmlIR::Document(isDebugging())); QmlIR::IRLoader loader(unit->data, m_document.data()); loader.load(); + m_document->jsModule.setFileName(finalUrlString()); m_document->javaScriptCompilationUnit = unit; continueLoadFromIR(); } @@ -2507,6 +2508,8 @@ void QQmlTypeData::compile(const QQmlRefPointer &typeNameCach { Q_ASSERT(m_compiledData.isNull()); + const bool typeRecompilation = m_document && m_document->javaScriptCompilationUnit && m_document->javaScriptCompilationUnit->data->flags & QV4::CompiledData::Unit::PendingTypeCompilation; + QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine()); QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache); m_compiledData = compiler.compile(); @@ -2515,7 +2518,7 @@ void QQmlTypeData::compile(const QQmlRefPointer &typeNameCach return; } - const bool trySaveToDisk = (!disableDiskCache() || forceDiskCache()) && !m_document->jsModule.debugMode; + const bool trySaveToDisk = (!disableDiskCache() || forceDiskCache()) && !m_document->jsModule.debugMode && !typeRecompilation; if (trySaveToDisk) { QString errorString; if (m_compiledData->saveToDisk(url(), &errorString)) { -- cgit v1.2.3 From 42e098fa0ad318a6b6fafadbadce21b974c29c4d Mon Sep 17 00:00:00 2001 From: Oleg Yadrov Date: Mon, 27 Feb 2017 13:15:52 -0800 Subject: QtQuick scene graph: fix text native rendering Only 65536 vertices (65536 / 4 = 16384 characters) can be drawn in one draw call. This is why QSGDistanceFieldGlyphNode (renderType: Text.QtRendering) creates subnodes if number of characters exceeds that limit. QSGDefaultGlyphNode (renderType: Text.NativeRendering) missed that logic for some reason. Task-number: QTBUG-58852 Change-Id: I88b3fcdb8e56bc92622d3347cd638634d43df138 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/quick/scenegraph/qsgdefaultglyphnode.cpp | 128 +++++++++++++++++++++++++++ src/quick/scenegraph/qsgdefaultglyphnode_p.h | 23 +++++ 2 files changed, 151 insertions(+) (limited to 'src') diff --git a/src/quick/scenegraph/qsgdefaultglyphnode.cpp b/src/quick/scenegraph/qsgdefaultglyphnode.cpp index b856d99bc1..0d42102f36 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode.cpp @@ -42,11 +42,33 @@ QT_BEGIN_NAMESPACE +QSGDefaultGlyphNode::QSGDefaultGlyphNode() + : m_glyphNodeType(RootGlyphNode) + , m_dirtyGeometry(false) +{ + setFlag(UsePreprocess); +} + +QSGDefaultGlyphNode::~QSGDefaultGlyphNode() +{ + if (m_glyphNodeType == SubGlyphNode) + return; + + qDeleteAll(m_nodesToDelete); + m_nodesToDelete.clear(); +} + void QSGDefaultGlyphNode::setMaterialColor(const QColor &color) { static_cast(m_material)->setColor(color); } +void QSGDefaultGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs) +{ + QSGBasicGlyphNode::setGlyphs(position, glyphs); + m_dirtyGeometry = true; +} + void QSGDefaultGlyphNode::update() { QRawFont font = m_glyphs.rawFont(); @@ -84,4 +106,110 @@ void QSGDefaultGlyphNode::update() markDirty(DirtyGeometry); } +void QSGDefaultGlyphNode::preprocess() +{ + qDeleteAll(m_nodesToDelete); + m_nodesToDelete.clear(); + + if (m_dirtyGeometry) + updateGeometry(); +} + +void QSGDefaultGlyphNode::updateGeometry() +{ + // Remove previously created sub glyph nodes + // We assume all the children are sub glyph nodes + QSGNode *subnode = firstChild(); + while (subnode) { + // We can't delete the node now as it might be in the preprocess list + // It will be deleted in the next preprocess + m_nodesToDelete.append(subnode); + subnode = subnode->nextSibling(); + } + removeAllChildNodes(); + + GlyphInfo glyphInfo; + + const QVector indexes = m_glyphs.glyphIndexes(); + const QVector positions = m_glyphs.positions(); + + const int maxGlyphs = (USHRT_MAX + 1) / 4; // 16384 + const int maxVertices = maxGlyphs * 4; // 65536 + const int maxIndexes = maxGlyphs * 6; // 98304 + + for (int i = 0; i < indexes.size(); ++i) { + const int glyphIndex = indexes.at(i); + const QPointF position = positions.at(i); + + // As we use UNSIGNED_SHORT indexing in the geometry, we overload the + // "glyphsInOtherNodes" concept as overflow for if there are more than + // 65536 (16384 * 4) vertices to render which would otherwise exceed + // the maximum index size. This will cause sub-nodes to be recursively + // created to handle any number of glyphs. + if (i >= maxGlyphs) { + glyphInfo.indexes.append(glyphIndex); + glyphInfo.positions.append(position); + continue; + } + } + + if (!glyphInfo.indexes.isEmpty()) { + QGlyphRun subNodeGlyphRun(m_glyphs); + subNodeGlyphRun.setGlyphIndexes(glyphInfo.indexes); + subNodeGlyphRun.setPositions(glyphInfo.positions); + + QSGDefaultGlyphNode *subNode = new QSGDefaultGlyphNode(); + subNode->setGlyphNodeType(SubGlyphNode); + subNode->setColor(m_color); + subNode->setStyle(m_style); + subNode->setStyleColor(m_styleColor); + subNode->setGlyphs(m_position, subNodeGlyphRun); + subNode->update(); + subNode->updateGeometry(); // we have to explicitly call this now as preprocess won't be called before it's rendered + appendChildNode(subNode); + + QSGGeometry *g = geometry(); + + QSGGeometry::TexturedPoint2D *vertexData = g->vertexDataAsTexturedPoint2D(); + quint16 *indexData = g->indexDataAsUShort(); + + QVector tempVertexData(maxVertices); + QVector tempIndexData(maxIndexes); + + for (int i = 0; i < maxGlyphs; i++) { + tempVertexData[i * 4 + 0] = vertexData[i * 4 + 0]; + tempVertexData[i * 4 + 1] = vertexData[i * 4 + 1]; + tempVertexData[i * 4 + 2] = vertexData[i * 4 + 2]; + tempVertexData[i * 4 + 3] = vertexData[i * 4 + 3]; + + tempIndexData[i * 6 + 0] = indexData[i * 6 + 0]; + tempIndexData[i * 6 + 1] = indexData[i * 6 + 1]; + tempIndexData[i * 6 + 2] = indexData[i * 6 + 2]; + tempIndexData[i * 6 + 3] = indexData[i * 6 + 3]; + tempIndexData[i * 6 + 4] = indexData[i * 6 + 4]; + tempIndexData[i * 6 + 5] = indexData[i * 6 + 5]; + } + + g->allocate(maxVertices, maxIndexes); + vertexData = g->vertexDataAsTexturedPoint2D(); + indexData = g->indexDataAsUShort(); + + for (int i = 0; i < maxGlyphs; i++) { + vertexData[i * 4 + 0] = tempVertexData[i * 4 + 0]; + vertexData[i * 4 + 1] = tempVertexData[i * 4 + 1]; + vertexData[i * 4 + 2] = tempVertexData[i * 4 + 2]; + vertexData[i * 4 + 3] = tempVertexData[i * 4 + 3]; + + indexData[i * 6 + 0] = tempIndexData[i * 6 + 0]; + indexData[i * 6 + 1] = tempIndexData[i * 6 + 1]; + indexData[i * 6 + 2] = tempIndexData[i * 6 + 2]; + indexData[i * 6 + 3] = tempIndexData[i * 6 + 3]; + indexData[i * 6 + 4] = tempIndexData[i * 6 + 4]; + indexData[i * 6 + 5] = tempIndexData[i * 6 + 5]; + } + } + + m_dirtyGeometry = false; +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.h b/src/quick/scenegraph/qsgdefaultglyphnode_p.h index 0eb7a4e4bd..37a89c70b9 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.h +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.h @@ -59,8 +59,31 @@ QT_BEGIN_NAMESPACE class QSGDefaultGlyphNode : public QSGBasicGlyphNode { public: + QSGDefaultGlyphNode(); + ~QSGDefaultGlyphNode(); void setMaterialColor(const QColor &color) override; + void setGlyphs(const QPointF &position, const QGlyphRun &glyphs) override; void update() override; + void preprocess() override; + void updateGeometry(); + +private: + enum DefaultGlyphNodeType { + RootGlyphNode, + SubGlyphNode + }; + + void setGlyphNodeType(DefaultGlyphNodeType type) { m_glyphNodeType = type; } + + DefaultGlyphNodeType m_glyphNodeType; + QLinkedList m_nodesToDelete; + + struct GlyphInfo { + QVector indexes; + QVector positions; + }; + + uint m_dirtyGeometry: 1; }; QT_END_NAMESPACE -- cgit v1.2.3 From 6b4b2f5f1bbd706742cbab8764a1d07cbd912600 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 24 Jan 2017 12:07:33 +0100 Subject: New mark table implementation Automatically generate a table containing the data where JS Values and pointers are in objects in the JS heap. This will allow making the GC mark phase a lot more efficient. A bit of a special hack is currently required for MemberData and ArrayData, as they have a variable length, and we need to read the size from the object. We keep backwards compatibility with the old markObjects() functions for now (calling them if they are defined). Some further work on QV4::String and in a few other places is required before we can get remove the compatibility. Change-Id: I78528ace67e886bdbe4a4330c9677c7fc9f08a33 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4argumentsobject.cpp | 11 ------- src/qml/jsruntime/qv4argumentsobject_p.h | 26 +++++++++------ src/qml/jsruntime/qv4arraydata.cpp | 24 +------------- src/qml/jsruntime/qv4arraydata_p.h | 16 +++++++--- src/qml/jsruntime/qv4dataview.cpp | 7 ---- src/qml/jsruntime/qv4dataview_p.h | 13 ++++---- src/qml/jsruntime/qv4errorobject.cpp | 8 ----- src/qml/jsruntime/qv4errorobject_p.h | 14 ++++---- src/qml/jsruntime/qv4functionobject.cpp | 22 ++----------- src/qml/jsruntime/qv4functionobject_p.h | 26 ++++++++------- src/qml/jsruntime/qv4global_p.h | 1 + src/qml/jsruntime/qv4managed.cpp | 1 + src/qml/jsruntime/qv4managed_p.h | 5 ++- src/qml/jsruntime/qv4memberdata.cpp | 7 ---- src/qml/jsruntime/qv4memberdata_p.h | 14 ++++---- src/qml/jsruntime/qv4object.cpp | 12 ------- src/qml/jsruntime/qv4object_p.h | 18 ++++++----- src/qml/jsruntime/qv4persistent.cpp | 11 +------ src/qml/jsruntime/qv4qobjectwrapper.cpp | 9 ------ src/qml/jsruntime/qv4qobjectwrapper_p.h | 20 ++++++------ src/qml/jsruntime/qv4regexp.cpp | 6 ---- src/qml/jsruntime/qv4regexp_p.h | 2 -- src/qml/jsruntime/qv4regexpobject.cpp | 18 ----------- src/qml/jsruntime/qv4regexpobject_p.h | 29 +++++++++-------- src/qml/jsruntime/qv4stringobject.cpp | 7 ---- src/qml/jsruntime/qv4stringobject_p.h | 9 ++++-- src/qml/jsruntime/qv4typedarray.cpp | 6 ---- src/qml/jsruntime/qv4typedarray_p.h | 19 +++++------ src/qml/memory/qv4heap_p.h | 3 ++ src/qml/memory/qv4mm.cpp | 55 +++++++++++++++++++++++++++++--- src/qml/memory/qv4mm_p.h | 1 + src/qml/memory/qv4mmdefs_p.h | 48 ++++++++++++++++++++++++++++ src/qml/qml/qqmlcomponent.cpp | 28 ++++++---------- src/qml/qml/qqmlxmlhttprequest.cpp | 15 ++++----- 34 files changed, 242 insertions(+), 269 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 7c1cc92a13..39b99e9876 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -235,17 +235,6 @@ void ArgumentsSetterFunction::call(const Managed *setter, Scope &scope, CallData scope.result = Encode::undefined(); } -void ArgumentsObject::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - ArgumentsObject::Data *o = static_cast(that); - if (o->context) - o->context->mark(e); - if (o->mappedArguments) - o->mappedArguments->mark(e); - - Object::markObjects(that, e); -} - uint ArgumentsObject::getLength(const Managed *m) { const ArgumentsObject *a = static_cast(m); diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index f80ade9611..f579afff14 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -59,26 +59,35 @@ namespace QV4 { namespace Heap { -struct ArgumentsGetterFunction : FunctionObject { +#define ArgumentsGetterFunctionMembers(class, Member) \ + Member(class, uint, index) + +DECLARE_HEAP_OBJECT(ArgumentsGetterFunction, FunctionObject) { + DECLARE_MARK_TABLE(ArgumentsGetterFunction); inline void init(QV4::ExecutionContext *scope, uint index); - uint index; }; -struct ArgumentsSetterFunction : FunctionObject { +#define ArgumentsSetterFunctionMembers(class, Member) \ + Member(class, uint, index) + +DECLARE_HEAP_OBJECT(ArgumentsSetterFunction, FunctionObject) { + DECLARE_MARK_TABLE(ArgumentsSetterFunction); inline void init(QV4::ExecutionContext *scope, uint index); - uint index; }; -struct ArgumentsObject : Object { +#define ArgumentsObjectMembers(class, Member) \ + Member(class, Pointer, context) \ + Member(class, Pointer, mappedArguments) \ + Member(class, bool, fullyCreated) + +DECLARE_HEAP_OBJECT(ArgumentsObject, Object) { + DECLARE_MARK_TABLE(ArgumentsObject); enum { LengthPropertyIndex = 0, CalleePropertyIndex = 1, CallerPropertyIndex = 3 }; void init(QV4::CallContext *context); - Pointer context; - bool fullyCreated; - Pointer mappedArguments; }; } @@ -131,7 +140,6 @@ struct ArgumentsObject: Object { static bool putIndexed(Managed *m, uint index, const Value &value); static bool deleteIndexedProperty(Managed *m, uint index); static PropertyAttributes queryIndexed(const Managed *m, uint index); - static void markObjects(Heap::Base *that, ExecutionEngine *e); static uint getLength(const Managed *m); void fullyCreate(); diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index d8a7de5466..47d353ffd0 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -49,6 +49,7 @@ using namespace QV4; QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON const QV4::VTable QV4::ArrayData::static_vtbl = { + 0, 0, QV4::ArrayData::IsExecutionContext, QV4::ArrayData::IsString, @@ -233,20 +234,6 @@ void ArrayData::ensureAttributes(Object *o) ArrayData::realloc(o, Heap::ArrayData::Simple, 0, true); } - -void SimpleArrayData::markObjects(Heap::Base *d, ExecutionEngine *e) -{ - Heap::SimpleArrayData *dd = static_cast(d); - uint end = dd->offset + dd->len; - if (end > dd->alloc) { - for (uint i = 0; i < end - dd->alloc; ++i) - dd->arrayData[i].mark(e); - end = dd->alloc; - } - for (uint i = dd->offset; i < end; ++i) - dd->arrayData[i].mark(e); -} - ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index) { const Heap::SimpleArrayData *dd = static_cast(d); @@ -380,15 +367,6 @@ void SparseArrayData::free(Heap::ArrayData *d, uint idx) d->attrs[idx].clear(); } - -void SparseArrayData::markObjects(Heap::Base *d, ExecutionEngine *e) -{ - Heap::SparseArrayData *dd = static_cast(d); - uint l = dd->alloc; - for (uint i = 0; i < l; ++i) - dd->arrayData[i].mark(e); -} - Heap::ArrayData *SparseArrayData::reallocate(Object *o, uint n, bool enforceAttributes) { realloc(o, Heap::ArrayData::Sparse, n, enforceAttributes); diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index 24b948f01e..919bd84762 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -90,7 +90,7 @@ struct ArrayVTable namespace Heap { -struct ArrayData : public Base { +struct ArrayDataData { enum Type { Simple = 0, Complex = 1, @@ -110,6 +110,13 @@ struct ArrayData : public Base { SparseArray *sparse; }; Value arrayData[1]; +}; +static Q_CONSTEXPR quint64 ArrayData_markTable = \ + (MarkFlagsForType::markFlags << (offsetof(ArrayDataData, arrayData) >> 2)) \ + << (sizeof(Base) >> 2) | QV4::Heap::Base::markTable; + +struct ArrayData : public Base, ArrayDataData { + DECLARE_MARK_TABLE(ArrayData); bool isSparse() const { return type == Sparse; } @@ -189,6 +196,9 @@ struct Q_QML_EXPORT ArrayData : public Managed { typedef Heap::ArrayData::Type Type; V4_MANAGED(ArrayData, Managed) + enum { + IsArrayData = true + }; uint alloc() const { return d()->alloc; } uint &alloc() { return d()->alloc; } @@ -246,8 +256,6 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes); - static void markObjects(Heap::Base *d, ExecutionEngine *e); - static ReturnedValue get(const Heap::ArrayData *d, uint index); static bool put(Object *o, uint index, const Value &value); static bool putArray(Object *o, uint index, const Value *values, uint n); @@ -274,8 +282,6 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData uint mappedIndex(uint index) const { return d()->mappedIndex(index); } - static void markObjects(Heap::Base *d, ExecutionEngine *e); - static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes); static ReturnedValue get(const Heap::ArrayData *d, uint index); static bool put(Object *o, uint index, const Value &value); diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp index a810b38f24..aa7d01d16c 100644 --- a/src/qml/jsruntime/qv4dataview.cpp +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -84,13 +84,6 @@ void DataViewCtor::call(const Managed *that, Scope &scope, CallData *callData) construct(that, scope, callData); } - -void DataView::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - DataView::Data *v = static_cast(that); - v->buffer->mark(e); -} - void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h index 11cc0a6bd9..f61a2a1780 100644 --- a/src/qml/jsruntime/qv4dataview_p.h +++ b/src/qml/jsruntime/qv4dataview_p.h @@ -63,11 +63,14 @@ struct DataViewCtor : FunctionObject { void init(QV4::ExecutionContext *scope); }; -struct DataView : Object { +#define DataViewMembers(class, Member) \ + Member(class, Pointer, buffer) \ + Member(class, uint, byteLength) \ + Member(class, uint, byteOffset) + +DECLARE_HEAP_OBJECT(DataView, Object) { + DECLARE_MARK_TABLE(DataView); void init() { Object::init(); } - Pointer buffer; - uint byteLength; - uint byteOffset; }; } @@ -84,8 +87,6 @@ struct DataView : Object { V4_OBJECT2(DataView, Object) V4_PROTOTYPE(dataViewPrototype) - - static void markObjects(Heap::Base *that, ExecutionEngine *e); }; struct DataViewPrototype: Object diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index f290bc5136..798a14086d 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -173,14 +173,6 @@ void ErrorObject::method_get_stack(const BuiltinFunction *, Scope &scope, CallDa scope.result = This->d()->stack; } -void ErrorObject::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - ErrorObject::Data *This = static_cast(that); - if (This->stack) - This->stack->mark(e); - Object::markObjects(that, e); -} - DEFINE_OBJECT_VTABLE(ErrorObject); DEFINE_OBJECT_VTABLE(SyntaxErrorObject); diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 9ba9f05234..a5af0b6ab6 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -62,7 +62,12 @@ struct SyntaxErrorObject; namespace Heap { -struct ErrorObject : Object { + +#define ErrorObjectMembers(class, Member) \ + Member(class, Pointer, stack) + +DECLARE_HEAP_OBJECT(ErrorObject, Object) { + DECLARE_MARK_TABLE(ErrorObject); enum ErrorType { Error, EvalError, @@ -72,6 +77,8 @@ struct ErrorObject : Object { TypeError, URIError }; + StackTrace *stackTrace; + ErrorType errorType; void init(); void init(const Value &message, ErrorType t = Error); @@ -80,10 +87,6 @@ struct ErrorObject : Object { delete stackTrace; Object::destroy(); } - - ErrorType errorType; - StackTrace *stackTrace; - Pointer stack; }; struct EvalErrorObject : ErrorObject { @@ -173,7 +176,6 @@ struct ErrorObject: Object { static const char *className(Heap::ErrorObject::ErrorType t); static void method_get_stack(const BuiltinFunction *, Scope &scope, CallData *callData); - static void markObjects(Heap::Base *that, ExecutionEngine *e); }; template<> diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index e9431ed25e..ae1a403ea1 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -69,6 +69,8 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(FunctionObject); +Q_STATIC_ASSERT((Heap::FunctionObject::markTable & Heap::Object::markTable) == Heap::Object::markTable); + void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, bool createProto) { Object::init(); @@ -149,15 +151,6 @@ void FunctionObject::call(const Managed *, Scope &scope, CallData *) scope.result = Encode::undefined(); } -void FunctionObject::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - Heap::FunctionObject *o = static_cast(that); - if (o->scope) - o->scope->mark(e); - - Object::markObjects(that, e); -} - Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function) { return scope->d()->engine->memoryManager->allocObject(scope, function); @@ -606,14 +599,3 @@ void BoundFunction::construct(const Managed *that, Scope &scope, CallData *dd) ScopedFunctionObject t(scope, f->target()); t->construct(scope, callData); } - -void BoundFunction::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - BoundFunction::Data *o = static_cast(that); - if (o->target) - o->target->mark(e); - o->boundThis.mark(e); - if (o->boundArgs) - o->boundArgs->mark(e); - FunctionObject::markObjects(that, e); -} diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 45d7485f1b..083ff4343b 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -65,7 +65,12 @@ struct BuiltinFunction; namespace Heap { -struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { +#define FunctionObjectMembers(class, Member) \ + Member(class, Pointer, scope) \ + Member(class, Function *, function) + +DECLARE_HEAP_OBJECT(FunctionObject, Object) { + DECLARE_MARK_TABLE(FunctionObject); enum { Index_Prototype = 0, Index_ProtoConstructor = 0 @@ -82,9 +87,6 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { bool needsActivation() const { return function ? function->needsActivation() : false; } const QV4::Object *protoProperty() const { return propertyData(Index_Prototype)->cast(); } - - Pointer scope; - Function *function; }; struct FunctionCtor : FunctionObject { @@ -119,11 +121,15 @@ struct ScriptFunction : FunctionObject { void init(QV4::ExecutionContext *scope, Function *function); }; -struct BoundFunction : FunctionObject { +#define BoundFunctionMembers(class, Member) \ + Member(class, Pointer, target) \ + Member(class, Value, boundThis) \ + Member(class, Pointer, boundArgs) + +DECLARE_HEAP_OBJECT(BoundFunction, FunctionObject) { + DECLARE_MARK_TABLE(BoundFunction); + void init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs); - Pointer target; - Value boundThis; - Pointer boundArgs; }; } @@ -160,8 +166,6 @@ struct Q_QML_EXPORT FunctionObject: Object { bool isBoundFunction() const; QQmlSourceLocation sourceLocation() const; - - static void markObjects(Heap::Base *that, ExecutionEngine *e); }; template<> @@ -259,8 +263,6 @@ struct BoundFunction: FunctionObject { static void construct(const Managed *, Scope &scope, CallData *d); static void call(const Managed *that, Scope &scope, CallData *dd); - - static void markObjects(Heap::Base *that, ExecutionEngine *e); }; } diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index b0d14fc2b4..0f4859f0fa 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -184,6 +184,7 @@ namespace Heap { struct DataView; struct TypedArray; + template struct Pointer; } class MemoryManager; diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index 3a84a83b9c..1b43fd86e8 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -46,6 +46,7 @@ using namespace QV4; const VTable Managed::static_vtbl = { + 0, 0, Managed::IsExecutionContext, Managed::IsString, diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 5c764e7ff0..d4cc31b96a 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -91,6 +91,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} dptr->_checkIsInitialized(); \ return dptr; \ } \ + static Q_CONSTEXPR quint64 markTable = QV4::Heap::DataClass::markTable; \ V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass) #define V4_MANAGED(DataClass, superClass) \ @@ -129,6 +130,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} #define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \ { \ parentVTable, \ + markTable, \ classname::IsExecutionContext, \ classname::IsString, \ classname::IsObject, \ @@ -139,7 +141,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} classname::MyType, \ #classname, \ Q_VTABLE_FUNCTION(classname, destroy), \ - markObjects, \ + Q_VTABLE_FUNCTION(classname, markObjects), \ isEqualTo \ } @@ -206,6 +208,7 @@ public: bool markBit() const { return d()->isMarked(); } static void destroy(Heap::Base *) {} + static void markObjects(Heap::Base *, ExecutionEngine *) {} Q_ALWAYS_INLINE Heap::Base *heapObject() const { return m(); diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index db45c77472..3a6d66a030 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -45,13 +45,6 @@ using namespace QV4; DEFINE_MANAGED_VTABLE(MemberData); -void MemberData::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - Heap::MemberData *m = static_cast(that); - for (uint i = 0; i < m->size; ++i) - m->data[i].mark(e); -} - Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberData *old) { Q_ASSERT(!old || old->size < n); diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index 5c89dfe8ec..c4e797ff8d 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -59,12 +59,12 @@ namespace QV4 { namespace Heap { -struct MemberData : Base { - union { - uint size; - double _dummy; - }; - Value data[1]; +#define MemberDataMembers(class, Member) \ + Member(class, uint, size) \ + Member(class, ValueArray, data) + +DECLARE_HEAP_OBJECT(MemberData, Base) { + DECLARE_MARK_TABLE(MemberData); }; V4_ASSERT_IS_TRIVIAL(MemberData) @@ -80,8 +80,6 @@ struct MemberData : Managed inline uint size() const { return d()->size; } static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = 0); - - static void markObjects(Heap::Base *that, ExecutionEngine *e); }; } diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index dd3bbccde3..095aa6b4da 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -258,18 +258,6 @@ void Object::defineReadonlyConfigurableProperty(String *name, const Value &value insertMember(name, value, Attr_ReadOnly_ButConfigurable); } -void Object::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - Heap::Object *o = static_cast(that); - - if (o->memberData) - o->memberData->mark(e); - if (o->arrayData) - o->arrayData->mark(e); - if (o->prototype) - o->prototype->mark(e); -} - void Object::insertMember(String *s, const Property *p, PropertyAttributes attributes) { uint idx; diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 0d17afbf41..b0eec1adfc 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -67,17 +67,19 @@ struct BuiltinFunction; namespace Heap { -struct Object : Base { +#define ObjectMembers(class, Member) \ + Member(class, InternalClass *, internalClass) \ + Member(class, Pointer, prototype) \ + Member(class, Pointer, memberData) \ + Member(class, Pointer, arrayData) + +DECLARE_HEAP_OBJECT(Object, Base) { + DECLARE_MARK_TABLE(Object); void init() { Base::init(); } void destroy() { Base::destroy(); } const Value *propertyData(uint index) const { return memberData->data + index; } Value *propertyData(uint index) { return memberData->data + index; } - - InternalClass *internalClass; - Pointer prototype; - Pointer memberData; - Pointer arrayData; }; } @@ -114,7 +116,8 @@ struct Object : Base { dptr->_checkIsInitialized(); \ return dptr; \ } \ - V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass); + V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass); \ + static Q_CONSTEXPR quint64 markTable = QV4::Heap::DataClass::markTable; #define V4_INTERNALCLASS(c) \ static QV4::InternalClass *defaultInternalClass(QV4::ExecutionEngine *e) \ @@ -400,7 +403,6 @@ public: inline void call(Scope &scope, CallData *d) const { vtable()->call(this, scope, d); } protected: - static void markObjects(Heap::Base *that, ExecutionEngine *e); static void construct(const Managed *m, Scope &scope, CallData *); static void call(const Managed *m, Scope &scope, CallData *); static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index 987c322e47..de82bf835f 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -215,15 +215,6 @@ void PersistentValueStorage::free(Value *v) freePage(p); } -static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase) -{ - while (engine->jsStackTop > markBase) { - Heap::Base *h = engine->popForGC(); - Q_ASSERT (h->vtable()->markObjects); - h->vtable()->markObjects(h, engine); - } -} - void PersistentValueStorage::mark(ExecutionEngine *e) { Value *markBase = e->jsStackTop; @@ -234,7 +225,7 @@ void PersistentValueStorage::mark(ExecutionEngine *e) if (Managed *m = p->values[i].as()) m->mark(e); } - drainMarkStack(e, markBase); + e->memoryManager->drainMarkStack(markBase); p = p->header.next; } diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index c9b4b433bd..deea893632 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -1841,15 +1841,6 @@ void QObjectMethod::callInternal(CallData *callData, Scope &scope) const } } -void QObjectMethod::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - QObjectMethod::Data *This = static_cast(that); - if (This->valueTypeWrapper) - This->valueTypeWrapper->mark(e); - - FunctionObject::markObjects(that, e); -} - DEFINE_OBJECT_VTABLE(QObjectMethod); diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index d81ef2a680..002e1f2eb0 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -95,7 +95,15 @@ private: QQmlQPointer qObj; }; -struct QObjectMethod : FunctionObject { +#define QObjectMethodMembers(class, Member) \ + Member(class, Pointer, valueTypeWrapper) \ + Member(class, QQmlQPointer, qObj) \ + Member(class, QQmlPropertyCache *, _propertyCache) \ + Member(class, int, index) + +DECLARE_HEAP_OBJECT(QObjectMethod, FunctionObject) { + DECLARE_MARK_TABLE(QObjectMethod); + void init(QV4::ExecutionContext *scope); void destroy() { @@ -113,18 +121,10 @@ struct QObjectMethod : FunctionObject { _propertyCache = c; } - Pointer valueTypeWrapper; - const QMetaObject *metaObject(); QObject *object() const { return qObj.data(); } void setObject(QObject *o) { qObj = o; } -private: - QQmlQPointer qObj; - QQmlPropertyCache *_propertyCache; - -public: - int index; }; struct QMetaObjectWrapper : FunctionObject { @@ -243,8 +243,6 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject void callInternal(CallData *callData, Scope &scope) const; - static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e); - static QPair extractQtMethod(const QV4::FunctionObject *function); }; diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index 9e94c58432..6778145ff1 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -126,9 +126,3 @@ void Heap::RegExp::destroy() delete pattern; Base::destroy(); } - -void RegExp::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - Q_UNUSED(that); - Q_UNUSED(e); -} diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h index d3e63375a5..348af0fb14 100644 --- a/src/qml/jsruntime/qv4regexp_p.h +++ b/src/qml/jsruntime/qv4regexp_p.h @@ -119,8 +119,6 @@ struct RegExp : public Managed int captureCount() const { return subPatternCount() + 1; } - static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e); - friend class RegExpCache; }; diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 0894d0c25b..ca893839ef 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -162,15 +162,6 @@ void RegExpObject::initProperties() *propertyData(Index_Multiline) = Primitive::fromBoolean(value()->multiLine); } - -void RegExpObject::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - RegExpObject::Data *re = static_cast(that); - if (re->value) - re->value->mark(e); - Object::markObjects(that, e); -} - Value *RegExpObject::lastIndexProperty() { Q_ASSERT(0 == internalClass()->find(engine()->id_lastIndex())); @@ -303,15 +294,6 @@ void RegExpCtor::call(const Managed *that, Scope &scope, CallData *callData) construct(that, scope, callData); } -void RegExpCtor::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - RegExpCtor::Data *This = static_cast(that); - This->lastMatch.mark(e); - if (This->lastInput) - This->lastInput->mark(e); - FunctionObject::markObjects(that, e); -} - void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor) { Scope scope(engine); diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index c0c7dfa78a..6726568eec 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -73,21 +73,28 @@ namespace QV4 { namespace Heap { -struct RegExpObject : Object { +#define RegExpObjectMembers(class, Member) \ + Member(class, Pointer, value) \ + Member(class, bool, global) + +DECLARE_HEAP_OBJECT(RegExpObject, Object) { + DECLARE_MARK_TABLE(RegExpObject); + void init(); void init(QV4::RegExp *value, bool global); void init(const QRegExp &re); - - Pointer value; - bool global; }; -struct RegExpCtor : FunctionObject { +#define RegExpCtorMembers(class, Member) \ + Member(class, Value, lastMatch) \ + Member(class, Pointer, lastInput) \ + Member(class, int, lastMatchStart) \ + Member(class, int, lastMatchEnd) + +DECLARE_HEAP_OBJECT(RegExpCtor, FunctionObject) { + DECLARE_MARK_TABLE(RegExpCtor); + void init(QV4::ExecutionContext *scope); - Value lastMatch; - Pointer lastInput; - int lastMatchStart; - int lastMatchEnd; void clearLastMatch(); }; @@ -126,9 +133,6 @@ struct RegExpObject: Object { QString toString() const; QString source() const; uint flags() const; - -protected: - static void markObjects(Heap::Base *that, ExecutionEngine *e); }; struct RegExpCtor: FunctionObject @@ -142,7 +146,6 @@ struct RegExpCtor: FunctionObject static void construct(const Managed *m, Scope &scope, CallData *callData); static void call(const Managed *that, Scope &scope, CallData *callData); - static void markObjects(Heap::Base *that, ExecutionEngine *e); }; struct RegExpPrototype: RegExpObject diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 72be11eca0..c6cc5a4639 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -145,13 +145,6 @@ void StringObject::advanceIterator(Managed *m, ObjectIterator *it, Value *name, return Object::advanceIterator(m, it, name, index, p, attrs); } -void StringObject::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - StringObject::Data *o = static_cast(that); - o->string->mark(e); - Object::markObjects(that, e); -} - DEFINE_OBJECT_VTABLE(StringCtor); void Heap::StringCtor::init(QV4::ExecutionContext *scope) diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index aed3bc1e28..ae9377abb4 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -60,14 +60,18 @@ namespace QV4 { namespace Heap { -struct StringObject : Object { +#define StringObjectMembers(class, Member) \ + Member(class, Pointer, string) + +DECLARE_HEAP_OBJECT(StringObject, Object) { + DECLARE_MARK_TABLE(StringObject); + enum { LengthPropertyIndex = 0 }; void init(); void init(const QV4::String *string); - String *string; Heap::String *getIndex(uint index) const; uint length() const; @@ -96,7 +100,6 @@ struct StringObject: Object { protected: static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs); - static void markObjects(Heap::Base *that, ExecutionEngine *e); }; struct StringCtor: FunctionObject diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 5573a2e57f..e936158ab1 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -375,12 +375,6 @@ Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type return e->memoryManager->allocObject(e->emptyClass, e->typedArrayPrototype + t, t); } -void TypedArray::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - static_cast(that)->buffer->mark(e); - Object::markObjects(that, e); -} - ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProperty) { Scope scope(static_cast(m)->engine()); diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index fbf13c9815..f6b302a396 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -72,7 +72,15 @@ struct TypedArrayOperations { namespace Heap { -struct TypedArray : Object { +#define TypedArrayMembers(class, Member) \ + Member(class, Pointer, buffer) \ + Member(class, const TypedArrayOperations *, type) \ + Member(class, uint, byteLength) \ + Member(class, uint, byteOffset) \ + Member(class, uint, arrayType) + +DECLARE_HEAP_OBJECT(TypedArray, Object) { + DECLARE_MARK_TABLE(TypedArray); enum Type { Int8Array, UInt8Array, @@ -87,12 +95,6 @@ struct TypedArray : Object { }; void init(Type t); - - const TypedArrayOperations *type; - Pointer buffer; - uint byteLength; - uint byteOffset; - Type arrayType; }; struct TypedArrayCtor : FunctionObject { @@ -128,10 +130,9 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object } Heap::TypedArray::Type arrayType() const { - return d()->arrayType; + return static_cast(d()->arrayType); } - static void markObjects(Heap::Base *that, ExecutionEngine *e); static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); static bool putIndexed(Managed *m, uint index, const Value &value); }; diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index 8285ef4de7..28d39b7fb7 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -72,6 +72,7 @@ namespace QV4 { struct VTable { const VTable * const parent; + const quint64 markTable; uint isExecutionContext : 1; uint isString : 1; uint isObject : 1; @@ -91,6 +92,8 @@ namespace Heap { struct Q_QML_EXPORT Base { void *operator new(size_t) = delete; + static Q_CONSTEXPR quint64 markTable = 0; + const VTable *vt; inline ReturnedValue asReturnedValue() const; diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index a829e902fb..bb600c6c0f 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -740,13 +740,58 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nM return o; } -static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase) +void MemoryManager::drainMarkStack(Value *markBase) { while (engine->jsStackTop > markBase) { Heap::Base *h = engine->popForGC(); Q_ASSERT(h); // at this point we should only have Heap::Base objects in this area on the stack. If not, weird things might happen. - Q_ASSERT (h->vtable()->markObjects); - h->vtable()->markObjects(h, engine); + if (h->vtable()->markObjects) + h->vtable()->markObjects(h, engine); + if (quint64 m = h->vtable()->markTable) { +// qDebug() << "using mark table:" << hex << m << "for" << h; + void **mem = reinterpret_cast(h); + while (m) { + MarkFlags mark = static_cast(m & 3); + switch (mark) { + case Mark_NoMark: + break; + case Mark_Value: +// qDebug() << "marking value at " << mem; + reinterpret_cast(mem)->mark(engine); + break; + case Mark_Pointer: { +// qDebug() << "marking pointer at " << mem; + Heap::Pointer *p = reinterpret_cast *>(mem); + if (*p) + (*p)->mark(engine); + break; + } + case Mark_ValueArray: { + Q_ASSERT(m == Mark_ValueArray); +// qDebug() << "marking Value Array at offset" << hex << (mem - reinterpret_cast(h)); + uint size; + Value *v = reinterpret_cast(mem); + if (h->vtable() == QV4::MemberData::staticVTable()) { + size = static_cast(h)->size; + } else if (h->vtable()->isArrayData) { + size = static_cast(h)->alloc; + } else { + size = 0; + Q_ASSERT(false); + } + const Value *end = v + size; + while (v < end) { + v->mark(engine); + ++v; + } + break; + } + } + + m >>= 2; + ++mem; + } + } } } @@ -788,10 +833,10 @@ void MemoryManager::mark() qobjectWrapper->mark(engine); if (engine->jsStackTop >= engine->jsStackLimit) - drainMarkStack(engine, markBase); + drainMarkStack(markBase); } - drainMarkStack(engine, markBase); + drainMarkStack(markBase); } void MemoryManager::sweep(bool lastSweep) diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 00daf8a622..016879799a 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -427,6 +427,7 @@ public: // called when a JS object grows itself. Specifically: Heap::String::append void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; } + void drainMarkStack(Value *markBase); protected: diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index 588ae21ee0..90e7d9cb61 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -255,6 +255,54 @@ Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize); Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits); Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits); +// Some helper classes and macros to automate the generation of our +// tables used for marking objects + +enum MarkFlags { + Mark_NoMark = 0, + Mark_Value = 1, + Mark_Pointer = 2, + Mark_ValueArray = 3 +}; + +template +struct MarkFlagsForType { + static const quint64 markFlags = Mark_NoMark; +}; +template +struct MarkFlagsForType> { + static const quint64 markFlags = Mark_Pointer; +}; +template<> +struct MarkFlagsForType { + static const quint64 markFlags = Mark_Value; +}; + +typedef Value ValueArray[1]; +template<> +struct MarkFlagsForType { + static const quint64 markFlags = Mark_ValueArray; +}; + +#define HEAP_OBJECT_MEMBER_EXPANSION(c, type, name) type name; + +#define HEAP_OBJECT_MARK_EXPANSION(class, type, name) \ + (MarkFlagsForType::markFlags << (offsetof(class, name) >> 2)) | + +#define DECLARE_HEAP_OBJECT(name, base) \ +struct name##Data { \ + name##Members(name, HEAP_OBJECT_MEMBER_EXPANSION) \ +}; \ +struct name##SizeStruct : base, name##Data {}; \ +static Q_CONSTEXPR quint64 name##_markTable = \ + (name##Members(name##Data, HEAP_OBJECT_MARK_EXPANSION) 0) << (((sizeof(name##SizeStruct) - sizeof(name##Data)) >> 2) | QV4::Heap::base::markTable; \ + \ +struct name : base, name##Data + +#define DECLARE_MARK_TABLE(class) static Q_CONSTEXPR quint64 markTable = class##_markTable + + + } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index a04f47e6a4..487846f610 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1046,14 +1046,18 @@ namespace QV4 { namespace Heap { -struct QmlIncubatorObject : Object { +#define QmlIncubatorObjectMembers(class, Member) \ + Member(class, Value, valuemap) \ + Member(class, Value, statusChanged) \ + Member(class, Pointer, qmlContext) \ + Member(class, QQmlComponentIncubator *, incubator) \ + Member(class, QQmlQPointer, parent) + +DECLARE_HEAP_OBJECT(QmlIncubatorObject, Object) { + DECLARE_MARK_TABLE(QmlIncubatorObject); + void init(QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous); inline void destroy(); - QQmlComponentIncubator *incubator; - QQmlQPointer parent; - QV4::Value valuemap; - QV4::Value statusChanged; - Pointer qmlContext; }; } @@ -1069,8 +1073,6 @@ struct QmlIncubatorObject : public QV4::Object static void method_get_object(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_forceCompletion(const BuiltinFunction *, Scope &scope, CallData *callData); - static void markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e); - void statusChanged(QQmlIncubator::Status); void setInitialState(QObject *); }; @@ -1497,16 +1499,6 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o) } } -void QV4::QmlIncubatorObject::markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e) -{ - QmlIncubatorObject::Data *o = static_cast(that); - o->valuemap.mark(e); - o->statusChanged.mark(e); - if (o->qmlContext) - o->qmlContext->mark(e); - Object::markObjects(that, e); -} - void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s) { QV4::Scope scope(engine()); diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index d0d9f080da..868120a2f6 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -1597,10 +1597,12 @@ struct QQmlXMLHttpRequestWrapper : Object { QQmlXMLHttpRequest *request; }; -struct QQmlXMLHttpRequestCtor : FunctionObject { - void init(ExecutionEngine *engine); +#define QQmlXMLHttpRequestCtorMembers(class, Member) \ + Member(class, Pointer, proto) - Pointer proto; +DECLARE_HEAP_OBJECT(QQmlXMLHttpRequestCtor, FunctionObject) { + DECLARE_MARK_TABLE(QQmlXMLHttpRequestCtor); + void init(ExecutionEngine *engine); }; } @@ -1614,12 +1616,7 @@ struct QQmlXMLHttpRequestWrapper : public Object struct QQmlXMLHttpRequestCtor : public FunctionObject { V4_OBJECT2(QQmlXMLHttpRequestCtor, FunctionObject) - static void markObjects(Heap::Base *that, ExecutionEngine *e) { - QQmlXMLHttpRequestCtor::Data *c = static_cast(that); - if (c->proto) - c->proto->mark(e); - FunctionObject::markObjects(that, e); - } + static void construct(const Managed *that, Scope &scope, QV4::CallData *) { Scoped ctor(scope, that->as()); -- cgit v1.2.3 From 4de7e48ab160dacc7a09360e80264eac4945a8f4 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 25 Jan 2017 15:24:27 +0100 Subject: Move most of the ExecutionContext's over to the new mark handling CallContext still requires further work, as the handling of locals is different between a CallContext and a SimpleCallContext. Change-Id: I74945ef701f60907aab0fb1a9939da1331235f6e Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4context.cpp | 53 ++++++++----------------------------- src/qml/jsruntime/qv4context_p.h | 46 +++++++++++++++++++++----------- src/qml/jsruntime/qv4qmlcontext_p.h | 9 ++++--- 3 files changed, 48 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 740ebbe359..fe01b9abad 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -264,52 +264,21 @@ bool CallContext::needsOwnArguments() const return (f && f->needsActivation()) || (argc() < (f ? static_cast(f->nFormals) : 0)); } -void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine) +void CallContext::markObjects(Heap::Base *m, ExecutionEngine *engine) { - ExecutionContext::Data *ctx = static_cast(m); + QV4::Heap::CallContext *ctx = static_cast(m); - if (ctx->outer) - ctx->outer->mark(engine); - - switch (ctx->type) { - case Heap::ExecutionContext::Type_CatchContext: { - CatchContext::Data *c = static_cast(ctx); - c->exceptionVarName->mark(engine); - c->exceptionValue.mark(engine); - break; - } - case Heap::ExecutionContext::Type_WithContext: { - WithContext::Data *w = static_cast(ctx); - if (w->withObject) - w->withObject->mark(engine); - break; - } - case Heap::ExecutionContext::Type_GlobalContext: { - GlobalContext::Data *g = static_cast(ctx); - g->global->mark(engine); - break; - } - case Heap::ExecutionContext::Type_SimpleCallContext: - break; - case Heap::ExecutionContext::Type_CallContext: { - QV4::Heap::CallContext *c = static_cast(ctx); - Q_ASSERT(c->v4Function); + if (ctx->type == Heap::ExecutionContext::Type_CallContext) { + Q_ASSERT(ctx->v4Function); ctx->callData->thisObject.mark(engine); - for (int arg = 0; arg < qMax(ctx->callData->argc, (int)c->v4Function->nFormals); ++arg) + for (int arg = 0; arg < qMax(ctx->callData->argc, (int)ctx->v4Function->nFormals); ++arg) ctx->callData->args[arg].mark(engine); - for (unsigned local = 0, lastLocal = c->v4Function->compiledFunction->nLocals; local < lastLocal; ++local) - c->locals[local].mark(engine); - if (c->activation) - c->activation->mark(engine); - if (c->function) - c->function->mark(engine); - break; - } - case Heap::ExecutionContext::Type_QmlContext: { - QmlContext::Data *g = static_cast(ctx); - g->qml->mark(engine); - break; - } + for (unsigned local = 0, lastLocal = ctx->v4Function->compiledFunction->nLocals; local < lastLocal; ++local) + ctx->locals[local].mark(engine); + if (ctx->activation) + ctx->activation->mark(engine); + if (ctx->function) + ctx->function->mark(engine); } } diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index bcfee2e1f8..cbf1ac9f7d 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -95,7 +95,11 @@ namespace Heap { struct QmlContext; -struct ExecutionContext : Base { +#define ExecutionContextMembers(class, Member) \ + Member(class, Pointer, outer) + +DECLARE_HEAP_OBJECT(ExecutionContext, Base) { + DECLARE_MARK_TABLE(ExecutionContext); enum ContextType { Type_GlobalContext = 0x1, Type_CatchContext = 0x2, @@ -117,7 +121,6 @@ struct ExecutionContext : Base { CallData *callData; ExecutionEngine *engine; - Pointer outer; Lookup *lookups; const QV4::Value *constantTable; CompiledData::CompilationUnit *compilationUnit; @@ -128,7 +131,12 @@ struct ExecutionContext : Base { }; V4_ASSERT_IS_TRIVIAL(ExecutionContext) -struct CallContext : ExecutionContext { +#define CallContextMembers(class, Member) \ + Member(class, Pointer, function) \ + Member(class, Pointer, activation) + +DECLARE_HEAP_OBJECT(CallContext, ExecutionContext) { + DECLARE_MARK_TABLE(CallContext); static CallContext *createSimpleContext(ExecutionEngine *v4); void freeSimpleCallContext(); @@ -139,27 +147,38 @@ struct CallContext : ExecutionContext { inline unsigned int formalParameterCount() const; - Pointer function; QV4::Function *v4Function; Value *locals; - Pointer activation; }; V4_ASSERT_IS_TRIVIAL(CallContext) -struct GlobalContext : ExecutionContext { +#define GlobalContextMembers(class, Member) \ + Member(class, Pointer, global) + +DECLARE_HEAP_OBJECT(GlobalContext, ExecutionContext) { + DECLARE_MARK_TABLE(GlobalContext); + void init(ExecutionEngine *engine); - Pointer global; }; V4_ASSERT_IS_TRIVIAL(GlobalContext) -struct CatchContext : ExecutionContext { +#define CatchContextMembers(class, Member) \ + Member(class, Pointer, exceptionVarName) \ + Member(class, Value, exceptionValue) + +DECLARE_HEAP_OBJECT(CatchContext, ExecutionContext) { + DECLARE_MARK_TABLE(CatchContext); + void init(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue); - Pointer exceptionVarName; - Value exceptionValue; }; V4_ASSERT_IS_TRIVIAL(CatchContext) -struct WithContext : ExecutionContext { +#define WithContextMembers(class, Member) \ + Member(class, Pointer, withObject) + +DECLARE_HEAP_OBJECT(WithContext, ExecutionContext) { + DECLARE_MARK_TABLE(WithContext); + void init(ExecutionContext *outerContext, Object *with) { Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_WithContext); @@ -171,8 +190,6 @@ struct WithContext : ExecutionContext { withObject = with; } - - Pointer withObject; }; V4_ASSERT_IS_TRIVIAL(WithContext) @@ -207,8 +224,6 @@ struct Q_QML_EXPORT ExecutionContext : public Managed Function *getFunction() const; - static void markObjects(Heap::Base *m, ExecutionEngine *e); - Value &thisObject() const { return d()->callData->thisObject; } @@ -239,6 +254,7 @@ struct Q_QML_EXPORT CallContext : public ExecutionContext inline ReturnedValue argument(int i) const; bool needsOwnArguments() const; + static void markObjects(Heap::Base *m, ExecutionEngine *e); }; inline ReturnedValue CallContext::argument(int i) const { diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index 6e5e743609..73100807ae 100644 --- a/src/qml/jsruntime/qv4qmlcontext_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -77,10 +77,13 @@ struct QmlContextWrapper : Object { QQmlQPointer scopeObject; }; -struct QmlContext : ExecutionContext { - void init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml); +#define QmlContextMembers(class, Member) \ + Member(class, Pointer, qml) + +DECLARE_HEAP_OBJECT(QmlContext, ExecutionContext) { + DECLARE_MARK_TABLE(QmlContext); - Pointer qml; + void init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml); }; } -- cgit v1.2.3 From 58b882ad42f99e03ac8dca13ff9c0d39fcafbaa0 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 27 Jan 2017 09:05:54 +0100 Subject: Avoid one indirection when looking up local variables Simple CallContext's never have locals, as they get converted to temps in the compiler. For regular CallContext's, local variables always got appended to the callcontext. So there was no need to have an additional indirect pointer to them in the CallContext. This speeds up v8-bench by 1-2%. Change-Id: I3def7ba653aea5bc5761076f398450ae30c62823 Reviewed-by: Simon Hausmann --- src/qml/jit/qv4assembler.cpp | 3 +-- src/qml/jsruntime/qv4context.cpp | 4 +--- src/qml/jsruntime/qv4context_p.h | 2 +- src/qml/jsruntime/qv4function.cpp | 3 ++- 4 files changed, 5 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index e658977da1..0b3d0bd0cc 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -286,8 +286,7 @@ typename Assembler::Pointer Assembler: } break; case IR::ArgLocal::Local: case IR::ArgLocal::ScopedLocal: { - loadPtr(Address(baseReg, qOffsetOf(CallContext::Data, locals)), baseReg); - offset = al->index * sizeof(Value); + offset = qOffsetOf(CallContext::Data, locals) + al->index * sizeof(Value); } break; default: Q_UNREACHABLE(); diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index fe01b9abad..569523595c 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -61,7 +61,7 @@ DEFINE_MANAGED_VTABLE(GlobalContext); /* Function *f, int argc */ #define requiredMemoryForExecutionContect(f, argc) \ - ((sizeof(CallContext::Data) + 7) & ~7) + \ + sizeof(CallContext::Data) - sizeof(Value) + \ sizeof(Value) * (f->compiledFunction->nLocals + qMax((uint)argc, f->nFormals)) + sizeof(CallData) Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData *callData) @@ -80,7 +80,6 @@ Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData c->compilationUnit = function->compilationUnit; c->lookups = c->compilationUnit->runtimeLookups; c->constantTable = c->compilationUnit->constants; - c->locals = (Value *)((quintptr(c + 1) + 7) & ~7); const CompiledData::Function *compiledFunction = function->compiledFunction; int nLocals = compiledFunction->nLocals; @@ -314,7 +313,6 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio ctx->lookups = function->compilationUnit->runtimeLookups; ctx->constantTable = function->compilationUnit->constants; ctx->outer = this->d(); - ctx->locals = scope.alloc(function->compiledFunction->nLocals); for (int i = callData->argc; i < (int)function->nFormals; ++i) callData->args[i] = Encode::undefined(); diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index cbf1ac9f7d..96cdb90db9 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -148,7 +148,7 @@ DECLARE_HEAP_OBJECT(CallContext, ExecutionContext) { inline unsigned int formalParameterCount() const; QV4::Function *v4Function; - Value *locals; + Value locals[1]; }; V4_ASSERT_IS_TRIVIAL(CallContext) diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index 358c2d079c..dd3208c7e9 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -86,7 +86,8 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, activationRequired = compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject)); canUseSimpleCall = !needsActivation() && !(compiledFunction->flags & CompiledData::Function::HasCatchOrWith) && - !(compiledFunction->nFormals > QV4::Global::ReservedArgumentCount) && !isNamedExpression(); + compiledFunction->nFormals <= QV4::Global::ReservedArgumentCount && + compiledFunction->nLocals == 0 && !isNamedExpression(); } Function::~Function() -- cgit v1.2.3 From 10c1e4053366085080a39ea84ebbd189c8d827ec Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 27 Jan 2017 09:57:00 +0100 Subject: Unify mark handling for MemberData and ArrayData Introduce a ValueArray class, that defines an array of Values at the end of a Heap Object. Change-Id: I00efbf6f5839a6687dd5bc5fc037ec8f06e0936e Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4argumentsobject.cpp | 4 +- src/qml/jsruntime/qv4arraydata.cpp | 144 +++++++++++++++---------------- src/qml/jsruntime/qv4arraydata_p.h | 46 +++++----- src/qml/jsruntime/qv4arrayobject.cpp | 4 +- src/qml/jsruntime/qv4engine.cpp | 6 +- src/qml/jsruntime/qv4functionobject.cpp | 4 +- src/qml/jsruntime/qv4global_p.h | 1 + src/qml/jsruntime/qv4lookup.cpp | 6 +- src/qml/jsruntime/qv4memberdata.cpp | 7 +- src/qml/jsruntime/qv4memberdata_p.h | 11 ++- src/qml/jsruntime/qv4object.cpp | 12 +-- src/qml/jsruntime/qv4object_p.h | 8 +- src/qml/jsruntime/qv4objectproto.cpp | 8 +- src/qml/jsruntime/qv4runtime.cpp | 2 +- src/qml/jsruntime/qv4value_p.h | 14 +++ src/qml/memory/qv4mm.cpp | 17 ++-- src/qml/memory/qv4mmdefs_p.h | 2 - src/qml/qml/qqmlvmemetaobject.cpp | 2 +- 18 files changed, 149 insertions(+), 149 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 39b99e9876..33cda59b72 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -91,7 +91,7 @@ void ArgumentsObject::fullyCreate() if (numAccessors) { d()->mappedArguments = md->allocate(engine(), numAccessors); for (uint i = 0; i < numAccessors; ++i) { - d()->mappedArguments->data[i] = context()->callData->args[i]; + d()->mappedArguments->values[i] = context()->callData->args[i]; arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor); } } @@ -122,7 +122,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con map->copy(pd, mapAttrs); setArrayAttributes(index, Attr_Data); pd = arrayData()->getProperty(index); - pd->value = d()->mappedArguments->data[index]; + pd->value = d()->mappedArguments->values[index]; } bool strict = engine->current->strictMode; diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index 47d353ffd0..ef1a7bee3c 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -129,7 +129,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt if (d->type() < Heap::ArrayData::Sparse) { offset = d->d()->offset; - toCopy = d->d()->len; + toCopy = d->d()->values.size; } else { toCopy = d->alloc(); } @@ -150,7 +150,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt Heap::SimpleArrayData *n = scope.engine->memoryManager->allocManaged(size); n->init(); n->offset = 0; - n->len = d ? d->d()->len : 0; + n->values.size = d ? d->d()->values.size : 0; newData = n; } else { Heap::SparseArrayData *n = scope.engine->memoryManager->allocManaged(size); @@ -159,7 +159,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt } newData->setAlloc(alloc); newData->setType(newType); - newData->setAttrs(enforceAttributes ? reinterpret_cast(newData->d()->arrayData + alloc) : 0); + newData->setAttrs(enforceAttributes ? reinterpret_cast(newData->d()->values.v + alloc) : 0); o->setArrayData(newData); if (d) { @@ -171,12 +171,12 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt newData->attrs()[i] = Attr_Data; } - if (toCopy > d->d()->alloc - offset) { - uint copyFromStart = toCopy - (d->d()->alloc - offset); - memcpy(newData->d()->arrayData + toCopy - copyFromStart, d->d()->arrayData, sizeof(Value)*copyFromStart); + if (toCopy > d->d()->values.alloc - offset) { + uint copyFromStart = toCopy - (d->d()->values.alloc - offset); + memcpy(newData->d()->values.v + toCopy - copyFromStart, d->d()->values.v, sizeof(Value)*copyFromStart); toCopy -= copyFromStart; } - memcpy(newData->d()->arrayData, d->d()->arrayData + offset, sizeof(Value)*toCopy); + memcpy(newData->d()->values.v, d->d()->values.v + offset, sizeof(Value)*toCopy); } if (newType != Heap::ArrayData::Sparse) @@ -196,22 +196,22 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt lastFree = &sparse->freeList; storeValue(lastFree, 0); for (uint i = 0; i < toCopy; ++i) { - if (!sparse->arrayData[i].isEmpty()) { + if (!sparse->values[i].isEmpty()) { SparseArrayNode *n = sparse->sparse->insert(i); n->value = i; } else { storeValue(lastFree, i); - sparse->arrayData[i].setEmpty(); - lastFree = &sparse->arrayData[i].rawValueRef(); + sparse->values[i].setEmpty(); + lastFree = &sparse->values[i].rawValueRef(); } } } - if (toCopy < sparse->alloc) { - for (uint i = toCopy; i < sparse->alloc; ++i) { + if (toCopy < sparse->values.alloc) { + for (uint i = toCopy; i < sparse->values.alloc; ++i) { storeValue(lastFree, i); - sparse->arrayData[i].setEmpty(); - lastFree = &sparse->arrayData[i].rawValueRef(); + sparse->values[i].setEmpty(); + lastFree = &sparse->values[i].rawValueRef(); } storeValue(lastFree, UINT_MAX); } @@ -237,7 +237,7 @@ void ArrayData::ensureAttributes(Object *o) ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index) { const Heap::SimpleArrayData *dd = static_cast(d); - if (index >= dd->len) + if (index >= dd->values.size) return Primitive::emptyValue().asReturnedValue(); return dd->data(index).asReturnedValue(); } @@ -245,13 +245,13 @@ ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index) bool SimpleArrayData::put(Object *o, uint index, const Value &value) { Heap::SimpleArrayData *dd = o->d()->arrayData.cast(); - Q_ASSERT(index >= dd->len || !dd->attrs || !dd->attrs[index].isAccessor()); + Q_ASSERT(index >= dd->values.size || !dd->attrs || !dd->attrs[index].isAccessor()); // ### honour attributes dd->data(index) = value; - if (index >= dd->len) { + if (index >= dd->values.size) { if (dd->attrs) dd->attrs[index] = Attr_Data; - dd->len = index + 1; + dd->values.size = index + 1; } return true; } @@ -259,7 +259,7 @@ bool SimpleArrayData::put(Object *o, uint index, const Value &value) bool SimpleArrayData::del(Object *o, uint index) { Heap::SimpleArrayData *dd = o->d()->arrayData.cast(); - if (index >= dd->len) + if (index >= dd->values.size) return true; if (!dd->attrs || dd->attrs[index].isConfigurable()) { @@ -282,8 +282,8 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n) { Heap::SimpleArrayData *dd = o->d()->arrayData.cast(); Q_ASSERT(!dd->attrs); - if (dd->len + n > dd->alloc) { - realloc(o, Heap::ArrayData::Simple, dd->len + n, false); + if (dd->values.size + n > dd->values.alloc) { + realloc(o, Heap::ArrayData::Simple, dd->values.size + n, false); Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Simple); dd = o->d()->arrayData.cast(); } @@ -291,10 +291,10 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n) dd->offset -= n; // there is enough space left in front } else { // we need to wrap around, so: - dd->offset = dd->alloc - // start at the back, but subtract: + dd->offset = dd->values.alloc - // start at the back, but subtract: (n - dd->offset); // the number of items we can put in the free space at the start of the allocated array } - dd->len += n; + dd->values.size += n; for (uint i = 0; i < n; ++i) dd->data(i) = values[i].asReturnedValue(); } @@ -303,58 +303,58 @@ ReturnedValue SimpleArrayData::pop_front(Object *o) { Heap::SimpleArrayData *dd = o->d()->arrayData.cast(); Q_ASSERT(!dd->attrs); - if (!dd->len) + if (!dd->values.size) return Encode::undefined(); ReturnedValue v = dd->data(0).isEmpty() ? Encode::undefined() : dd->data(0).asReturnedValue(); - dd->offset = (dd->offset + 1) % dd->alloc; - --dd->len; + dd->offset = (dd->offset + 1) % dd->values.alloc; + --dd->values.size; return v; } uint SimpleArrayData::truncate(Object *o, uint newLen) { Heap::SimpleArrayData *dd = o->d()->arrayData.cast(); - if (dd->len < newLen) + if (dd->values.size < newLen) return newLen; if (!dd->attrs) { - dd->len = newLen; + dd->values.size = newLen; return newLen; } - while (dd->len > newLen) { - if (!dd->data(dd->len - 1).isEmpty() && !dd->attrs[dd->len - 1].isConfigurable()) - return dd->len; - --dd->len; + while (dd->values.size > newLen) { + if (!dd->data(dd->values.size - 1).isEmpty() && !dd->attrs[dd->values.size - 1].isConfigurable()) + return dd->values.size; + --dd->values.size; } - return dd->len; + return dd->values.size; } uint SimpleArrayData::length(const Heap::ArrayData *d) { - return d->len; + return d->values.size; } bool SimpleArrayData::putArray(Object *o, uint index, const Value *values, uint n) { Heap::SimpleArrayData *dd = o->d()->arrayData.cast(); - if (index + n > dd->alloc) { + if (index + n > dd->values.alloc) { reallocate(o, index + n + 1, false); dd = o->d()->arrayData.cast(); } - for (uint i = dd->len; i < index; ++i) + for (uint i = dd->values.size; i < index; ++i) dd->data(i) = Primitive::emptyValue(); for (uint i = 0; i < n; ++i) dd->data(index + i) = values[i]; - dd->len = qMax(dd->len, index + n); + dd->values.size = qMax(dd->values.size, index + n); return true; } void SparseArrayData::free(Heap::ArrayData *d, uint idx) { Q_ASSERT(d && d->type == Heap::ArrayData::Sparse); - Value *v = d->arrayData + idx; + Value *v = d->values.v + idx; if (d->attrs && d->attrs[idx].isAccessor()) { // double slot, free both. Order is important, so we have a double slot for allocation again afterwards. v[1].setEmpty(Value::fromReturnedValue(d->freeList).emptyValue()); @@ -382,32 +382,32 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot) ReturnedValue *last = &dd->freeList; while (1) { if (Value::fromReturnedValue(*last).value() == UINT_MAX) { - reallocate(o, dd->alloc + 2, true); + reallocate(o, dd->values.alloc + 2, true); dd = o->d()->arrayData.cast(); last = &dd->freeList; Q_ASSERT(Value::fromReturnedValue(*last).value() != UINT_MAX); } - Q_ASSERT(dd->arrayData[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value()); - if (dd->arrayData[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) { + Q_ASSERT(dd->values[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value()); + if (dd->values[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) { // found two slots in a row uint idx = Value::fromReturnedValue(*last).emptyValue(); Value lastV = Value::fromReturnedValue(*last); - lastV.setEmpty(dd->arrayData[lastV.emptyValue() + 1].value()); + lastV.setEmpty(dd->values[lastV.emptyValue() + 1].value()); *last = lastV.rawValue(); dd->attrs[idx] = Attr_Accessor; return idx; } - last = &dd->arrayData[Value::fromReturnedValue(*last).value()].rawValueRef(); + last = &dd->values[Value::fromReturnedValue(*last).value()].rawValueRef(); } } else { if (Value::fromReturnedValue(dd->freeList).value() == UINT_MAX) { - reallocate(o, dd->alloc + 1, false); + reallocate(o, dd->values.alloc + 1, false); dd = o->d()->arrayData.cast(); } uint idx = Value::fromReturnedValue(dd->freeList).value(); Q_ASSERT(idx != UINT_MAX); - dd->freeList = dd->arrayData[idx].asReturnedValue(); + dd->freeList = dd->values[idx].asReturnedValue(); Q_ASSERT(Value::fromReturnedValue(dd->freeList).isEmpty()); if (dd->attrs) dd->attrs[idx] = Attr_Data; @@ -421,7 +421,7 @@ ReturnedValue SparseArrayData::get(const Heap::ArrayData *d, uint index) index = s->mappedIndex(index); if (index == UINT_MAX) return Primitive::emptyValue().asReturnedValue(); - return s->arrayData[index].asReturnedValue(); + return s->values[index].asReturnedValue(); } bool SparseArrayData::put(Object *o, uint index, const Value &value) @@ -435,7 +435,7 @@ bool SparseArrayData::put(Object *o, uint index, const Value &value) if (n->value == UINT_MAX) n->value = allocate(o); s = o->d()->arrayData.cast(); - s->arrayData[n->value] = value; + s->values[n->value] = value; if (s->attrs) s->attrs[n->value] = Attr_Data; return true; @@ -450,7 +450,7 @@ bool SparseArrayData::del(Object *o, uint index) return true; uint pidx = n->value; - Q_ASSERT(!dd->arrayData[pidx].isEmpty()); + Q_ASSERT(!dd->values[pidx].isEmpty()); bool isAccessor = false; if (dd->attrs) { @@ -463,11 +463,11 @@ bool SparseArrayData::del(Object *o, uint index) if (isAccessor) { // free up both indices - dd->arrayData[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); - dd->arrayData[pidx].setEmpty(pidx + 1); + dd->values[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); + dd->values[pidx].setEmpty(pidx + 1); } else { Q_ASSERT(dd->type == Heap::ArrayData::Sparse); - dd->arrayData[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); + dd->values[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); } dd->freeList = Primitive::emptyValue(pidx).asReturnedValue(); @@ -496,10 +496,10 @@ void SparseArrayData::push_front(Object *o, const Value *values, uint n) { Heap::SparseArrayData *d = o->d()->arrayData.cast(); Q_ASSERT(!d->attrs); - for (int i = n - 1; i >= 0; --i) { + for (int i = static_cast(n) - 1; i >= 0; --i) { uint idx = allocate(o); d = o->d()->arrayData.cast(); - d->arrayData[idx] = values[i]; + d->values[idx] = values[i]; d->sparse->push_front(idx); } } @@ -511,7 +511,7 @@ ReturnedValue SparseArrayData::pop_front(Object *o) uint idx = d->sparse->pop_front(); ReturnedValue v; if (idx != UINT_MAX) { - v = d->arrayData[idx].asReturnedValue(); + v = d->values[idx].asReturnedValue(); free(o->arrayData(), idx); } else { v = Encode::undefined(); @@ -589,24 +589,24 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n) ScopedValue v(scope); for (const SparseArrayNode *it = os->sparse->begin(); it != os->sparse->end(); it = it->nextNode()) { - v = otherObj->getValue(os->arrayData[it->value], other->d()->attrs[it->value]); + v = otherObj->getValue(os->values[it->value], other->d()->attrs[it->value]); obj->arraySet(oldSize + it->key(), v); } } else { for (const SparseArrayNode *it = other->d()->sparse->begin(); it != os->sparse->end(); it = it->nextNode()) - obj->arraySet(oldSize + it->key(), os->arrayData[it->value]); + obj->arraySet(oldSize + it->key(), os->values[it->value]); } } else { Heap::SimpleArrayData *os = static_cast(other->d()); uint toCopy = n; uint chunk = toCopy; - if (chunk > os->alloc - os->offset) - chunk -= os->alloc - os->offset; - obj->arrayPut(oldSize, os->arrayData + os->offset, chunk); + if (chunk > os->values.alloc - os->offset) + chunk -= os->values.alloc - os->offset; + obj->arrayPut(oldSize, os->values.v + os->offset, chunk); toCopy -= chunk; if (toCopy) - obj->arrayPut(oldSize + chunk, os->arrayData, toCopy); + obj->arrayPut(oldSize + chunk, os->values.v, toCopy); } return oldSize + n; @@ -616,18 +616,18 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor) { if (!isAccessor && o->d()->arrayData->type != Heap::ArrayData::Sparse) { Heap::SimpleArrayData *d = o->d()->arrayData.cast(); - if (index < 0x1000 || index < d->len + (d->len >> 2)) { - if (index >= d->alloc) { + if (index < 0x1000 || index < d->values.size + (d->values.size >> 2)) { + if (index >= d->values.alloc) { o->arrayReserve(index + 1); d = o->d()->arrayData.cast(); } - if (index >= d->len) { + if (index >= d->values.size) { // mark possible hole in the array - for (uint i = d->len; i < index; ++i) + for (uint i = d->values.size; i < index; ++i) d->data(i) = Primitive::emptyValue(); - d->len = index + 1; + d->values.size = index + 1; } - d->arrayData[d->mappedIndex(index)] = *v; + d->values[d->mappedIndex(index)] = *v; return; } } @@ -638,9 +638,9 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor) if (n->value == UINT_MAX) n->value = SparseArrayData::allocate(o, isAccessor); s = o->d()->arrayData.cast(); - s->arrayData[n->value] = *v; + s->values[n->value] = *v; if (isAccessor) - s->arrayData[n->value + Object::SetterOffset] = v[Object::SetterOffset]; + s->values[n->value + Object::SetterOffset] = v[Object::SetterOffset]; } @@ -792,7 +792,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c ++i; } } - d->len = i; + d->values.size = i; if (len > i) len = i; if (n != sparse->sparse()->end()) { @@ -808,8 +808,8 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c } } else { Heap::SimpleArrayData *d = thisObject->d()->arrayData.cast(); - if (len > d->len) - len = d->len; + if (len > d->values.size) + len = d->values.size; // sort empty values to the end for (uint i = 0; i < len; i++) { @@ -830,7 +830,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c ArrayElementLessThan lessThan(engine, thisObject, comparefn); - Value *begin = thisObject->arrayData()->arrayData; + Value *begin = thisObject->arrayData()->values.v; sortHelper(begin, begin + len, *begin, lessThan); #ifdef CHECK_SPARSE_ARRAYS diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index 919bd84762..882f8d1f8d 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -98,21 +98,15 @@ struct ArrayDataData { Custom = 3 }; - uint alloc; Type type; + uint offset; PropertyAttributes *attrs; - union { - uint len; - ReturnedValue freeList; - }; - union { - uint offset; - SparseArray *sparse; - }; - Value arrayData[1]; + ReturnedValue freeList; + SparseArray *sparse; + ValueArray values; }; static Q_CONSTEXPR quint64 ArrayData_markTable = \ - (MarkFlagsForType::markFlags << (offsetof(ArrayDataData, arrayData) >> 2)) \ + (MarkFlagsForType::markFlags << (offsetof(ArrayDataData, values) >> 2)) \ << (sizeof(Base) >> 2) | QV4::Heap::Base::markTable; struct ArrayData : public Base, ArrayDataData { @@ -135,7 +129,7 @@ struct ArrayData : public Base, ArrayDataData { return get(i) == Primitive::emptyValue().asReturnedValue(); } - inline ReturnedValue length() const { + inline uint length() const { return vtable()->length(this); } @@ -143,17 +137,17 @@ struct ArrayData : public Base, ArrayDataData { V4_ASSERT_IS_TRIVIAL(ArrayData) struct SimpleArrayData : public ArrayData { - uint mappedIndex(uint index) const { return (index + offset) % alloc; } - Value data(uint index) const { return arrayData[mappedIndex(index)]; } - Value &data(uint index) { return arrayData[mappedIndex(index)]; } + uint mappedIndex(uint index) const { return (index + offset) % values.alloc; } + Value data(uint index) const { return values[mappedIndex(index)]; } + Value &data(uint index) { return values[mappedIndex(index)]; } Property *getProperty(uint index) { - if (index >= len) + if (index >= values.size) return 0; index = mappedIndex(index); - if (arrayData[index].isEmpty()) + if (values[index].isEmpty()) return 0; - return reinterpret_cast(arrayData + index); + return reinterpret_cast(values.v + index); } PropertyAttributes attributes(uint i) const { @@ -179,7 +173,7 @@ struct SparseArrayData : public ArrayData { SparseArrayNode *n = sparse->findNode(index); if (!n) return 0; - return reinterpret_cast(arrayData + n->value); + return reinterpret_cast(values.v + n->value); } PropertyAttributes attributes(uint i) const { @@ -200,15 +194,15 @@ struct Q_QML_EXPORT ArrayData : public Managed IsArrayData = true }; - uint alloc() const { return d()->alloc; } - uint &alloc() { return d()->alloc; } - void setAlloc(uint a) { d()->alloc = a; } + uint alloc() const { return d()->values.alloc; } + uint &alloc() { return d()->values.alloc; } + void setAlloc(uint a) { d()->values.alloc = a; } Type type() const { return d()->type; } void setType(Type t) { d()->type = t; } PropertyAttributes *attrs() const { return d()->attrs; } void setAttrs(PropertyAttributes *a) { d()->attrs = a; } - const Value *arrayData() const { return &d()->arrayData[0]; } - Value *arrayData() { return &d()->arrayData[0]; } + const Value *arrayData() const { return d()->values.v; } + Value *arrayData() { return d()->values.v; } const ArrayVTable *vtable() const { return d()->vtable(); } bool isSparse() const { return type() == Heap::ArrayData::Sparse; } @@ -251,8 +245,8 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData Value data(uint index) const { return d()->data(index); } Value &data(uint index) { return d()->data(index); } - uint &len() { return d()->len; } - uint len() const { return d()->len; } + uint &len() { return d()->values.size; } + uint len() const { return d()->values.size; } static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes); diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 759354f4e2..a2c19e1f2d 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -690,8 +690,8 @@ void ArrayPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallD } else { Q_ASSERT(instance->arrayType() == Heap::ArrayData::Simple || instance->arrayType() == Heap::ArrayData::Complex); Heap::SimpleArrayData *sa = instance->d()->arrayData.cast(); - if (len > sa->len) - len = sa->len; + if (len > sa->values.size) + len = sa->values.size; uint idx = fromIndex; while (idx < len) { value = sa->data(idx); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 39b433e5f9..19298f3803 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -600,11 +600,11 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int leng size_t size = sizeof(Heap::ArrayData) + (length-1)*sizeof(Value); Heap::SimpleArrayData *d = scope.engine->memoryManager->allocManaged(size); d->init(); - d->alloc = length; d->type = Heap::ArrayData::Simple; d->offset = 0; - d->len = length; - memcpy(&d->arrayData, values, length*sizeof(Value)); + d->values.alloc = length; + d->values.size = length; + memcpy(&d->values.v, values, length*sizeof(Value)); a->d()->arrayData = d; a->setArrayLengthUnchecked(length); } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index ae1a403ea1..94555a6679 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -302,7 +302,7 @@ void FunctionPrototype::method_apply(const BuiltinFunction *, Scope &scope, Call cData->args[i] = Primitive::undefinedValue(); } else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) { auto sad = static_cast(arr->arrayData()); - uint alen = sad ? sad->len : 0; + uint alen = sad ? sad->values.size : 0; if (alen > len) alen = len; for (uint i = 0; i < alen; ++i) @@ -345,7 +345,7 @@ void FunctionPrototype::method_bind(const BuiltinFunction *, Scope &scope, CallD Scoped boundArgs(scope, (Heap::MemberData *)0); if (callData->argc > 1) { boundArgs = MemberData::allocate(scope.engine, callData->argc - 1); - boundArgs->d()->size = callData->argc - 1; + boundArgs->d()->values.size = callData->argc - 1; memcpy(boundArgs->data(), callData->args + 1, (callData->argc - 1)*sizeof(Value)); } diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 0f4859f0fa..677f0ebea9 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -199,6 +199,7 @@ struct ScriptFunction; struct InternalClass; struct Property; struct Value; +struct ValueArray; struct Lookup; struct ArrayData; struct VTable; diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 52ed449664..f85ead1852 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -182,7 +182,7 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con Heap::Object *o = static_cast(b); if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) { Heap::SimpleArrayData *s = o->arrayData.cast(); - if (idx < s->len) + if (idx < s->values.size) if (!s->data(idx).isEmpty()) return s->data(idx).asReturnedValue(); } @@ -217,7 +217,7 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value & if (index.asArrayIndex(idx)) { if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { Heap::SimpleArrayData *s = o->d()->arrayData.cast(); - if (idx < s->len) { + if (idx < s->values.size) { s->data(idx) = value; return; } @@ -239,7 +239,7 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value Heap::Object *o = static_cast(b); if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) { Heap::SimpleArrayData *s = o->arrayData.cast(); - if (idx < s->len) { + if (idx < s->values.size) { s->data(idx) = v; return; } diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index 3a6d66a030..ce1c8b614e 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -47,15 +47,16 @@ DEFINE_MANAGED_VTABLE(MemberData); Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberData *old) { - Q_ASSERT(!old || old->size < n); + Q_ASSERT(!old || old->values.size < n); Q_ASSERT(n); size_t alloc = MemoryManager::align(sizeof(Heap::MemberData) + (n - 1)*sizeof(Value)); Heap::MemberData *m = e->memoryManager->allocManaged(alloc); if (old) - memcpy(m, old, sizeof(Heap::MemberData) + (old->size - 1)* sizeof(Value)); + memcpy(m, old, sizeof(Heap::MemberData) + (old->values.size - 1) * sizeof(Value)); else m->init(); - m->size = static_cast((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); + m->values.alloc = static_cast((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); + m->values.size = m->values.alloc; return m; } diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index c4e797ff8d..a531d3303f 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -60,8 +60,7 @@ namespace QV4 { namespace Heap { #define MemberDataMembers(class, Member) \ - Member(class, uint, size) \ - Member(class, ValueArray, data) + Member(class, ValueArray, values) DECLARE_HEAP_OBJECT(MemberData, Base) { DECLARE_MARK_TABLE(MemberData); @@ -74,10 +73,10 @@ struct MemberData : Managed { V4_MANAGED(MemberData, Managed) - Value &operator[] (uint idx) { return d()->data[idx]; } - const Value *data() const { return d()->data; } - Value *data() { return d()->data; } - inline uint size() const { return d()->size; } + Value &operator[] (uint idx) { return d()->values[idx]; } + const Value *data() const { return d()->values.v; } + Value *data() { return d()->values.v; } + inline uint size() const { return d()->values.size; } static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = 0); }; diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 095aa6b4da..7886dd24fa 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -62,7 +62,7 @@ void Object::setInternalClass(InternalClass *ic) { d()->internalClass = ic; bool hasMD = d()->memberData != nullptr; - if ((!hasMD && ic->size) || (hasMD && d()->memberData->size < ic->size)) + if ((!hasMD && ic->size) || (hasMD && d()->memberData->values.size < ic->size)) d()->memberData = MemberData::allocate(ic->engine, ic->size, d()->memberData); } @@ -582,7 +582,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint * int k = it->arrayNode->key(); uint pidx = it->arrayNode->value; Heap::SparseArrayData *sa = o->d()->arrayData.cast(); - Property *p = reinterpret_cast(sa->arrayData + pidx); + Property *p = reinterpret_cast(sa->values.v + pidx); it->arrayNode = it->arrayNode->nextNode(); PropertyAttributes a = sa->attrs ? sa->attrs[pidx] : Attr_Data; if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { @@ -597,7 +597,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint * it->arrayIndex = UINT_MAX; } // dense arrays - while (it->arrayIndex < o->d()->arrayData->len) { + while (it->arrayIndex < o->d()->arrayData->values.size) { Heap::SimpleArrayData *sa = o->d()->arrayData.cast(); Value &val = sa->data(it->arrayIndex); PropertyAttributes a = o->arrayData()->attributes(it->arrayIndex); @@ -1132,7 +1132,7 @@ void Object::copyArrayData(Object *other) ; } else { Q_ASSERT(!arrayData() && other->arrayData()); - ArrayData::realloc(this, other->d()->arrayData->type, other->d()->arrayData->alloc, false); + ArrayData::realloc(this, other->d()->arrayData->type, other->d()->arrayData->values.alloc, false); if (other->arrayType() == Heap::ArrayData::Sparse) { Heap::ArrayData *od = other->d()->arrayData; Heap::ArrayData *dd = d()->arrayData; @@ -1140,10 +1140,10 @@ void Object::copyArrayData(Object *other) dd->freeList = od->freeList; } else { Heap::ArrayData *dd = d()->arrayData; - dd->len = other->d()->arrayData->len; + dd->values.size = other->d()->arrayData->values.size; dd->offset = other->d()->arrayData->offset; } - memcpy(d()->arrayData->arrayData, other->d()->arrayData->arrayData, other->d()->arrayData->alloc*sizeof(Value)); + memcpy(d()->arrayData->values.v, other->d()->arrayData->values.v, other->d()->arrayData->values.alloc*sizeof(Value)); } setArrayLengthUnchecked(other->getLength()); } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index b0eec1adfc..2affcd1af9 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -78,8 +78,8 @@ DECLARE_HEAP_OBJECT(Object, Base) { void init() { Base::init(); } void destroy() { Base::destroy(); } - const Value *propertyData(uint index) const { return memberData->data + index; } - Value *propertyData(uint index) { return memberData->data + index; } + const Value *propertyData(uint index) const { return memberData->values.v + index; } + Value *propertyData(uint index) { return memberData->values.v + index; } }; } @@ -524,7 +524,7 @@ inline void Object::arraySet(uint index, const Property *p, PropertyAttributes a { // ### Clean up arrayCreate(); - if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->alloc)) { + if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->values.alloc)) { initSparseArray(); } else { arrayData()->vtable()->reallocate(this, index + 1, false); @@ -539,7 +539,7 @@ inline void Object::arraySet(uint index, const Property *p, PropertyAttributes a inline void Object::arraySet(uint index, const Value &value) { arrayCreate(); - if (index > 0x1000 && index > 2*d()->arrayData->alloc) { + if (index > 0x1000 && index > 2*d()->arrayData->values.alloc) { initSparseArray(); } ArrayData::insert(this, index, &value); diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index f650ffc7b1..2e72c0f13f 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -295,7 +295,7 @@ void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallDat if (o->arrayData()) { ArrayData::ensureAttributes(o); - for (uint i = 0; i < o->d()->arrayData->alloc; ++i) { + for (uint i = 0; i < o->d()->arrayData->values.alloc; ++i) { if (!o->arrayData()->isEmpty(i)) o->d()->arrayData->attrs[i].setConfigurable(false); } @@ -320,7 +320,7 @@ void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallD if (o->arrayData()) { ArrayData::ensureAttributes(o); - for (uint i = 0; i < o->arrayData()->alloc; ++i) { + for (uint i = 0; i < o->arrayData()->values.alloc; ++i) { if (!o->arrayData()->isEmpty(i)) o->arrayData()->attrs[i].setConfigurable(false); if (o->arrayData()->attrs[i].isData()) @@ -371,7 +371,7 @@ void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, Cal return; } - for (uint i = 0; i < o->arrayData()->alloc; ++i) { + for (uint i = 0; i < o->arrayData()->values.alloc; ++i) { if (!o->arrayData()->isEmpty(i)) if (o->arrayData()->attributes(i).isConfigurable()) { scope.result = Encode(false); @@ -411,7 +411,7 @@ void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, Cal return; } - for (uint i = 0; i < o->arrayData()->alloc; ++i) { + for (uint i = 0; i < o->arrayData()->values.alloc; ++i) { if (!o->arrayData()->isEmpty(i)) if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable()) { scope.result = Encode(false); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 6590054bf3..4459af0e66 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -643,7 +643,7 @@ void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, co if (idx < UINT_MAX) { if (o->arrayType() == Heap::ArrayData::Simple) { Heap::SimpleArrayData *s = static_cast(o->arrayData()); - if (s && idx < s->len && !s->data(idx).isEmpty()) { + if (s && idx < s->values.size && !s->data(idx).isEmpty()) { s->data(idx) = value; return; } diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 4ff0565f9b..6d25abba9a 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -708,6 +708,20 @@ inline unsigned int Value::toUInt32() const return (unsigned int)toInt32(); } +struct ValueArray { + uint size; + uint alloc; + Value v[1]; + + inline Value &operator[] (uint index) { + Q_ASSERT(index < alloc); + return v[index]; + } + inline const Value &operator[] (uint index) const { + Q_ASSERT(index < alloc); + return v[index]; + } +}; } diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index bb600c6c0f..259f221a86 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -733,7 +733,8 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nM memset(m, 0, memberSize); o->memberData = static_cast(m); o->memberData->setVtable(MemberData::staticVTable()); - o->memberData->size = static_cast((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); + o->memberData->values.alloc = static_cast((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); + o->memberData->values.size = o->memberData->values.alloc; o->memberData->init(); // qDebug() << " got" << o->memberData << o->memberData->size; } @@ -769,17 +770,9 @@ void MemoryManager::drainMarkStack(Value *markBase) case Mark_ValueArray: { Q_ASSERT(m == Mark_ValueArray); // qDebug() << "marking Value Array at offset" << hex << (mem - reinterpret_cast(h)); - uint size; - Value *v = reinterpret_cast(mem); - if (h->vtable() == QV4::MemberData::staticVTable()) { - size = static_cast(h)->size; - } else if (h->vtable()->isArrayData) { - size = static_cast(h)->alloc; - } else { - size = 0; - Q_ASSERT(false); - } - const Value *end = v + size; + ValueArray *a = reinterpret_cast(mem); + Value *v = a->v; + const Value *end = v + a->alloc; while (v < end) { v->mark(engine); ++v; diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index 90e7d9cb61..a987c3a200 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -277,8 +277,6 @@ template<> struct MarkFlagsForType { static const quint64 markFlags = Mark_Value; }; - -typedef Value ValueArray[1]; template<> struct MarkFlagsForType { static const quint64 markFlags = Mark_ValueArray; diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 490a4e19ab..2c3476f63a 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -329,7 +329,7 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, if (size) { QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, size); propertyAndMethodStorage.set(v4, data); - std::fill(data->data, data->data + data->size, QV4::Encode::undefined()); + std::fill(data->values.v, data->values.v + data->values.size, QV4::Encode::undefined()); } // Need JS wrapper to ensure properties/methods are marked. -- cgit v1.2.3 From 3a0bb11d730390ce9fd64932f58269cfbe8c378e Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 30 Jan 2017 11:59:58 +0100 Subject: Separate SimpleCallData and CallData SimpleCallData doesn't need any loca variables, so move it into a separate CallData Heap object. This also allows getting rid of the manual markObjects() implementation for CallContext. Change-Id: I9014eb2f815d3e2fe63a951a9d126c38e8aaa0a3 Reviewed-by: Simon Hausmann --- .../qmldbg_debugger/qv4datacollector.cpp | 14 +-- .../qmltooling/qmldbg_debugger/qv4datacollector.h | 4 +- .../qqmlnativedebugservice.cpp | 17 ++-- src/qml/jit/qv4assembler.cpp | 2 +- src/qml/jsruntime/qv4context.cpp | 110 ++++++++------------- src/qml/jsruntime/qv4context_p.h | 53 +++++----- src/qml/jsruntime/qv4engine.cpp | 2 +- src/qml/jsruntime/qv4function_p.h | 2 +- src/qml/jsruntime/qv4functionobject.cpp | 4 +- src/qml/jsruntime/qv4vme_moth.cpp | 8 +- src/qml/memory/qv4mm_p.h | 6 +- 11 files changed, 106 insertions(+), 116 deletions(-) (limited to 'src') diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index a4bad5618b..225a1fa27d 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -55,11 +55,11 @@ QT_BEGIN_NAMESPACE -QV4::CallContext *QV4DataCollector::findContext(int frame) +QV4::SimpleCallContext *QV4DataCollector::findContext(int frame) { QV4::ExecutionContext *ctx = engine()->currentContext; while (ctx) { - QV4::CallContext *cCtxt = ctx->asCallContext(); + QV4::SimpleCallContext *cCtxt = ctx->asSimpleCallContext(); if (cCtxt && cCtxt->d()->v4Function) { if (frame < 1) return cCtxt; @@ -71,7 +71,7 @@ QV4::CallContext *QV4DataCollector::findContext(int frame) return 0; } -QV4::Heap::CallContext *QV4DataCollector::findScope(QV4::ExecutionContext *ctxt, int scope) +QV4::Heap::SimpleCallContext *QV4DataCollector::findScope(QV4::ExecutionContext *ctxt, int scope) { if (!ctxt) return 0; @@ -81,7 +81,7 @@ QV4::Heap::CallContext *QV4DataCollector::findScope(QV4::ExecutionContext *ctxt, for (; scope > 0 && ctx; --scope) ctx = ctx->d()->outer; - return (ctx && ctx->d()) ? ctx->asCallContext()->d() : 0; + return (ctx && ctx->d()) ? ctx->asSimpleCallContext()->d() : 0; } QVector QV4DataCollector::getScopeTypes(int frame) @@ -89,7 +89,7 @@ QVector QV4DataCollector::getScopeType QVector types; QV4::Scope scope(engine()); - QV4::CallContext *sctxt = findContext(frame); + QV4::SimpleCallContext *sctxt = findContext(frame); if (!sctxt || sctxt->d()->type < QV4::Heap::ExecutionContext::Type_QmlContext) return types; @@ -310,7 +310,7 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int QV4::Scope scope(engine()); QV4::ScopedContext ctxt(scope, findContext(frameNr)); while (ctxt) { - if (QV4::CallContext *cCtxt = ctxt->asCallContext()) { + if (QV4::SimpleCallContext *cCtxt = ctxt->asSimpleCallContext()) { if (cCtxt->d()->activation) break; } @@ -318,7 +318,7 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int } if (ctxt) { - QV4::ScopedValue o(scope, ctxt->asCallContext()->d()->activation); + QV4::ScopedValue o(scope, ctxt->asSimpleCallContext()->d()->activation); frame[QLatin1String("receiver")] = toRef(collect(o)); } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h index fd6356f22e..09a0d683ba 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h @@ -58,11 +58,11 @@ public: typedef uint Ref; typedef QVector Refs; - static QV4::Heap::CallContext *findScope(QV4::ExecutionContext *ctxt, int scope); + static QV4::Heap::SimpleCallContext *findScope(QV4::ExecutionContext *ctxt, int scope); static int encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType); QVector getScopeTypes(int frame); - QV4::CallContext *findContext(int frame); + QV4::SimpleCallContext *findContext(int frame); QV4DataCollector(QV4::ExecutionEngine *engine); diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp index 7f842419e7..6cb1ab4051 100644 --- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp @@ -481,17 +481,20 @@ void NativeDebugger::handleVariables(QJsonObject *response, const QJsonObject &a QJsonArray output; QV4::Scope scope(engine); - if (QV4::CallContext *callContext = executionContext->asCallContext()) { + if (QV4::SimpleCallContext *callContext = executionContext->asSimpleCallContext()) { QV4::Value thisObject = callContext->thisObject(); collector.collect(&output, QString(), QStringLiteral("this"), thisObject); QV4::Identifier *const *variables = callContext->variables(); QV4::Identifier *const *formals = callContext->formals(); - for (unsigned i = 0, ei = callContext->variableCount(); i != ei; ++i) { - QString qName; - if (QV4::Identifier *name = variables[i]) - qName = name->string; - QV4::Value val = callContext->d()->locals[i]; - collector.collect(&output, QString(), qName, val); + if (callContext->d()->type == QV4::Heap::ExecutionContext::Type_CallContext) { + QV4::CallContext *ctx = static_cast(callContext); + for (unsigned i = 0, ei = ctx->variableCount(); i != ei; ++i) { + QString qName; + if (QV4::Identifier *name = variables[i]) + qName = name->string; + QV4::Value val = ctx->d()->locals[i]; + collector.collect(&output, QString(), qName, val); + } } for (unsigned i = 0, ei = callContext->formalCount(); i != ei; ++i) { QString qName; diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 0b3d0bd0cc..83baef8453 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -286,7 +286,7 @@ typename Assembler::Pointer Assembler: } break; case IR::ArgLocal::Local: case IR::ArgLocal::ScopedLocal: { - offset = qOffsetOf(CallContext::Data, locals) + al->index * sizeof(Value); + offset = qOffsetOf(CallContext::Data, locals.v) + al->index * sizeof(Value); } break; default: Q_UNREACHABLE(); diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 569523595c..ec11422c15 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -54,20 +54,19 @@ using namespace QV4; DEFINE_MANAGED_VTABLE(ExecutionContext); +DEFINE_MANAGED_VTABLE(SimpleCallContext); DEFINE_MANAGED_VTABLE(CallContext); DEFINE_MANAGED_VTABLE(WithContext); DEFINE_MANAGED_VTABLE(CatchContext); DEFINE_MANAGED_VTABLE(GlobalContext); -/* Function *f, int argc */ -#define requiredMemoryForExecutionContect(f, argc) \ - sizeof(CallContext::Data) - sizeof(Value) + \ - sizeof(Value) * (f->compiledFunction->nLocals + qMax((uint)argc, f->nFormals)) + sizeof(CallData) - Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData *callData) { - Heap::CallContext *c = d()->engine->memoryManager->allocManaged( - requiredMemoryForExecutionContect(function, callData->argc)); + uint localsAndFormals = function->compiledFunction->nLocals + qMax(static_cast(callData->argc), function->nFormals); + size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + \ + sizeof(Value) * (localsAndFormals) + sizeof(CallData) - sizeof(Value); + + Heap::CallContext *c = d()->engine->memoryManager->allocManaged(requiredMemory); c->init(d()->engine, Heap::ExecutionContext::Type_CallContext); c->v4Function = function; @@ -75,36 +74,25 @@ Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData c->strictMode = function->isStrict(); c->outer = this->d(); - c->activation = 0; - c->compilationUnit = function->compilationUnit; c->lookups = c->compilationUnit->runtimeLookups; c->constantTable = c->compilationUnit->constants; const CompiledData::Function *compiledFunction = function->compiledFunction; - int nLocals = compiledFunction->nLocals; + uint nLocals = compiledFunction->nLocals; + c->locals.size = nLocals; + c->locals.alloc = localsAndFormals; if (nLocals) - std::fill(c->locals, c->locals + nLocals, Primitive::undefinedValue()); + std::fill(c->locals.v, c->locals.v + nLocals, Primitive::undefinedValue()); - c->callData = reinterpret_cast(c->locals + nLocals); - ::memcpy(c->callData, callData, sizeof(CallData) + (callData->argc - 1) * sizeof(Value)); + c->callData = reinterpret_cast(c->locals.v + nLocals); + ::memcpy(c->callData, callData, sizeof(CallData) - sizeof(Value) + static_cast(callData->argc) * sizeof(Value)); if (callData->argc < static_cast(compiledFunction->nFormals)) std::fill(c->callData->args + c->callData->argc, c->callData->args + compiledFunction->nFormals, Primitive::undefinedValue()); return c; } -Heap::CallContext *Heap::CallContext::createSimpleContext(ExecutionEngine *v4) -{ - Heap::CallContext *ctxt = v4->memoryManager->allocSimpleCallContext(v4); - return ctxt; -} - -void Heap::CallContext::freeSimpleCallContext() -{ - engine->memoryManager->freeSimpleCallContext(); -} - Heap::WithContext *ExecutionContext::newWithContext(Heap::Object *with) { return d()->engine->memoryManager->alloc(d(), with); @@ -128,7 +116,7 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) switch (ctx->d()->type) { case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { - Heap::CallContext *c = static_cast(ctx->d()); + Heap::SimpleCallContext *c = static_cast(ctx->d()); if (!activation) { if (!c->activation) c->activation = scope.engine->newObject(); @@ -184,22 +172,22 @@ void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionV } -Identifier * const *CallContext::formals() const +Identifier * const *SimpleCallContext::formals() const { return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() : 0; } -unsigned int CallContext::formalCount() const +unsigned int SimpleCallContext::formalCount() const { return d()->v4Function ? d()->v4Function->nFormals : 0; } -Identifier * const *CallContext::variables() const +Identifier * const *SimpleCallContext::variables() const { return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() + d()->v4Function->nFormals : 0; } -unsigned int CallContext::variableCount() const +unsigned int SimpleCallContext::variableCount() const { return d()->v4Function ? d()->v4Function->compiledFunction->nLocals : 0; } @@ -234,7 +222,7 @@ bool ExecutionContext::deleteProperty(String *name) } case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { - Heap::CallContext *c = static_cast(ctx->d()); + Heap::SimpleCallContext *c = static_cast(ctx->d()); if (c->v4Function && (c->v4Function->needsActivation() || hasWith)) { uint index = c->v4Function->internalClass->find(name); if (index < UINT_MAX) @@ -257,30 +245,6 @@ bool ExecutionContext::deleteProperty(String *name) return true; } -bool CallContext::needsOwnArguments() const -{ - QV4::Function *f = d()->v4Function; - return (f && f->needsActivation()) || (argc() < (f ? static_cast(f->nFormals) : 0)); -} - -void CallContext::markObjects(Heap::Base *m, ExecutionEngine *engine) -{ - QV4::Heap::CallContext *ctx = static_cast(m); - - if (ctx->type == Heap::ExecutionContext::Type_CallContext) { - Q_ASSERT(ctx->v4Function); - ctx->callData->thisObject.mark(engine); - for (int arg = 0; arg < qMax(ctx->callData->argc, (int)ctx->v4Function->nFormals); ++arg) - ctx->callData->args[arg].mark(engine); - for (unsigned local = 0, lastLocal = ctx->v4Function->compiledFunction->nLocals; local < lastLocal; ++local) - ctx->locals[local].mark(engine); - if (ctx->activation) - ctx->activation->mark(engine); - if (ctx->function) - ctx->function->mark(engine); - } -} - // Do a standard call with this execution context as the outer scope void ExecutionContext::call(Scope &scope, CallData *callData, Function *function, const FunctionObject *f) { @@ -304,7 +268,7 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio ExecutionContextSaver ctxSaver(scope); - CallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext(scope.engine); + SimpleCallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext(scope.engine); ctx->strictMode = function->isStrict(); ctx->callData = callData; @@ -357,15 +321,16 @@ void ExecutionContext::setProperty(String *name, const Value &value) } case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { - Heap::CallContext *c = static_cast(ctx->d()); + Heap::SimpleCallContext *c = static_cast(ctx->d()); if (c->v4Function) { uint index = c->v4Function->internalClass->find(name); if (index < UINT_MAX) { if (index < c->v4Function->nFormals) { c->callData->args[c->v4Function->nFormals - index - 1] = value; } else { + Q_ASSERT(c->type = Heap::ExecutionContext::Type_CallContext); index -= c->v4Function->nFormals; - c->locals[index] = value; + static_cast(c)->locals[index] = value; } return; } @@ -438,13 +403,14 @@ ReturnedValue ExecutionContext::getProperty(String *name) } case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { - Heap::CallContext *c = static_cast(ctx->d()); + Heap::SimpleCallContext *c = static_cast(ctx->d()); if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { uint index = c->v4Function->internalClass->find(name); if (index < UINT_MAX) { if (index < c->v4Function->nFormals) return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); - return c->locals[index - c->v4Function->nFormals].asReturnedValue(); + Q_ASSERT(c->type = Heap::ExecutionContext::Type_CallContext); + return static_cast(c)->locals[index - c->v4Function->nFormals].asReturnedValue(); } } ScopedObject activation(scope, c->activation); @@ -454,9 +420,12 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (hasProperty) return v->asReturnedValue(); } - if (c->function && c->v4Function->isNamedExpression() - && name->equals(ScopedString(scope, c->v4Function->name()))) - return c->function->asReturnedValue(); + if (c->v4Function->isNamedExpression()) { + Q_ASSERT(c->type == Heap::CallContext::Type_CallContext); + Heap::CallContext *ctx = static_cast(c); + if (ctx->function && name->equals(ScopedString(scope, c->v4Function->name()))) + return ctx->function->asReturnedValue(); + } break; } case Heap::ExecutionContext::Type_QmlContext: { @@ -516,13 +485,15 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) } case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { - Heap::CallContext *c = static_cast(ctx->d()); + Heap::SimpleCallContext *c = static_cast(ctx->d()); if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { + Q_ASSERT(c->type == Heap::CallContext::Type_CallContext); + Heap::CallContext *ctx = static_cast(c); uint index = c->v4Function->internalClass->find(name); if (index < UINT_MAX) { if (index < c->v4Function->nFormals) return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); - return c->locals[index - c->v4Function->nFormals].asReturnedValue(); + return ctx->locals[index - c->v4Function->nFormals].asReturnedValue(); } } ScopedObject activation(scope, c->activation); @@ -532,9 +503,12 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) if (hasProperty) return v->asReturnedValue(); } - if (c->function && c->v4Function->isNamedExpression() - && name->equals(ScopedString(scope, c->v4Function->name()))) - return c->function->asReturnedValue(); + if (c->v4Function->isNamedExpression()) { + Q_ASSERT(c->type == Heap::CallContext::Type_CallContext); + Heap::CallContext *ctx = static_cast(c); + if (ctx->function && name->equals(ScopedString(scope, c->v4Function->name()))) + return ctx->function->asReturnedValue(); + } break; } case Heap::ExecutionContext::Type_QmlContext: { @@ -558,7 +532,7 @@ Function *ExecutionContext::getFunction() const Scope scope(d()->engine); ScopedContext it(scope, this->d()); for (; it; it = it->d()->outer) { - if (const CallContext *callCtx = it->asCallContext()) + if (const SimpleCallContext *callCtx = it->asSimpleCallContext()) return callCtx->d()->v4Function; else if (it->asCatchContext() || it->asWithContext()) continue; // look in the parent context for a FunctionObject diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 96cdb90db9..3d4a9ba1d7 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -68,6 +68,7 @@ struct Function; struct Function; struct Identifier; struct CallContext; +struct SimpleCallContext; struct CatchContext; struct WithContext; struct QmlContext; @@ -131,14 +132,12 @@ DECLARE_HEAP_OBJECT(ExecutionContext, Base) { }; V4_ASSERT_IS_TRIVIAL(ExecutionContext) -#define CallContextMembers(class, Member) \ - Member(class, Pointer, function) \ - Member(class, Pointer, activation) +#define SimpleCallContextMembers(class, Member) \ + Member(class, Pointer, activation) \ + Member(class, QV4::Function *, v4Function) -DECLARE_HEAP_OBJECT(CallContext, ExecutionContext) { - DECLARE_MARK_TABLE(CallContext); - static CallContext *createSimpleContext(ExecutionEngine *v4); - void freeSimpleCallContext(); +DECLARE_HEAP_OBJECT(SimpleCallContext, ExecutionContext) { + DECLARE_MARK_TABLE(SimpleCallContext); void init(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext) { @@ -147,10 +146,18 @@ DECLARE_HEAP_OBJECT(CallContext, ExecutionContext) { inline unsigned int formalParameterCount() const; - QV4::Function *v4Function; - Value locals[1]; }; -V4_ASSERT_IS_TRIVIAL(CallContext) +V4_ASSERT_IS_TRIVIAL(SimpleCallContext) + +#define CallContextMembers(class, Member) \ + Member(class, Pointer, function) \ + Member(class, ValueArray, locals) \ + +DECLARE_HEAP_OBJECT(CallContext, SimpleCallContext) { + DECLARE_MARK_TABLE(CallContext); + + using SimpleCallContext::formalParameterCount; +}; #define GlobalContextMembers(class, Member) \ Member(class, Pointer, global) @@ -217,8 +224,8 @@ struct Q_QML_EXPORT ExecutionContext : public Managed ReturnedValue getPropertyAndBase(String *name, Value *base); bool deleteProperty(String *name); - inline CallContext *asCallContext(); - inline const CallContext *asCallContext() const; + inline SimpleCallContext *asSimpleCallContext(); + inline const SimpleCallContext *asSimpleCallContext() const; inline const CatchContext *asCatchContext() const; inline const WithContext *asWithContext() const; @@ -241,9 +248,9 @@ struct Q_QML_EXPORT ExecutionContext : public Managed void simpleCall(Scope &scope, CallData *callData, QV4::Function *function); }; -struct Q_QML_EXPORT CallContext : public ExecutionContext +struct Q_QML_EXPORT SimpleCallContext : public ExecutionContext { - V4_MANAGED(CallContext, ExecutionContext) + V4_MANAGED(SimpleCallContext, ExecutionContext) // formals are in reverse order Identifier * const *formals() const; @@ -252,15 +259,17 @@ struct Q_QML_EXPORT CallContext : public ExecutionContext unsigned int variableCount() const; inline ReturnedValue argument(int i) const; - bool needsOwnArguments() const; - - static void markObjects(Heap::Base *m, ExecutionEngine *e); }; -inline ReturnedValue CallContext::argument(int i) const { +inline ReturnedValue SimpleCallContext::argument(int i) const { return i < argc() ? args()[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue(); } +struct Q_QML_EXPORT CallContext : public SimpleCallContext +{ + V4_MANAGED(CallContext, SimpleCallContext) +}; + struct GlobalContext : public ExecutionContext { V4_MANAGED(GlobalContext, ExecutionContext) @@ -277,14 +286,14 @@ struct WithContext : public ExecutionContext V4_MANAGED(WithContext, ExecutionContext) }; -inline CallContext *ExecutionContext::asCallContext() +inline SimpleCallContext *ExecutionContext::asSimpleCallContext() { - return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast(this) : 0; + return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast(this) : 0; } -inline const CallContext *ExecutionContext::asCallContext() const +inline const SimpleCallContext *ExecutionContext::asSimpleCallContext() const { - return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast(this) : 0; + return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast(this) : 0; } inline const CatchContext *ExecutionContext::asCatchContext() const diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 19298f3803..bc618e3e7a 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -886,7 +886,7 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) QUrl base; ExecutionContext *c = currentContext; while (c) { - CallContext *callCtx = c->asCallContext(); + SimpleCallContext *callCtx = c->asSimpleCallContext(); if (callCtx && callCtx->d()->v4Function) { base.setUrl(callCtx->d()->v4Function->sourceFile()); break; diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 54d0528c42..ff5febd19c 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -102,7 +102,7 @@ struct Q_QML_EXPORT Function { }; -inline unsigned int Heap::CallContext::formalParameterCount() const +inline unsigned int Heap::SimpleCallContext::formalParameterCount() const { return v4Function ? v4Function->nFormals : 0; } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 94555a6679..9afea01141 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -472,7 +472,7 @@ void OldBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callD ExecutionContextSaver ctxSaver(scope); - CallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4); + SimpleCallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4); ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context? ctx->callData = callData; v4->pushContext(ctx); @@ -519,7 +519,7 @@ void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *c ExecutionContextSaver ctxSaver(scope); - CallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4); + SimpleCallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4); ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context? ctx->callData = callData; v4->pushContext(ctx); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index be2772c23f..8afeb5b4da 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -410,10 +410,14 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code QV4::Heap::ExecutionContext *scope = context->d(); int i = 0; while (scope) { - if (scope->type >= QV4::Heap::ExecutionContext::Type_SimpleCallContext) { + if (scope->type == QV4::Heap::ExecutionContext::Type_SimpleCallContext) { + QV4::Heap::SimpleCallContext *cc = static_cast(scope); + scopes[2*i + 2] = cc->callData->args; + scopes[2*i + 3] = 0; + } else if (scope->type == QV4::Heap::ExecutionContext::Type_CallContext) { QV4::Heap::CallContext *cc = static_cast(scope); scopes[2*i + 2] = cc->callData->args; - scopes[2*i + 3] = cc->locals; + scopes[2*i + 3] = cc->locals.v; } else { scopes[2*i + 2] = 0; scopes[2*i + 3] = 0; diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 016879799a..0bd9229792 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -206,11 +206,11 @@ public: Q_DECL_CONSTEXPR static inline std::size_t align(std::size_t size) { return (size + Chunk::SlotSize - 1) & ~(Chunk::SlotSize - 1); } - QV4::Heap::CallContext *allocSimpleCallContext(QV4::ExecutionEngine *v4) + QV4::Heap::SimpleCallContext *allocSimpleCallContext(QV4::ExecutionEngine *v4) { Heap::CallContext *ctxt = stackAllocator.allocate(); - memset(ctxt, 0, sizeof(Heap::CallContext)); - ctxt->setVtable(QV4::CallContext::staticVTable()); + memset(ctxt, 0, sizeof(Heap::SimpleCallContext)); + ctxt->setVtable(QV4::SimpleCallContext::staticVTable()); ctxt->init(v4); return ctxt; -- cgit v1.2.3 From d8c195149c784e3cf11df681229bcf6defba9256 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 30 Jan 2017 12:00:23 +0100 Subject: Cleanup Property class Disable copying and remove some unused methods Change-Id: I2ae56f29260255e1ed759a4656e76ce4a30a2e89 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4property_p.h | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h index 5069d7690b..2a5b6f7f74 100644 --- a/src/qml/jsruntime/qv4property_p.h +++ b/src/qml/jsruntime/qv4property_p.h @@ -78,12 +78,6 @@ struct Property { attrs->resolve(); } - static Property genericDescriptor() { - Property pd; - pd.value = Primitive::emptyValue(); - return pd; - } - inline bool isSubset(const PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const; inline void merge(PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs); @@ -99,19 +93,12 @@ struct Property { } explicit Property() { value = Encode::undefined(); set = Value::fromHeapObject(0); } - explicit Property(Value v) : value(v) { set = Value::fromHeapObject(0); } - Property(FunctionObject *getter, FunctionObject *setter) { - value = reinterpret_cast(getter); - set = reinterpret_cast(setter); - } Property(Heap::FunctionObject *getter, Heap::FunctionObject *setter) { value.setM(reinterpret_cast(getter)); set.setM(reinterpret_cast(setter)); } - Property &operator=(Value v) { value = v; return *this; } private: - Property(const Property &); - Property &operator=(const Property &); + Q_DISABLE_COPY(Property) }; inline bool Property::isSubset(const PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const -- cgit v1.2.3 From 2fbb5c93c765ea53c3bd5f30b8bf769ccc88874a Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 30 Jan 2017 14:04:33 +0100 Subject: Always pass the ExecutionEngine into lookup calls This is required in preparation for proper write barriers, where we'll need to check the engine whether the barrier is enabled. It also makes the lookup calls more consistent, and doesn't affect performance in any measurable way. Change-Id: Ia838237a44ba809d4643e2626bc81560388276e2 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4compileddata.cpp | 2 -- src/qml/jit/qv4isel_masm.cpp | 2 ++ src/qml/jit/qv4isel_masm_p.h | 12 +++++++++--- src/qml/jsruntime/qv4lookup.cpp | 30 +++++++++++++++--------------- src/qml/jsruntime/qv4lookup_p.h | 17 ++++++++--------- src/qml/jsruntime/qv4vme_moth.cpp | 4 ++-- 6 files changed, 36 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index a8f065210b..c25a139379 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -174,8 +174,6 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) l->level = -1; l->index = UINT_MAX; l->nameIndex = compiledLookups[i].nameIndex; - if (type == CompiledData::Lookup::Type_IndexedGetter || type == CompiledData::Lookup::Type_IndexedSetter) - l->engine = engine; } } diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 69d6951bb9..6d3066aea1 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -621,6 +621,7 @@ void InstructionSelection::getElement(IR::Expr *base, IR::Expr *in if (useFastLookups) { uint lookup = registerIndexedGetterLookup(); generateLookupCall(target, lookup, qOffsetOf(QV4::Lookup, indexedGetter), + JITTargetPlatform::EngineRegister, PointerToValue(base), PointerToValue(index)); return; @@ -636,6 +637,7 @@ void InstructionSelection::setElement(IR::Expr *source, IR::Expr * if (useFastLookups) { uint lookup = registerIndexedSetterLookup(); generateLookupCall(JITAssembler::Void, lookup, qOffsetOf(QV4::Lookup, indexedSetter), + JITTargetPlatform::EngineRegister, PointerToValue(targetBase), PointerToValue(targetIndex), PointerToValue(source)); return; diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h index 5c046cb397..5764c3946e 100644 --- a/src/qml/jit/qv4isel_masm_p.h +++ b/src/qml/jit/qv4isel_masm_p.h @@ -260,8 +260,8 @@ private: void calculateRegistersToSave(const RegisterInformation &used); - template - void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3) + template + void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) { // Note: using the return value register is intentional: for ABIs where the first parameter // goes into the same register as the return value (currently only ARM), the prepareCall @@ -271,7 +271,7 @@ private: _as->generateFunctionCallImp(true, retval, "lookup getter/setter", typename JITAssembler::LookupCall(lookupAddr, getterSetterOffset), lookupAddr, - arg1, arg2, arg3); + arg1, arg2, arg3, arg4); } template @@ -280,6 +280,12 @@ private: generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, typename JITAssembler::VoidType()); } + template + void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3) + { + generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, arg3, typename JITAssembler::VoidType()); + } + IR::BasicBlock *_block; BitVector _removableJumps; JITAssembler* _as; diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index f85ead1852..bd677483b5 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -116,20 +116,20 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs return Primitive::emptyValue().asReturnedValue(); } -ReturnedValue Lookup::indexedGetterGeneric(Lookup *l, const Value &object, const Value &index) +ReturnedValue Lookup::indexedGetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index) { uint idx; if (object.isObject() && index.asArrayIndex(idx)) { l->indexedGetter = indexedGetterObjectInt; - return indexedGetterObjectInt(l, object, index); + return indexedGetterObjectInt(l, engine, object, index); } - return indexedGetterFallback(l, object, index); + return indexedGetterFallback(l, engine, object, index); } -ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, const Value &index) +ReturnedValue Lookup::indexedGetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index) { Q_UNUSED(l); - Scope scope(l->engine); + Scope scope(engine); uint idx = 0; bool isInt = index.asArrayIndex(idx); @@ -147,7 +147,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons if (object.isNullOrUndefined()) { QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index.toQStringNoThrow()).arg(object.toQStringNoThrow()); - return l->engine->throwTypeError(message); + return engine->throwTypeError(message); } o = RuntimeHelpers::convertToObject(scope.engine, object); @@ -173,7 +173,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons } -ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, const Value &index) +ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index) { uint idx; if (index.asArrayIndex(idx)) { @@ -190,25 +190,25 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con } } - return indexedGetterFallback(l, object, index); + return indexedGetterFallback(l, engine, object, index); } -void Lookup::indexedSetterGeneric(Lookup *l, const Value &object, const Value &index, const Value &v) +void Lookup::indexedSetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v) { if (Object *o = object.objectValue()) { uint idx; if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple && index.asArrayIndex(idx)) { l->indexedSetter = indexedSetterObjectInt; - indexedSetterObjectInt(l, object, index, v); + indexedSetterObjectInt(l, engine, object, index, v); return; } } - indexedSetterFallback(l, object, index, v); + indexedSetterFallback(l, engine, object, index, v); } -void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value &index, const Value &value) +void Lookup::indexedSetterFallback(Lookup *, ExecutionEngine *engine, const Value &object, const Value &index, const Value &value) { - Scope scope(l->engine); + Scope scope(engine); ScopedObject o(scope, object.toObject(scope.engine)); if (scope.engine->hasException) return; @@ -230,7 +230,7 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value & o->put(name, value); } -void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value &index, const Value &v) +void Lookup::indexedSetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v) { uint idx; if (index.asArrayIndex(idx)) { @@ -247,7 +247,7 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value } } } - indexedSetterFallback(l, object, index, v); + indexedSetterFallback(l, engine, object, index, v); } ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object) diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index c5ee92fedd..1b1c307530 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -67,14 +67,13 @@ namespace QV4 { struct Lookup { enum { Size = 4 }; union { - ReturnedValue (*indexedGetter)(Lookup *l, const Value &object, const Value &index); - void (*indexedSetter)(Lookup *l, const Value &object, const Value &index, const Value &v); + ReturnedValue (*indexedGetter)(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index); + void (*indexedSetter)(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v); ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object); ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine); void (*setter)(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v); }; union { - ExecutionEngine *engine; InternalClass *classList[Size]; struct { void *dummy0; @@ -90,13 +89,13 @@ struct Lookup { uint index; uint nameIndex; - static ReturnedValue indexedGetterGeneric(Lookup *l, const Value &object, const Value &index); - static ReturnedValue indexedGetterFallback(Lookup *l, const Value &object, const Value &index); - static ReturnedValue indexedGetterObjectInt(Lookup *l, const Value &object, const Value &index); + static ReturnedValue indexedGetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index); + static ReturnedValue indexedGetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index); + static ReturnedValue indexedGetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index); - static void indexedSetterGeneric(Lookup *l, const Value &object, const Value &index, const Value &v); - static void indexedSetterFallback(Lookup *l, const Value &object, const Value &index, const Value &value); - static void indexedSetterObjectInt(Lookup *l, const Value &object, const Value &index, const Value &v); + static void indexedSetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v); + static void indexedSetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &value); + static void indexedSetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v); static ReturnedValue getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 8afeb5b4da..73db76e105 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -484,7 +484,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(LoadElementLookup) QV4::Lookup *l = context->d()->lookups + instr.lookup; - STOREVALUE(instr.result, l->indexedGetter(l, VALUE(instr.base), VALUE(instr.index))); + STOREVALUE(instr.result, l->indexedGetter(l, engine, VALUE(instr.base), VALUE(instr.index))); MOTH_END_INSTR(LoadElementLookup) MOTH_BEGIN_INSTR(StoreElement) @@ -494,7 +494,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(StoreElementLookup) QV4::Lookup *l = context->d()->lookups + instr.lookup; - l->indexedSetter(l, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source)); + l->indexedSetter(l, engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source)); CHECK_EXCEPTION; MOTH_END_INSTR(StoreElementLookup) -- cgit v1.2.3 From 8b3cbc4403e3eac286613691c11aa1ded588da59 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 30 Jan 2017 22:22:00 +0100 Subject: Refactor how we define Heap objects Declare the type of Heap object in the Member() macro, instead of deducing it from templates. This allows us to encode the offset of the member in the second template argument to Pointer<> in a second step. Change-Id: I2cfb73785749d3fb991689b4e0554a72b3e5e13f Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4argumentsobject_p.h | 10 +++++----- src/qml/jsruntime/qv4arraydata_p.h | 33 ++++++++++++-------------------- src/qml/jsruntime/qv4context_p.h | 18 ++++++++--------- src/qml/jsruntime/qv4dataview_p.h | 6 +++--- src/qml/jsruntime/qv4errorobject_p.h | 2 +- src/qml/jsruntime/qv4functionobject_p.h | 10 +++++----- src/qml/jsruntime/qv4global_p.h | 5 +++-- src/qml/jsruntime/qv4memberdata_p.h | 2 +- src/qml/jsruntime/qv4object.cpp | 3 ++- src/qml/jsruntime/qv4object_p.h | 10 +++++----- src/qml/jsruntime/qv4qmlcontext_p.h | 2 +- src/qml/jsruntime/qv4qobjectwrapper_p.h | 8 ++++---- src/qml/jsruntime/qv4regexpobject_p.h | 12 ++++++------ src/qml/jsruntime/qv4stringobject_p.h | 2 +- src/qml/jsruntime/qv4typedarray_p.h | 10 +++++----- src/qml/jsruntime/qv4value_p.h | 1 + src/qml/memory/qv4heap_p.h | 13 +++++++------ src/qml/memory/qv4mm.cpp | 8 ++++---- src/qml/memory/qv4mmdefs_p.h | 29 ++++++++-------------------- src/qml/qml/qqmlcomponent.cpp | 10 +++++----- src/qml/qml/qqmlxmlhttprequest.cpp | 2 +- 21 files changed, 89 insertions(+), 107 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index f579afff14..46e1f884e8 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -60,7 +60,7 @@ namespace QV4 { namespace Heap { #define ArgumentsGetterFunctionMembers(class, Member) \ - Member(class, uint, index) + Member(class, NoMark, uint, index) DECLARE_HEAP_OBJECT(ArgumentsGetterFunction, FunctionObject) { DECLARE_MARK_TABLE(ArgumentsGetterFunction); @@ -68,7 +68,7 @@ DECLARE_HEAP_OBJECT(ArgumentsGetterFunction, FunctionObject) { }; #define ArgumentsSetterFunctionMembers(class, Member) \ - Member(class, uint, index) + Member(class, NoMark, uint, index) DECLARE_HEAP_OBJECT(ArgumentsSetterFunction, FunctionObject) { DECLARE_MARK_TABLE(ArgumentsSetterFunction); @@ -76,9 +76,9 @@ DECLARE_HEAP_OBJECT(ArgumentsSetterFunction, FunctionObject) { }; #define ArgumentsObjectMembers(class, Member) \ - Member(class, Pointer, context) \ - Member(class, Pointer, mappedArguments) \ - Member(class, bool, fullyCreated) + Member(class, Pointer, CallContext *, context) \ + Member(class, Pointer, MemberData *, mappedArguments) \ + Member(class, NoMark, bool, fullyCreated) DECLARE_HEAP_OBJECT(ArgumentsObject, Object) { DECLARE_MARK_TABLE(ArgumentsObject); diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index 882f8d1f8d..1ede463d6d 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -90,28 +90,19 @@ struct ArrayVTable namespace Heap { -struct ArrayDataData { - enum Type { - Simple = 0, - Complex = 1, - Sparse = 2, - Custom = 3 - }; - - Type type; - uint offset; - PropertyAttributes *attrs; - ReturnedValue freeList; - SparseArray *sparse; - ValueArray values; -}; -static Q_CONSTEXPR quint64 ArrayData_markTable = \ - (MarkFlagsForType::markFlags << (offsetof(ArrayDataData, values) >> 2)) \ - << (sizeof(Base) >> 2) | QV4::Heap::Base::markTable; - -struct ArrayData : public Base, ArrayDataData { +#define ArrayDataMembers(class, Member) \ + Member(class, NoMark, uint, type) \ + Member(class, NoMark, uint, offset) \ + Member(class, NoMark, PropertyAttributes *, attrs) \ + Member(class, NoMark, ReturnedValue, freeList) \ + Member(class, NoMark, SparseArray *, sparse) \ + Member(class, ValueArray, ValueArray, values) + +DECLARE_HEAP_OBJECT(ArrayData, Base) { DECLARE_MARK_TABLE(ArrayData); + enum Type { Simple = 0, Complex = 1, Sparse = 2, Custom = 3 }; + bool isSparse() const { return type == Sparse; } const ArrayVTable *vtable() const { return reinterpret_cast(Base::vtable()); } @@ -197,7 +188,7 @@ struct Q_QML_EXPORT ArrayData : public Managed uint alloc() const { return d()->values.alloc; } uint &alloc() { return d()->values.alloc; } void setAlloc(uint a) { d()->values.alloc = a; } - Type type() const { return d()->type; } + Type type() const { return static_cast(d()->type); } void setType(Type t) { d()->type = t; } PropertyAttributes *attrs() const { return d()->attrs; } void setAttrs(PropertyAttributes *a) { d()->attrs = a; } diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 3d4a9ba1d7..ccea1dbc80 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -97,7 +97,7 @@ namespace Heap { struct QmlContext; #define ExecutionContextMembers(class, Member) \ - Member(class, Pointer, outer) + Member(class, Pointer, ExecutionContext *, outer) DECLARE_HEAP_OBJECT(ExecutionContext, Base) { DECLARE_MARK_TABLE(ExecutionContext); @@ -133,8 +133,8 @@ DECLARE_HEAP_OBJECT(ExecutionContext, Base) { V4_ASSERT_IS_TRIVIAL(ExecutionContext) #define SimpleCallContextMembers(class, Member) \ - Member(class, Pointer, activation) \ - Member(class, QV4::Function *, v4Function) + Member(class, Pointer, Object *, activation) \ + Member(class, NoMark, QV4::Function *, v4Function) DECLARE_HEAP_OBJECT(SimpleCallContext, ExecutionContext) { DECLARE_MARK_TABLE(SimpleCallContext); @@ -150,8 +150,8 @@ DECLARE_HEAP_OBJECT(SimpleCallContext, ExecutionContext) { V4_ASSERT_IS_TRIVIAL(SimpleCallContext) #define CallContextMembers(class, Member) \ - Member(class, Pointer, function) \ - Member(class, ValueArray, locals) \ + Member(class, Pointer, FunctionObject *, function) \ + Member(class, ValueArray, ValueArray, locals) \ DECLARE_HEAP_OBJECT(CallContext, SimpleCallContext) { DECLARE_MARK_TABLE(CallContext); @@ -160,7 +160,7 @@ DECLARE_HEAP_OBJECT(CallContext, SimpleCallContext) { }; #define GlobalContextMembers(class, Member) \ - Member(class, Pointer, global) + Member(class, Pointer, Object *, global) DECLARE_HEAP_OBJECT(GlobalContext, ExecutionContext) { DECLARE_MARK_TABLE(GlobalContext); @@ -170,8 +170,8 @@ DECLARE_HEAP_OBJECT(GlobalContext, ExecutionContext) { V4_ASSERT_IS_TRIVIAL(GlobalContext) #define CatchContextMembers(class, Member) \ - Member(class, Pointer, exceptionVarName) \ - Member(class, Value, exceptionValue) + Member(class, Pointer, String *, exceptionVarName) \ + Member(class, Value, Value, exceptionValue) DECLARE_HEAP_OBJECT(CatchContext, ExecutionContext) { DECLARE_MARK_TABLE(CatchContext); @@ -181,7 +181,7 @@ DECLARE_HEAP_OBJECT(CatchContext, ExecutionContext) { V4_ASSERT_IS_TRIVIAL(CatchContext) #define WithContextMembers(class, Member) \ - Member(class, Pointer, withObject) + Member(class, Pointer, Object *, withObject) DECLARE_HEAP_OBJECT(WithContext, ExecutionContext) { DECLARE_MARK_TABLE(WithContext); diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h index f61a2a1780..5c50df4655 100644 --- a/src/qml/jsruntime/qv4dataview_p.h +++ b/src/qml/jsruntime/qv4dataview_p.h @@ -64,9 +64,9 @@ struct DataViewCtor : FunctionObject { }; #define DataViewMembers(class, Member) \ - Member(class, Pointer, buffer) \ - Member(class, uint, byteLength) \ - Member(class, uint, byteOffset) + Member(class, Pointer, ArrayBuffer *, buffer) \ + Member(class, NoMark, uint, byteLength) \ + Member(class, NoMark, uint, byteOffset) DECLARE_HEAP_OBJECT(DataView, Object) { DECLARE_MARK_TABLE(DataView); diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index a5af0b6ab6..5afd9efcba 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -64,7 +64,7 @@ namespace Heap { #define ErrorObjectMembers(class, Member) \ - Member(class, Pointer, stack) + Member(class, Pointer, String *, stack) DECLARE_HEAP_OBJECT(ErrorObject, Object) { DECLARE_MARK_TABLE(ErrorObject); diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 083ff4343b..1fc40e6ff6 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -66,8 +66,8 @@ struct BuiltinFunction; namespace Heap { #define FunctionObjectMembers(class, Member) \ - Member(class, Pointer, scope) \ - Member(class, Function *, function) + Member(class, Pointer, ExecutionContext *, scope) \ + Member(class, NoMark, Function *, function) DECLARE_HEAP_OBJECT(FunctionObject, Object) { DECLARE_MARK_TABLE(FunctionObject); @@ -122,9 +122,9 @@ struct ScriptFunction : FunctionObject { }; #define BoundFunctionMembers(class, Member) \ - Member(class, Pointer, target) \ - Member(class, Value, boundThis) \ - Member(class, Pointer, boundArgs) + Member(class, Pointer, FunctionObject *, target) \ + Member(class, Value, Value, boundThis) \ + Member(class, Pointer, MemberData *, boundArgs) DECLARE_HEAP_OBJECT(BoundFunction, FunctionObject) { DECLARE_MARK_TABLE(BoundFunction); diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 677f0ebea9..ea3e1d750e 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -184,7 +184,7 @@ namespace Heap { struct DataView; struct TypedArray; - template struct Pointer; + template struct Pointer; } class MemoryManager; @@ -199,10 +199,11 @@ struct ScriptFunction; struct InternalClass; struct Property; struct Value; -struct ValueArray; +template struct ValueArray; struct Lookup; struct ArrayData; struct VTable; +struct Function; struct BooleanObject; struct NumberObject; diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index a531d3303f..e486895754 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -60,7 +60,7 @@ namespace QV4 { namespace Heap { #define MemberDataMembers(class, Member) \ - Member(class, ValueArray, values) + Member(class, ValueArray, ValueArray, values) DECLARE_HEAP_OBJECT(MemberData, Base) { DECLARE_MARK_TABLE(MemberData); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 7886dd24fa..cb7ce03c5c 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -1132,7 +1132,8 @@ void Object::copyArrayData(Object *other) ; } else { Q_ASSERT(!arrayData() && other->arrayData()); - ArrayData::realloc(this, other->d()->arrayData->type, other->d()->arrayData->values.alloc, false); + ArrayData::realloc(this, static_cast(other->d()->arrayData->type), + other->d()->arrayData->values.alloc, false); if (other->arrayType() == Heap::ArrayData::Sparse) { Heap::ArrayData *od = other->d()->arrayData; Heap::ArrayData *dd = d()->arrayData; diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 2affcd1af9..5b43710c03 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -68,10 +68,10 @@ struct BuiltinFunction; namespace Heap { #define ObjectMembers(class, Member) \ - Member(class, InternalClass *, internalClass) \ - Member(class, Pointer, prototype) \ - Member(class, Pointer, memberData) \ - Member(class, Pointer, arrayData) + Member(class, NoMark, InternalClass *, internalClass) \ + Member(class, Pointer, Object *, prototype) \ + Member(class, Pointer, MemberData *, memberData) \ + Member(class, Pointer, ArrayData *, arrayData) DECLARE_HEAP_OBJECT(Object, Base) { DECLARE_MARK_TABLE(Object); @@ -299,7 +299,7 @@ public: void push_back(const Value &v); ArrayData::Type arrayType() const { - return arrayData() ? d()->arrayData->type : Heap::ArrayData::Simple; + return arrayData() ? static_cast(d()->arrayData->type) : Heap::ArrayData::Simple; } // ### remove me void setArrayType(ArrayData::Type t) { diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index 73100807ae..835c9236fe 100644 --- a/src/qml/jsruntime/qv4qmlcontext_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -78,7 +78,7 @@ struct QmlContextWrapper : Object { }; #define QmlContextMembers(class, Member) \ - Member(class, Pointer, qml) + Member(class, Pointer, QmlContextWrapper *, qml) DECLARE_HEAP_OBJECT(QmlContext, ExecutionContext) { DECLARE_MARK_TABLE(QmlContext); diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 002e1f2eb0..c031a40211 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -96,10 +96,10 @@ private: }; #define QObjectMethodMembers(class, Member) \ - Member(class, Pointer, valueTypeWrapper) \ - Member(class, QQmlQPointer, qObj) \ - Member(class, QQmlPropertyCache *, _propertyCache) \ - Member(class, int, index) + Member(class, Pointer, QQmlValueTypeWrapper *, valueTypeWrapper) \ + Member(class, NoMark, QQmlQPointer, qObj) \ + Member(class, NoMark, QQmlPropertyCache *, _propertyCache) \ + Member(class, NoMark, int, index) DECLARE_HEAP_OBJECT(QObjectMethod, FunctionObject) { DECLARE_MARK_TABLE(QObjectMethod); diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index 6726568eec..b429524b71 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -74,8 +74,8 @@ namespace QV4 { namespace Heap { #define RegExpObjectMembers(class, Member) \ - Member(class, Pointer, value) \ - Member(class, bool, global) + Member(class, Pointer, RegExp *, value) \ + Member(class, NoMark, bool, global) DECLARE_HEAP_OBJECT(RegExpObject, Object) { DECLARE_MARK_TABLE(RegExpObject); @@ -86,10 +86,10 @@ DECLARE_HEAP_OBJECT(RegExpObject, Object) { }; #define RegExpCtorMembers(class, Member) \ - Member(class, Value, lastMatch) \ - Member(class, Pointer, lastInput) \ - Member(class, int, lastMatchStart) \ - Member(class, int, lastMatchEnd) + Member(class, Value, Value, lastMatch) \ + Member(class, Pointer, String *, lastInput) \ + Member(class, NoMark, int, lastMatchStart) \ + Member(class, NoMark, int, lastMatchEnd) DECLARE_HEAP_OBJECT(RegExpCtor, FunctionObject) { DECLARE_MARK_TABLE(RegExpCtor); diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index ae9377abb4..5ccee3335e 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -61,7 +61,7 @@ namespace QV4 { namespace Heap { #define StringObjectMembers(class, Member) \ - Member(class, Pointer, string) + Member(class, Pointer, String *, string) DECLARE_HEAP_OBJECT(StringObject, Object) { DECLARE_MARK_TABLE(StringObject); diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index f6b302a396..96786c8231 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -73,11 +73,11 @@ struct TypedArrayOperations { namespace Heap { #define TypedArrayMembers(class, Member) \ - Member(class, Pointer, buffer) \ - Member(class, const TypedArrayOperations *, type) \ - Member(class, uint, byteLength) \ - Member(class, uint, byteOffset) \ - Member(class, uint, arrayType) + Member(class, Pointer, ArrayBuffer *, buffer) \ + Member(class, NoMark, const TypedArrayOperations *, type) \ + Member(class, NoMark, uint, byteLength) \ + Member(class, NoMark, uint, byteOffset) \ + Member(class, NoMark, uint, arrayType) DECLARE_HEAP_OBJECT(TypedArray, Object) { DECLARE_MARK_TABLE(TypedArray); diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 6d25abba9a..771d28dce8 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -708,6 +708,7 @@ inline unsigned int Value::toUInt32() const return (unsigned int)toInt32(); } +template struct ValueArray { uint size; uint alloc; diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index 28d39b7fb7..febe4e6446 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -164,19 +164,20 @@ struct Q_QML_EXPORT Base { }; V4_ASSERT_IS_TRIVIAL(Base) -template +template struct Pointer { - T *operator->() const { return ptr; } - operator T *() const { return ptr; } + T operator->() const { return ptr; } + operator T () const { return ptr; } - Pointer &operator =(T *t) { ptr = t; return *this; } + Pointer &operator =(T t) { ptr = t; return *this; } template Type *cast() { return static_cast(ptr); } - T *ptr; + T ptr; }; -V4_ASSERT_IS_TRIVIAL(Pointer) +typedef Pointer V4PointerCheck; +V4_ASSERT_IS_TRIVIAL(V4PointerCheck) } diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 259f221a86..89cf9caf9e 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -762,15 +762,15 @@ void MemoryManager::drainMarkStack(Value *markBase) break; case Mark_Pointer: { // qDebug() << "marking pointer at " << mem; - Heap::Pointer *p = reinterpret_cast *>(mem); - if (*p) - (*p)->mark(engine); + Heap::Base *p = reinterpret_cast(mem); + if (p) + p->mark(engine); break; } case Mark_ValueArray: { Q_ASSERT(m == Mark_ValueArray); // qDebug() << "marking Value Array at offset" << hex << (mem - reinterpret_cast(h)); - ValueArray *a = reinterpret_cast(mem); + ValueArray<0> *a = reinterpret_cast *>(mem); Value *v = a->v; const Value *end = v + a->alloc; while (v < end) { diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index a987c3a200..e4d5ce9da2 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -265,27 +265,16 @@ enum MarkFlags { Mark_ValueArray = 3 }; -template -struct MarkFlagsForType { - static const quint64 markFlags = Mark_NoMark; -}; -template -struct MarkFlagsForType> { - static const quint64 markFlags = Mark_Pointer; -}; -template<> -struct MarkFlagsForType { - static const quint64 markFlags = Mark_Value; -}; -template<> -struct MarkFlagsForType { - static const quint64 markFlags = Mark_ValueArray; -}; +#define HEAP_OBJECT_MEMBER_EXPANSION(c, gcType, type, name) \ + HEAP_OBJECT_MEMBER_EXPANSION_##gcType(c, type, name) -#define HEAP_OBJECT_MEMBER_EXPANSION(c, type, name) type name; +#define HEAP_OBJECT_MEMBER_EXPANSION_Pointer(c, type, name) Pointer name; +#define HEAP_OBJECT_MEMBER_EXPANSION_NoMark(c, type, name) type name; +#define HEAP_OBJECT_MEMBER_EXPANSION_Value(c, type, name) type name; +#define HEAP_OBJECT_MEMBER_EXPANSION_ValueArray(c, type, name) ValueArray<0> name; -#define HEAP_OBJECT_MARK_EXPANSION(class, type, name) \ - (MarkFlagsForType::markFlags << (offsetof(class, name) >> 2)) | +#define HEAP_OBJECT_MARK_EXPANSION(class, gcType, type, name) \ + (Mark_##gcType << (offsetof(class, name) >> 2)) | #define DECLARE_HEAP_OBJECT(name, base) \ struct name##Data { \ @@ -299,8 +288,6 @@ struct name : base, name##Data #define DECLARE_MARK_TABLE(class) static Q_CONSTEXPR quint64 markTable = class##_markTable - - } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 487846f610..79e52f3914 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1047,11 +1047,11 @@ namespace QV4 { namespace Heap { #define QmlIncubatorObjectMembers(class, Member) \ - Member(class, Value, valuemap) \ - Member(class, Value, statusChanged) \ - Member(class, Pointer, qmlContext) \ - Member(class, QQmlComponentIncubator *, incubator) \ - Member(class, QQmlQPointer, parent) + Member(class, Value, Value, valuemap) \ + Member(class, Value, Value, statusChanged) \ + Member(class, Pointer, QmlContext *, qmlContext) \ + Member(class, NoMark, QQmlComponentIncubator *, incubator) \ + Member(class, NoMark, QQmlQPointer, parent) DECLARE_HEAP_OBJECT(QmlIncubatorObject, Object) { DECLARE_MARK_TABLE(QmlIncubatorObject); diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 868120a2f6..502a693d5c 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -1598,7 +1598,7 @@ struct QQmlXMLHttpRequestWrapper : Object { }; #define QQmlXMLHttpRequestCtorMembers(class, Member) \ - Member(class, Pointer, proto) + Member(class, Pointer, Object *, proto) DECLARE_HEAP_OBJECT(QQmlXMLHttpRequestCtor, FunctionObject) { DECLARE_MARK_TABLE(QQmlXMLHttpRequestCtor); -- cgit v1.2.3 From 518e258d59adc976e2e8aa9a7f9ef36d8b8cdb66 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 31 Jan 2017 13:25:09 +0100 Subject: Make every member of a Heap object aware of its offset inside the object This will allow adding a write barrier to those fields with manageable effort. Change-Id: I7d06d7ffccbcefe66e2524c64c962353c91c2766 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4context_p.h | 2 +- src/qml/jsruntime/qv4functionobject_p.h | 2 +- src/qml/jsruntime/qv4global_p.h | 1 + src/qml/jsruntime/qv4object_p.h | 2 ++ src/qml/jsruntime/qv4regexpobject_p.h | 2 +- src/qml/jsruntime/qv4value_p.h | 5 ++++ src/qml/memory/qv4heap_p.h | 4 ++- src/qml/memory/qv4mm.cpp | 2 +- src/qml/memory/qv4mmdefs_p.h | 48 ++++++++++++++++++++++++++++----- src/qml/qml/qqmlcomponent.cpp | 4 +-- 10 files changed, 58 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index ccea1dbc80..f544821729 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -171,7 +171,7 @@ V4_ASSERT_IS_TRIVIAL(GlobalContext) #define CatchContextMembers(class, Member) \ Member(class, Pointer, String *, exceptionVarName) \ - Member(class, Value, Value, exceptionValue) + Member(class, HeapValue, HeapValue, exceptionValue) DECLARE_HEAP_OBJECT(CatchContext, ExecutionContext) { DECLARE_MARK_TABLE(CatchContext); diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 1fc40e6ff6..c7dac7d3e5 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -123,7 +123,7 @@ struct ScriptFunction : FunctionObject { #define BoundFunctionMembers(class, Member) \ Member(class, Pointer, FunctionObject *, target) \ - Member(class, Value, Value, boundThis) \ + Member(class, HeapValue, HeapValue, boundThis) \ Member(class, Pointer, MemberData *, boundArgs) DECLARE_HEAP_OBJECT(BoundFunction, FunctionObject) { diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index ea3e1d750e..cd8fb91f7a 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -199,6 +199,7 @@ struct ScriptFunction; struct InternalClass; struct Property; struct Value; +template struct HeapValue; template struct ValueArray; struct Lookup; struct ArrayData; diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 5b43710c03..63b132c2e6 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -82,6 +82,8 @@ DECLARE_HEAP_OBJECT(Object, Base) { Value *propertyData(uint index) { return memberData->values.v + index; } }; +Q_STATIC_ASSERT(Object::markTable == ((2 << 4) | (2 << 6) | (2 << 8))); + } #define V4_OBJECT(superClass) \ diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index b429524b71..c2eeb32b88 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -86,7 +86,7 @@ DECLARE_HEAP_OBJECT(RegExpObject, Object) { }; #define RegExpCtorMembers(class, Member) \ - Member(class, Value, Value, lastMatch) \ + Member(class, HeapValue, HeapValue, lastMatch) \ Member(class, Pointer, String *, lastInput) \ Member(class, NoMark, int, lastMatchStart) \ Member(class, NoMark, int, lastMatchEnd) diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 771d28dce8..3d7776b736 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -708,6 +708,11 @@ inline unsigned int Value::toUInt32() const return (unsigned int)toInt32(); } +template +struct HeapValue : Value { + HeapValue &operator = (const Value &other) { setRawValue(other.rawValue()); return *this; } +}; + template struct ValueArray { uint size; diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index febe4e6446..b3dfa407f8 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -164,8 +164,10 @@ struct Q_QML_EXPORT Base { }; V4_ASSERT_IS_TRIVIAL(Base) -template +template struct Pointer { + static Q_CONSTEXPR size_t offset = o; + static Q_CONSTEXPR quint64 markBits = Mark_Pointer << (o >> 2); T operator->() const { return ptr; } operator T () const { return ptr; } diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 89cf9caf9e..edd26cf982 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -762,7 +762,7 @@ void MemoryManager::drainMarkStack(Value *markBase) break; case Mark_Pointer: { // qDebug() << "marking pointer at " << mem; - Heap::Base *p = reinterpret_cast(mem); + Heap::Base *p = *reinterpret_cast(mem); if (p) p->mark(engine); break; diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index e4d5ce9da2..63e51f9742 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -265,24 +265,58 @@ enum MarkFlags { Mark_ValueArray = 3 }; +template +struct MarkFlagEvaluator { + static Q_CONSTEXPR quint64 value = 0; +}; +template +struct MarkFlagEvaluator> { + static Q_CONSTEXPR quint64 value = static_cast(Mark_Pointer) << (2*o / sizeof(quintptr)); +}; +template +struct MarkFlagEvaluator> { + static Q_CONSTEXPR quint64 value = static_cast(Mark_ValueArray) << (2*o / sizeof(quintptr)); +}; +template +struct MarkFlagEvaluator> { + static Q_CONSTEXPR quint64 value = static_cast(Mark_Value) << (2 *o / sizeof(quintptr)); +}; + +#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION(c, gcType, type, name) \ + HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_##gcType(c, type, name) + +#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_Pointer(c, type, name) Pointer name; +#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_NoMark(c, type, name) type name; +#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_HeapValue(c, type, name) HeapValue<0> name; +#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_ValueArray(c, type, name) ValueArray<0> name; + #define HEAP_OBJECT_MEMBER_EXPANSION(c, gcType, type, name) \ HEAP_OBJECT_MEMBER_EXPANSION_##gcType(c, type, name) -#define HEAP_OBJECT_MEMBER_EXPANSION_Pointer(c, type, name) Pointer name; -#define HEAP_OBJECT_MEMBER_EXPANSION_NoMark(c, type, name) type name; -#define HEAP_OBJECT_MEMBER_EXPANSION_Value(c, type, name) type name; -#define HEAP_OBJECT_MEMBER_EXPANSION_ValueArray(c, type, name) ValueArray<0> name; +#define HEAP_OBJECT_MEMBER_EXPANSION_Pointer(c, type, name) \ + Pointer name; +#define HEAP_OBJECT_MEMBER_EXPANSION_NoMark(c, type, name) \ + type name; +#define HEAP_OBJECT_MEMBER_EXPANSION_HeapValue(c, type, name) \ + HeapValue name; +#define HEAP_OBJECT_MEMBER_EXPANSION_ValueArray(c, type, name) \ + ValueArray name; #define HEAP_OBJECT_MARK_EXPANSION(class, gcType, type, name) \ - (Mark_##gcType << (offsetof(class, name) >> 2)) | + MarkFlagEvaluator::value | #define DECLARE_HEAP_OBJECT(name, base) \ +struct name##OffsetStruct { \ + name##Members(name, HEAP_OBJECT_OFFSET_MEMBER_EXPANSION) \ +}; \ +struct name##SizeStruct : base, name##OffsetStruct {}; \ struct name##Data { \ + static Q_CONSTEXPR size_t baseOffset = sizeof(name##SizeStruct) - sizeof(name##OffsetStruct); \ name##Members(name, HEAP_OBJECT_MEMBER_EXPANSION) \ }; \ -struct name##SizeStruct : base, name##Data {}; \ +Q_STATIC_ASSERT(sizeof(name##SizeStruct) == sizeof(name##Data) + name##Data::baseOffset); \ static Q_CONSTEXPR quint64 name##_markTable = \ - (name##Members(name##Data, HEAP_OBJECT_MARK_EXPANSION) 0) << (((sizeof(name##SizeStruct) - sizeof(name##Data)) >> 2) | QV4::Heap::base::markTable; \ + (name##Members(name##Data, HEAP_OBJECT_MARK_EXPANSION) 0) | QV4::Heap::base::markTable; \ \ struct name : base, name##Data diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 79e52f3914..c1a0637d00 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1047,8 +1047,8 @@ namespace QV4 { namespace Heap { #define QmlIncubatorObjectMembers(class, Member) \ - Member(class, Value, Value, valuemap) \ - Member(class, Value, Value, statusChanged) \ + Member(class, HeapValue, HeapValue, valuemap) \ + Member(class, HeapValue, HeapValue, statusChanged) \ Member(class, Pointer, QmlContext *, qmlContext) \ Member(class, NoMark, QQmlComponentIncubator *, incubator) \ Member(class, NoMark, QQmlQPointer, parent) -- cgit v1.2.3 From 91714e004e0c91527e7049ff43565dda682fc2bd Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 31 Jan 2017 14:03:51 +0100 Subject: Make all write operations to Pointer<> types go through a set() method The new set() method also taked an ExecutionEngine pointer. This makes it trivial to now add a write barrier for those operations. Change-Id: I321eccfe6fb279cc240b5c84910e6854f71759f6 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4argumentsobject.cpp | 7 ++++--- src/qml/jsruntime/qv4context.cpp | 14 +++++++------- src/qml/jsruntime/qv4context_p.h | 4 ++-- src/qml/jsruntime/qv4dataview.cpp | 2 +- src/qml/jsruntime/qv4engine.cpp | 4 ++-- src/qml/jsruntime/qv4errorobject.cpp | 2 +- src/qml/jsruntime/qv4functionobject.cpp | 14 +++++++------- src/qml/jsruntime/qv4object.cpp | 4 ++-- src/qml/jsruntime/qv4object_p.h | 2 +- src/qml/jsruntime/qv4qmlcontext.cpp | 4 ++-- src/qml/jsruntime/qv4qobjectwrapper.cpp | 2 +- src/qml/jsruntime/qv4regexpobject.cpp | 15 ++++++++------- src/qml/jsruntime/qv4stringobject.cpp | 4 ++-- src/qml/jsruntime/qv4typedarray.cpp | 16 ++++++++-------- src/qml/memory/qv4heap_p.h | 7 +++++-- src/qml/memory/qv4mm.cpp | 2 +- src/qml/memory/qv4mm_p.h | 12 ++++++------ src/qml/qml/qqmlcomponent.cpp | 4 ++-- src/qml/qml/qqmlxmlhttprequest.cpp | 2 +- 19 files changed, 63 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 33cda59b72..bc832c3349 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -48,12 +48,13 @@ DEFINE_OBJECT_VTABLE(ArgumentsObject); void Heap::ArgumentsObject::init(QV4::CallContext *context) { + ExecutionEngine *v4 = context->d()->engine; + Object::init(); fullyCreated = false; - this->context = context->d(); + this->context.set(v4, context->d()); Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable()); - ExecutionEngine *v4 = context->d()->engine; Scope scope(v4); Scoped args(scope, this); @@ -89,7 +90,7 @@ void ArgumentsObject::fullyCreate() Scope scope(engine()); Scoped md(scope, d()->mappedArguments); if (numAccessors) { - d()->mappedArguments = md->allocate(engine(), numAccessors); + d()->mappedArguments.set(scope.engine, md->allocate(engine(), numAccessors)); for (uint i = 0; i < numAccessors; ++i) { d()->mappedArguments->values[i] = context()->callData->args[i]; arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor); diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index ec11422c15..3918d25326 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -72,7 +72,7 @@ Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData c->v4Function = function; c->strictMode = function->isStrict(); - c->outer = this->d(); + c->outer.set(d()->engine, this->d()); c->compilationUnit = function->compilationUnit; c->lookups = c->compilationUnit->runtimeLookups; @@ -119,7 +119,7 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) Heap::SimpleCallContext *c = static_cast(ctx->d()); if (!activation) { if (!c->activation) - c->activation = scope.engine->newObject(); + c->activation.set(scope.engine, scope.engine->newObject()); activation = c->activation; } break; @@ -153,21 +153,21 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) void Heap::GlobalContext::init(ExecutionEngine *eng) { Heap::ExecutionContext::init(eng, Heap::ExecutionContext::Type_GlobalContext); - global = eng->globalObject->d(); + global.set(eng, eng->globalObject->d()); } void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue) { Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_CatchContext); - outer = outerContext; + outer.set(engine, outerContext); strictMode = outer->strictMode; callData = outer->callData; lookups = outer->lookups; constantTable = outer->constantTable; compilationUnit = outer->compilationUnit; - this->exceptionVarName = exceptionVarName; + this->exceptionVarName.set(engine, exceptionVarName); this->exceptionValue = exceptionValue; } @@ -252,7 +252,7 @@ void ExecutionContext::call(Scope &scope, CallData *callData, Function *function Scoped ctx(scope, newCallContext(function, callData)); if (f) - ctx->d()->function = f->d(); + ctx->d()->function.set(scope.engine, f->d()); scope.engine->pushContext(ctx); scope.result = Q_V4_PROFILE(scope.engine, function); @@ -276,7 +276,7 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio ctx->compilationUnit = function->compilationUnit; ctx->lookups = function->compilationUnit->runtimeLookups; ctx->constantTable = function->compilationUnit->constants; - ctx->outer = this->d(); + ctx->outer.set(scope.engine, this->d()); for (int i = callData->argc; i < (int)function->nFormals; ++i) callData->args[i] = Encode::undefined(); diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index f544821729..a405da0f57 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -189,13 +189,13 @@ DECLARE_HEAP_OBJECT(WithContext, ExecutionContext) { void init(ExecutionContext *outerContext, Object *with) { Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_WithContext); - outer = outerContext; + outer.set(engine, outerContext); callData = outer->callData; lookups = outer->lookups; constantTable = outer->constantTable; compilationUnit = outer->compilationUnit; - withObject = with; + withObject.set(engine, with); } }; V4_ASSERT_IS_TRIVIAL(WithContext) diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp index aa7d01d16c..f1405e08ee 100644 --- a/src/qml/jsruntime/qv4dataview.cpp +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -73,7 +73,7 @@ void DataViewCtor::construct(const Managed *, Scope &scope, CallData *callData) } Scoped a(scope, scope.engine->memoryManager->allocObject()); - a->d()->buffer = buffer->d(); + a->d()->buffer.set(scope.engine, buffer->d()); a->d()->byteLength = byteLength; a->d()->byteOffset = byteOffset; scope.result = a.asReturnedValue(); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index bc618e3e7a..f38580e5f8 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -398,7 +398,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) // // set up the global object // - rootContext()->d()->global = globalObject->d(); + rootContext()->d()->global.set(scope.engine, globalObject->d()); rootContext()->d()->callData->thisObject = globalObject; Q_ASSERT(globalObject->d()->vtable()); @@ -605,7 +605,7 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int leng d->values.alloc = length; d->values.size = length; memcpy(&d->values.v, values, length*sizeof(Value)); - a->d()->arrayData = d; + a->d()->arrayData.set(this, d); a->setArrayLengthUnchecked(length); } return a->d(); diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index 798a14086d..daa4f2d9a6 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -168,7 +168,7 @@ void ErrorObject::method_get_stack(const BuiltinFunction *, Scope &scope, CallDa if (frame.line >= 0) trace += QLatin1Char(':') + QString::number(frame.line); } - This->d()->stack = scope.engine->newString(trace); + This->d()->stack.set(scope.engine, scope.engine->newString(trace)); } scope.result = This->d()->stack; } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 9afea01141..a2433e7471 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -75,7 +75,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, { Object::init(); function = nullptr; - this->scope = scope->d(); + this->scope.set(scope->engine(), scope->d()); Scope s(scope->engine()); ScopedFunctionObject f(s, this); f->init(name, createProto); @@ -86,7 +86,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function Object::init(); this->function = function; function->compilationUnit->addref(); - this->scope = scope->d(); + this->scope.set(scope->engine(), scope->d()); Scope s(scope->engine()); ScopedString name(s, function->name()); ScopedFunctionObject f(s, this); @@ -104,7 +104,7 @@ void Heap::FunctionObject::init() { Object::init(); function = nullptr; - this->scope = internalClass->engine->rootContext()->d(); + this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d()); Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()) == Index_Prototype); *propertyData(Index_Prototype) = Encode::undefined(); } @@ -413,7 +413,7 @@ void ScriptFunction::call(const Managed *that, Scope &scope, CallData *callData) void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function) { FunctionObject::init(); - this->scope = scope->d(); + this->scope.set(scope->engine(), scope->d()); this->function = function; function->compilationUnit->addref(); @@ -536,12 +536,12 @@ DEFINE_OBJECT_VTABLE(BoundFunction); void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs) { + Scope s(scope); Heap::FunctionObject::init(scope, QStringLiteral("__bound function__")); - this->target = target->d(); - this->boundArgs = boundArgs ? boundArgs->d() : 0; + this->target.set(s.engine, target->d()); + this->boundArgs.set(s.engine, boundArgs ? boundArgs->d() : 0); this->boundThis = boundThis; - Scope s(scope); ScopedObject f(s, this); ScopedValue l(s, target->get(s.engine->id_length())); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index cb7ce03c5c..006615e580 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -63,7 +63,7 @@ void Object::setInternalClass(InternalClass *ic) d()->internalClass = ic; bool hasMD = d()->memberData != nullptr; if ((!hasMD && ic->size) || (hasMD && d()->memberData->values.size < ic->size)) - d()->memberData = MemberData::allocate(ic->engine, ic->size, d()->memberData); + d()->memberData.set(engine(), MemberData::allocate(ic->engine, ic->size, d()->memberData)); } void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) const @@ -89,7 +89,7 @@ bool Object::setPrototype(Object *proto) return false; pp = pp->prototype; } - d()->prototype = proto ? proto->d() : 0; + d()->prototype.set(engine(), proto ? proto->d() : 0); return true; } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 63b132c2e6..df987c88f9 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -198,7 +198,7 @@ struct Q_QML_EXPORT Object: Managed { Value *propertyData(uint index) { return d()->propertyData(index); } Heap::ArrayData *arrayData() const { return d()->arrayData; } - void setArrayData(ArrayData *a) { d()->arrayData = a->d(); } + void setArrayData(ArrayData *a) { d()->arrayData.set(engine(), a->d()); } void getProperty(uint index, Property *p, PropertyAttributes *attrs) const; void setProperty(uint index, const Property *p); diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index cdc29c8b9c..56ecc9f682 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -298,14 +298,14 @@ bool QmlContextWrapper::put(Managed *m, String *name, const Value &value) void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml) { Heap::ExecutionContext::init(outerContext->engine(), Heap::ExecutionContext::Type_QmlContext); - outer = outerContext->d(); + outer.set(engine, outerContext->d()); strictMode = false; callData = outer->callData; lookups = outer->lookups; constantTable = outer->constantTable; compilationUnit = outer->compilationUnit; - this->qml = qml->d(); + this->qml.set(engine, qml->d()); } Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, const QUrl &source, Value *sendFunction) diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index deea893632..4f6c179026 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -1704,7 +1704,7 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueType Scoped method(valueScope, valueScope.engine->memoryManager->allocObject(scope)); method->d()->setPropertyCache(valueType->d()->propertyCache()); method->d()->index = index; - method->d()->valueTypeWrapper = valueType->d(); + method->d()->valueTypeWrapper.set(valueScope.engine, valueType->d()); return method.asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index ca893839ef..3ec24edb5d 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -74,7 +74,7 @@ void Heap::RegExpObject::init() Object::init(); Scope scope(internalClass->engine); Scoped o(scope, this); - o->d()->value = QV4::RegExp::create(scope.engine, QString(), false, false); + o->d()->value.set(scope.engine, QV4::RegExp::create(scope.engine, QString(), false, false)); o->d()->global = false; o->initProperties(); } @@ -82,9 +82,9 @@ void Heap::RegExpObject::init() void Heap::RegExpObject::init(QV4::RegExp *value, bool global) { Object::init(); - this->global = global; - this->value = value->d(); Scope scope(internalClass->engine); + this->global = global; + this->value.set(scope.engine, value->d()); Scoped o(scope, this); o->initProperties(); } @@ -137,7 +137,8 @@ void Heap::RegExpObject::init(const QRegExp &re) Scope scope(internalClass->engine); Scoped o(scope, this); - o->d()->value = QV4::RegExp::create(scope.engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false); + o->d()->value.set(scope.engine, + QV4::RegExp::create(scope.engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false)); o->initProperties(); } @@ -220,7 +221,7 @@ void Heap::RegExpCtor::init(QV4::ExecutionContext *scope) void Heap::RegExpCtor::clearLastMatch() { lastMatch = Primitive::nullValue(); - lastInput = internalClass->engine->id_empty()->d(); + lastInput.set(internalClass->engine, internalClass->engine->id_empty()->d()); lastMatchStart = 0; lastMatchEnd = 0; } @@ -377,7 +378,7 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat RegExpCtor::Data *dd = regExpCtor->d(); dd->lastMatch = array; - dd->lastInput = str->d(); + dd->lastInput.set(scope.engine, str->d()); dd->lastMatchStart = matchOffsets[0]; dd->lastMatchEnd = matchOffsets[1]; @@ -414,7 +415,7 @@ void RegExpPrototype::method_compile(const BuiltinFunction *, Scope &scope, Call scope.engine->regExpCtor()->as()->construct(scope, cData); Scoped re(scope, scope.result.asReturnedValue()); - r->d()->value = re->value(); + r->d()->value.set(scope.engine, re->value()); r->d()->global = re->global(); RETURN_UNDEFINED(); } diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index c6cc5a4639..628c220bae 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -77,14 +77,14 @@ void Heap::StringObject::init() { Object::init(); Q_ASSERT(vtable() == QV4::StringObject::staticVTable()); - string = internalClass->engine->id_empty()->d(); + string.set(internalClass->engine, internalClass->engine->id_empty()->d()); *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0); } void Heap::StringObject::init(const QV4::String *str) { Object::init(); - string = str->d(); + string.set(internalClass->engine, str->d()); *propertyData(LengthPropertyIndex) = Primitive::fromInt32(length()); } diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index e936158ab1..a34a8922e1 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -229,8 +229,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat return; } - Scoped array(scope, TypedArray::create(scope.engine, that->d()->type)); - array->d()->buffer = buffer->d(); + Scoped array(scope, TypedArray::create(scope.engine, that->d()->type)); + array->d()->buffer.set(scope.engine, buffer->d()); array->d()->byteLength = byteLength; array->d()->byteOffset = 0; @@ -252,8 +252,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat return; } - Scoped array(scope, TypedArray::create(scope.engine, that->d()->type)); - array->d()->buffer = newBuffer->d(); + Scoped array(scope, TypedArray::create(scope.engine, that->d()->type)); + array->d()->buffer.set(scope.engine, newBuffer->d()); array->d()->byteLength = destByteLength; array->d()->byteOffset = 0; @@ -311,8 +311,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat byteLength = (uint)l; } - Scoped array(scope, TypedArray::create(scope.engine, that->d()->type)); - array->d()->buffer = buffer->d(); + Scoped array(scope, TypedArray::create(scope.engine, that->d()->type)); + array->d()->buffer.set(scope.engine, buffer->d()); array->d()->byteLength = byteLength; array->d()->byteOffset = byteOffset; scope.result = array.asReturnedValue(); @@ -335,8 +335,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat return; } - Scoped array(scope, TypedArray::create(scope.engine, that->d()->type)); - array->d()->buffer = newBuffer->d(); + Scoped array(scope, TypedArray::create(scope.engine, that->d()->type)); + array->d()->buffer.set(scope.engine, newBuffer->d()); array->d()->byteLength = l * elementSize; array->d()->byteOffset = 0; diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index b3dfa407f8..2cf3e721f9 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -167,15 +167,18 @@ V4_ASSERT_IS_TRIVIAL(Base) template struct Pointer { static Q_CONSTEXPR size_t offset = o; - static Q_CONSTEXPR quint64 markBits = Mark_Pointer << (o >> 2); T operator->() const { return ptr; } operator T () const { return ptr; } - Pointer &operator =(T t) { ptr = t; return *this; } + void set(ExecutionEngine *e, T newVal) { + Q_UNUSED(e); + ptr = newVal; + } template Type *cast() { return static_cast(ptr); } +private: T ptr; }; typedef Pointer V4PointerCheck; diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index edd26cf982..39272850b4 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -731,7 +731,7 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nM else m = *blockAllocator.allocate(memberSize, true); memset(m, 0, memberSize); - o->memberData = static_cast(m); + o->memberData.set(engine, static_cast(m)); o->memberData->setVtable(MemberData::staticVTable()); o->memberData->values.alloc = static_cast((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); o->memberData->values.size = o->memberData->values.alloc; diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 0bd9229792..6e9303acb6 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -245,7 +245,7 @@ public: o->setVtable(ObjectType::staticVTable()); Object *prototype = ObjectType::defaultPrototype(engine); o->internalClass = ic; - o->prototype = prototype->d(); + o->prototype.set(engine, prototype->d()); return static_cast(o); } @@ -272,7 +272,7 @@ public: { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->prototype = prototype->d(); + t->d_unchecked()->prototype.set(engine, prototype->d()); t->d_unchecked()->init(); return t->d(); } @@ -282,7 +282,7 @@ public: { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->prototype = prototype->d(); + t->d_unchecked()->prototype.set(engine, prototype->d()); t->d_unchecked()->init(arg1); return t->d(); } @@ -292,7 +292,7 @@ public: { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->prototype = prototype->d(); + t->d_unchecked()->prototype.set(engine, prototype->d()); t->d_unchecked()->init(arg1, arg2); return t->d(); } @@ -302,7 +302,7 @@ public: { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->prototype = prototype->d(); + t->d_unchecked()->prototype.set(engine, prototype->d()); t->d_unchecked()->init(arg1, arg2, arg3); return t->d(); } @@ -312,7 +312,7 @@ public: { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->prototype = prototype->d(); + t->d_unchecked()->prototype.set(engine, prototype->d()); t->d_unchecked()->init(arg1, arg2, arg3, arg4); return t->d(); } diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index c1a0637d00..993ad10639 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1377,7 +1377,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) if (!valuemap->isUndefined()) r->d()->valuemap = valuemap; - r->d()->qmlContext = v4->qmlContext(); + r->d()->qmlContext.set(scope.engine, v4->qmlContext()); r->d()->parent = parent; QQmlIncubator *incubator = r->d()->incubator; @@ -1476,7 +1476,7 @@ void QV4::Heap::QmlIncubatorObject::init(QQmlIncubator::IncubationMode m) valuemap = QV4::Primitive::undefinedValue(); statusChanged = QV4::Primitive::undefinedValue(); parent.init(); - qmlContext = nullptr; + qmlContext.set(internalClass->engine, nullptr); incubator = new QQmlComponentIncubator(this, m); } diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 502a693d5c..b18904fc73 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -1683,7 +1683,7 @@ void QQmlXMLHttpRequestCtor::setupProto() ExecutionEngine *v4 = engine(); Scope scope(v4); ScopedObject p(scope, v4->newObject()); - d()->proto = p->d(); + d()->proto.set(scope.engine, p->d()); // Methods p->defineDefaultProperty(QStringLiteral("open"), method_open); -- cgit v1.2.3 From 9242e5a685695356b2c9101a5e1642a726a6fede Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 31 Jan 2017 15:00:06 +0100 Subject: Add a set() method to HeapValue as well And use it instead of simply assigning to it, so we can add a write barrier later on. Change-Id: I31c0d0b20ed5d37fee046aa02af17875679b22bf Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4context.cpp | 4 ++-- src/qml/jsruntime/qv4functionobject.cpp | 2 +- src/qml/jsruntime/qv4regexpobject.cpp | 4 ++-- src/qml/jsruntime/qv4value_p.h | 5 ++++- src/qml/qml/qqmlcomponent.cpp | 8 ++++---- 5 files changed, 13 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 3918d25326..667b8dbb24 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -168,7 +168,7 @@ void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionV compilationUnit = outer->compilationUnit; this->exceptionVarName.set(engine, exceptionVarName); - this->exceptionValue = exceptionValue; + this->exceptionValue.set(engine, exceptionValue); } @@ -302,7 +302,7 @@ void ExecutionContext::setProperty(String *name, const Value &value) case Heap::ExecutionContext::Type_CatchContext: { Heap::CatchContext *c = static_cast(ctx->d()); if (c->exceptionVarName->isEqualTo(name->d())) { - c->exceptionValue = value; + c->exceptionValue.set(scope.engine, value); return; } break; diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index a2433e7471..55b0175a47 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -540,7 +540,7 @@ void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject Heap::FunctionObject::init(scope, QStringLiteral("__bound function__")); this->target.set(s.engine, target->d()); this->boundArgs.set(s.engine, boundArgs ? boundArgs->d() : 0); - this->boundThis = boundThis; + this->boundThis.set(scope->engine(), boundThis); ScopedObject f(s, this); diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 3ec24edb5d..7b15494ea9 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -220,7 +220,7 @@ void Heap::RegExpCtor::init(QV4::ExecutionContext *scope) void Heap::RegExpCtor::clearLastMatch() { - lastMatch = Primitive::nullValue(); + lastMatch.set(internalClass->engine, Primitive::nullValue()); lastInput.set(internalClass->engine, internalClass->engine->id_empty()->d()); lastMatchStart = 0; lastMatchEnd = 0; @@ -377,7 +377,7 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat *array->propertyData(Index_ArrayInput) = str; RegExpCtor::Data *dd = regExpCtor->d(); - dd->lastMatch = array; + dd->lastMatch.set(scope.engine, array); dd->lastInput.set(scope.engine, str->d()); dd->lastMatchStart = matchOffsets[0]; dd->lastMatchEnd = matchOffsets[1]; diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 3d7776b736..ce7dd8fb0d 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -710,7 +710,10 @@ inline unsigned int Value::toUInt32() const template struct HeapValue : Value { - HeapValue &operator = (const Value &other) { setRawValue(other.rawValue()); return *this; } + void set(ExecutionEngine *e, const Value &newVal) { + Q_UNUSED(e); + setRawValue(newVal.rawValue()); + } }; template diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 993ad10639..75968ffc43 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1376,7 +1376,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) r->setPrototype(p); if (!valuemap->isUndefined()) - r->d()->valuemap = valuemap; + r->d()->valuemap.set(scope.engine, valuemap); r->d()->qmlContext.set(scope.engine, v4->qmlContext()); r->d()->parent = parent; @@ -1461,7 +1461,7 @@ void QV4::QmlIncubatorObject::method_set_statusChanged(const BuiltinFunction *, if (!o || callData->argc < 1) THROW_TYPE_ERROR(); - o->d()->statusChanged = callData->args[0]; + o->d()->statusChanged.set(scope.engine, callData->args[0]); RETURN_UNDEFINED(); } @@ -1473,8 +1473,8 @@ QQmlComponentExtension::~QQmlComponentExtension() void QV4::Heap::QmlIncubatorObject::init(QQmlIncubator::IncubationMode m) { Object::init(); - valuemap = QV4::Primitive::undefinedValue(); - statusChanged = QV4::Primitive::undefinedValue(); + valuemap.set(internalClass->engine, QV4::Primitive::undefinedValue()); + statusChanged.set(internalClass->engine, QV4::Primitive::undefinedValue()); parent.init(); qmlContext.set(internalClass->engine, nullptr); incubator = new QQmlComponentIncubator(this, m); -- cgit v1.2.3 From 38c9bc6b9f5f019f55896369c3b46c77fc29fb41 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 17 Feb 2017 11:18:35 +0100 Subject: Change getValueOrSetter to be write barrier friendly Don't return a naked pointer into the heap, as this makes it impossible to track where and when we're writing into it. Change-Id: I2b9b81779ef8e9fb7a643ddda82aa6af8af459a7 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4arraydata_p.h | 37 ++++++++++++--- src/qml/jsruntime/qv4memberdata_p.h | 12 +++++ src/qml/jsruntime/qv4object.cpp | 94 ++++++++++++++++++++----------------- src/qml/jsruntime/qv4object_p.h | 4 +- src/qml/jsruntime/qv4value_p.h | 5 ++ 5 files changed, 100 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index 1ede463d6d..71ed96a9a5 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -103,6 +103,18 @@ DECLARE_HEAP_OBJECT(ArrayData, Base) { enum Type { Simple = 0, Complex = 1, Sparse = 2, Custom = 3 }; + struct Index { + Heap::ArrayData *arrayData; + uint index; + + void set(ExecutionEngine *e, Value newVal) { + arrayData->values.set(e, index, newVal); + } + const Value *operator->() const { return &arrayData->values[index]; } + const Value &operator*() const { return arrayData->values[index]; } + bool isNull() const { return !arrayData; } + }; + bool isSparse() const { return type == Sparse; } const ArrayVTable *vtable() const { return reinterpret_cast(Base::vtable()); } @@ -113,7 +125,7 @@ DECLARE_HEAP_OBJECT(ArrayData, Base) { inline void getProperty(uint index, Property *p, PropertyAttributes *attrs); inline void setProperty(uint index, const Property *p); inline Property *getProperty(uint index); - inline Value *getValueOrSetter(uint index, PropertyAttributes *attrs); + inline Index getValueOrSetter(uint index, PropertyAttributes *attrs); inline PropertyAttributes attributes(uint i) const; bool isEmpty(uint i) const { @@ -124,6 +136,7 @@ DECLARE_HEAP_OBJECT(ArrayData, Base) { return vtable()->length(this); } + uint mappedIndex(uint index) const; }; V4_ASSERT_IS_TRIVIAL(ArrayData) @@ -185,6 +198,8 @@ struct Q_QML_EXPORT ArrayData : public Managed IsArrayData = true }; + typedef Heap::ArrayData::Index Index; + uint alloc() const { return d()->values.alloc; } uint &alloc() { return d()->values.alloc; } void setAlloc(uint a) { d()->values.alloc = a; } @@ -281,6 +296,16 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData namespace Heap { +inline uint ArrayData::mappedIndex(uint index) const +{ + if (isSparse()) + return static_cast(this)->mappedIndex(index); + if (index >= values.size) + return UINT_MAX; + uint idx = static_cast(this)->mappedIndex(index); + return values[idx].isEmpty() ? UINT_MAX : idx; +} + void ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs) { Property *pd = getProperty(index); @@ -314,16 +339,16 @@ inline PropertyAttributes ArrayData::attributes(uint i) const return static_cast(this)->attributes(i); } -Value *ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs) +ArrayData::Index ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs) { - Property *p = getProperty(index); - if (!p) { + uint idx = mappedIndex(index); + if (idx == UINT_MAX) { *attrs = Attr_Invalid; - return 0; + return { 0, 0 }; } *attrs = attributes(index); - return attrs->isAccessor() ? &p->set : &p->value; + return { this, attrs->isAccessor() ? idx + 1 /* QV4::Object::SetterOffset*/ : idx }; } diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index e486895754..302553464e 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -73,6 +73,18 @@ struct MemberData : Managed { V4_MANAGED(MemberData, Managed) + struct Index { + Heap::MemberData *memberData; + uint index; + + void set(ExecutionEngine *e, Value newVal) { + memberData->values.set(e, index, newVal); + } + const Value *operator->() const { return &memberData->values[index]; } + const Value &operator*() const { return memberData->values[index]; } + bool isNull() const { return !memberData; } + }; + Value &operator[] (uint idx) { return d()->values[idx]; } const Value *data() const { return d()->values.v; } Value *data() { return d()->values.v; } diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 006615e580..5522c78849 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -316,7 +316,7 @@ void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p) } // Section 8.12.2 -Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs) +MemberData::Index Object::getValueOrSetter(String *name, PropertyAttributes *attrs) { Q_ASSERT(name->asArrayIndex() == UINT_MAX); @@ -325,36 +325,38 @@ Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs) uint idx = o->internalClass->find(name); if (idx < UINT_MAX) { *attrs = o->internalClass->propertyData[idx]; - return o->propertyData(attrs->isAccessor() ? idx + SetterOffset : idx); + return MemberData::Index{ o->memberData, attrs->isAccessor() ? idx + SetterOffset : idx }; } o = o->prototype; } *attrs = Attr_Invalid; - return 0; + return { 0, 0 }; } -Value *Object::getValueOrSetter(uint index, PropertyAttributes *attrs) +ArrayData::Index Object::getValueOrSetter(uint index, PropertyAttributes *attrs) { Heap::Object *o = d(); while (o) { - Property *p = o->arrayData ? o->arrayData->getProperty(index) : 0; - if (p) { - *attrs = o->arrayData->attributes(index); - return attrs->isAccessor() ? &p->set : &p->value; + if (o->arrayData) { + uint idx = o->arrayData->mappedIndex(index); + if (idx != UINT_MAX) { + *attrs = o->arrayData->attributes(index); + return { o->arrayData , attrs->isAccessor() ? idx + SetterOffset : idx }; + } } if (o->vtable()->type == Type_StringObject) { if (index < static_cast(o)->length()) { // this is an evil hack, but it works, as the method is only ever called from putIndexed, // where we don't use the returned pointer there for non writable attributes *attrs = (Attr_NotWritable|Attr_NotConfigurable); - return reinterpret_cast(0x1); + return { reinterpret_cast(0x1), 0 }; } } o = o->prototype; } *attrs = Attr_Invalid; - return 0; + return { 0, 0 }; } bool Object::hasProperty(String *name) const @@ -703,43 +705,44 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const // Section 8.12.5 bool Object::internalPut(String *name, const Value &value) { - if (internalClass()->engine->hasException) + ExecutionEngine *engine = this->engine(); + if (engine->hasException) return false; uint idx = name->asArrayIndex(); if (idx != UINT_MAX) return putIndexed(idx, value); - name->makeIdentifier(engine()); + name->makeIdentifier(engine); + MemberData::Index memberIndex{0, 0}; uint member = internalClass()->find(name); - Value *v = 0; PropertyAttributes attrs; if (member < UINT_MAX) { attrs = internalClass()->propertyData[member]; - v = propertyData(attrs.isAccessor() ? member + SetterOffset : member); + memberIndex = { d()->memberData, (attrs.isAccessor() ? member + SetterOffset : member) }; } // clause 1 - if (v) { + if (!memberIndex.isNull()) { if (attrs.isAccessor()) { - if (v->as()) + if (memberIndex->as()) goto cont; goto reject; } else if (!attrs.isWritable()) goto reject; - else if (isArrayObject() && name->equals(engine()->id_length())) { + else if (isArrayObject() && name->equals(engine->id_length())) { bool ok; uint l = value.asArrayLength(&ok); if (!ok) { - engine()->throwRangeError(value); + engine->throwRangeError(value); return false; } ok = setArrayLength(l); if (!ok) goto reject; } else { - *v = value; + memberIndex.set(engine, value); } return true; } else if (!prototype()) { @@ -747,10 +750,11 @@ bool Object::internalPut(String *name, const Value &value) goto reject; } else { // clause 4 - Scope scope(engine()); - if ((v = ScopedObject(scope, prototype())->getValueOrSetter(name, &attrs))) { + Scope scope(engine); + memberIndex = ScopedObject(scope, prototype())->getValueOrSetter(name, &attrs); + if (!memberIndex.isNull()) { if (attrs.isAccessor()) { - if (!v->as()) + if (!memberIndex->as()) goto reject; } else if (!isExtensible() || !attrs.isWritable()) { goto reject; @@ -763,11 +767,11 @@ bool Object::internalPut(String *name, const Value &value) cont: // Clause 5 - if (v && attrs.isAccessor()) { - Q_ASSERT(v->as()); + if (!memberIndex.isNull() && attrs.isAccessor()) { + Q_ASSERT(memberIndex->as()); - Scope scope(engine()); - ScopedFunctionObject setter(scope, *v); + Scope scope(engine); + ScopedFunctionObject setter(scope, *memberIndex); ScopedCallData callData(scope, 1); callData->args[0] = value; callData->thisObject = this; @@ -780,49 +784,51 @@ bool Object::internalPut(String *name, const Value &value) reject: // ### this should be removed once everything is ported to use Object::set() - if (engine()->current->strictMode) { + if (engine->current->strictMode) { QString message = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"'); - engine()->throwTypeError(message); + engine->throwTypeError(message); } return false; } bool Object::internalPutIndexed(uint index, const Value &value) { - if (internalClass()->engine->hasException) + ExecutionEngine *engine = this->engine(); + if (engine->hasException) return false; PropertyAttributes attrs; - Value *v = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : 0; + ArrayData::Index arrayIndex = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : ArrayData::Index{ 0, 0 }; - if (!v && isStringObject()) { + if (arrayIndex.isNull() && isStringObject()) { if (index < static_cast(this)->length()) // not writable goto reject; } // clause 1 - if (v) { + if (!arrayIndex.isNull()) { if (attrs.isAccessor()) { - if (v->as()) + if (arrayIndex->as()) goto cont; goto reject; } else if (!attrs.isWritable()) goto reject; - else - *v = value; + + arrayIndex.set(engine, value); return true; } else if (!prototype()) { if (!isExtensible()) goto reject; } else { // clause 4 - Scope scope(engine()); - if ((v = ScopedObject(scope, prototype())->getValueOrSetter(index, &attrs))) { + Scope scope(engine); + arrayIndex = ScopedObject(scope, prototype())->getValueOrSetter(index, &attrs); + if (!arrayIndex.isNull()) { if (attrs.isAccessor()) { - if (!v->as()) + if (!arrayIndex->as()) goto reject; } else if (!isExtensible() || !attrs.isWritable()) { goto reject; @@ -835,11 +841,11 @@ bool Object::internalPutIndexed(uint index, const Value &value) cont: // Clause 5 - if (v && attrs.isAccessor()) { - Q_ASSERT(v->as()); + if (!arrayIndex.isNull() && attrs.isAccessor()) { + Q_ASSERT(arrayIndex->as()); - Scope scope(engine()); - ScopedFunctionObject setter(scope, *v); + Scope scope(engine); + ScopedFunctionObject setter(scope, *arrayIndex); ScopedCallData callData(scope, 1); callData->args[0] = value; callData->thisObject = this; @@ -852,8 +858,8 @@ bool Object::internalPutIndexed(uint index, const Value &value) reject: // ### this should be removed once everything is ported to use Object::setIndexed() - if (engine()->current->strictMode) - engine()->throwTypeError(); + if (engine->current->strictMode) + engine->throwTypeError(); return false; } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index df987c88f9..3db52bf3d3 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -210,8 +210,8 @@ struct Q_QML_EXPORT Object: Managed { void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0); void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = 0); - Value *getValueOrSetter(String *name, PropertyAttributes *attrs); - Value *getValueOrSetter(uint index, PropertyAttributes *attrs); + MemberData::Index getValueOrSetter(String *name, PropertyAttributes *attrs); + ArrayData::Index getValueOrSetter(uint index, PropertyAttributes *attrs); bool hasProperty(String *name) const; bool hasProperty(uint index) const; diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index ce7dd8fb0d..93b0dfb6d4 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -722,6 +722,11 @@ struct ValueArray { uint alloc; Value v[1]; + void set(ExecutionEngine *e, uint index, Value newVal) { + Q_UNUSED(e); + v[index] = newVal; + } + inline Value &operator[] (uint index) { Q_ASSERT(index < alloc); return v[index]; -- cgit v1.2.3 From ae92e34a0c3e8a2df88a854081678fa35c4f6b42 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 3 Feb 2017 14:55:22 +0100 Subject: Get rid of methods returning a pointer to a Property structure Those are unsafe to use when we introduce write barriers. Change-Id: I686b3544437fc344d14f3561173521600ecb77a0 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4argumentsobject.cpp | 19 +++++------ src/qml/jsruntime/qv4arraydata_p.h | 56 ++++++++++---------------------- src/qml/jsruntime/qv4object.cpp | 26 +++++++-------- 3 files changed, 37 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index bc832c3349..4a83c4e8dc 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -108,22 +108,22 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con fullyCreate(); Scope scope(engine); - Property *pd = arrayData() ? arrayData()->getProperty(index) : 0; ScopedProperty map(scope); PropertyAttributes mapAttrs; + uint numAccessors = qMin(context()->formalParameterCount(), static_cast(context()->callData->argc)); bool isMapped = false; - uint numAccessors = qMin((int)context()->formalParameterCount(), context()->callData->argc); - if (pd && index < (uint)numAccessors) - isMapped = arrayData()->attributes(index).isAccessor() && - pd->getter() == context()->engine->argumentsAccessors[index].getter(); + if (arrayData() && index < numAccessors && + arrayData()->attributes(index).isAccessor() && + arrayData()->get(index) == context()->engine->argumentsAccessors[index].getter()->asReturnedValue()) + isMapped = true; if (isMapped) { Q_ASSERT(arrayData()); mapAttrs = arrayData()->attributes(index); - map->copy(pd, mapAttrs); + arrayData()->getProperty(index, map, &mapAttrs); setArrayAttributes(index, Attr_Data); - pd = arrayData()->getProperty(index); - pd->value = d()->mappedArguments->values[index]; + ArrayData::Index arrayIndex{ arrayData(), arrayData()->mappedIndex(index) }; + arrayIndex.set(scope.engine, d()->mappedArguments->values[index]); } bool strict = engine->current->strictMode; @@ -141,8 +141,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con if (attrs.isWritable()) { setArrayAttributes(index, mapAttrs); - pd = arrayData()->getProperty(index); - pd->copy(map, mapAttrs); + arrayData()->setProperty(engine, index, map); } } diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index 71ed96a9a5..65cf69f6cd 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -122,9 +122,8 @@ DECLARE_HEAP_OBJECT(ArrayData, Base) { inline ReturnedValue get(uint i) const { return vtable()->get(this, i); } - inline void getProperty(uint index, Property *p, PropertyAttributes *attrs); - inline void setProperty(uint index, const Property *p); - inline Property *getProperty(uint index); + inline bool getProperty(uint index, Property *p, PropertyAttributes *attrs); + inline void setProperty(ExecutionEngine *e, uint index, const Property *p); inline Index getValueOrSetter(uint index, PropertyAttributes *attrs); inline PropertyAttributes attributes(uint i) const; @@ -145,15 +144,6 @@ struct SimpleArrayData : public ArrayData { Value data(uint index) const { return values[mappedIndex(index)]; } Value &data(uint index) { return values[mappedIndex(index)]; } - Property *getProperty(uint index) { - if (index >= values.size) - return 0; - index = mappedIndex(index); - if (values[index].isEmpty()) - return 0; - return reinterpret_cast(values.v + index); - } - PropertyAttributes attributes(uint i) const { return attrs ? attrs[i] : Attr_Data; } @@ -173,13 +163,6 @@ struct SparseArrayData : public ArrayData { return n->value; } - Property *getProperty(uint index) { - SparseArrayNode *n = sparse->findNode(index); - if (!n) - return 0; - return reinterpret_cast(values.v + n->value); - } - PropertyAttributes attributes(uint i) const { if (!attrs) return Attr_Data; @@ -231,9 +214,6 @@ struct Q_QML_EXPORT ArrayData : public Managed ReturnedValue get(uint i) const { return d()->get(i); } - inline Property *getProperty(uint index) { - return d()->getProperty(index); - } static void ensureAttributes(Object *o); static void realloc(Object *o, Type newType, uint alloc, bool enforceAttributes); @@ -306,30 +286,28 @@ inline uint ArrayData::mappedIndex(uint index) const return values[idx].isEmpty() ? UINT_MAX : idx; } -void ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs) +bool ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs) { - Property *pd = getProperty(index); - Q_ASSERT(pd); + uint mapped = mappedIndex(index); + if (mapped == UINT_MAX) { + *attrs = Attr_Invalid; + return false; + } + *attrs = attributes(index); - p->value = pd->value; + p->value = *(Index{ this, mapped }); if (attrs->isAccessor()) - p->set = pd->set; + p->set = *(Index{ this, mapped + 1 /*Object::SetterOffset*/ }); + return true; } -void ArrayData::setProperty(uint index, const Property *p) +void ArrayData::setProperty(QV4::ExecutionEngine *e, uint index, const Property *p) { - Property *pd = getProperty(index); - Q_ASSERT(pd); - pd->value = p->value; + uint mapped = mappedIndex(index); + Q_ASSERT(mapped != UINT_MAX); + values.set(e, mapped, p->value); if (attributes(index).isAccessor()) - pd->set = p->set; -} - -inline Property *ArrayData::getProperty(uint index) -{ - if (isSparse()) - return static_cast(this)->getProperty(index); - return static_cast(this)->getProperty(index); + values.set(e, mapped + 1 /*QV4::Object::SetterOffset*/, p->set); } inline PropertyAttributes ArrayData::attributes(uint i) const diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 5522c78849..3fe1ac71b4 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -296,12 +296,9 @@ void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p) { - Property *pd = arrayData() ? arrayData()->getProperty(index) : 0; - if (pd) { - *attrs = arrayData()->attributes(index); - if (p) - p->copy(pd, *attrs); - return; + if (arrayData()) { + if (arrayData()->getProperty(index, p, attrs)) + return; } if (isStringObject()) { *attrs = Attr_NotConfigurable|Attr_NotWritable; @@ -667,15 +664,14 @@ ReturnedValue Object::internalGet(String *name, bool *hasProperty) const ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const { - Property *pd = 0; PropertyAttributes attrs; Scope scope(engine()); ScopedObject o(scope, this); + ScopedProperty pd(scope); + bool exists = false; while (o) { - Property *p = o->arrayData() ? o->arrayData()->getProperty(index) : 0; - if (p) { - pd = p; - attrs = o->arrayData()->attributes(index); + if (o->arrayData() && o->arrayData()->getProperty(index, pd, &attrs)) { + exists = true; break; } if (o->isStringObject()) { @@ -690,7 +686,7 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const o = o->prototype(); } - if (pd) { + if (exists) { if (hasProperty) *hasProperty = true; return getValue(pd->value, attrs); @@ -989,8 +985,8 @@ bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Prope // Clause 1 if (arrayData()) { - hasProperty = arrayData()->getProperty(index); - if (!hasProperty && isStringObject()) + hasProperty = arrayData()->mappedIndex(index) != UINT_MAX; + if (!hasProperty && isStringObject()) hasProperty = (index < static_cast(this)->length()); } @@ -1102,7 +1098,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String * setProperty(index, current); } else { setArrayAttributes(index, cattrs); - arrayData()->setProperty(index, current); + arrayData()->setProperty(scope.engine, index, current); } return true; reject: -- cgit v1.2.3 From df3256b1f1eaa3ff9137ad1da36508365d978a8a Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 3 Feb 2017 16:28:17 +0100 Subject: Go through proper set() functions when writing to MemberData This is required, so we only have to add the write barrier in one place. Change-Id: I4e8bde823b30ad18f043312ac3f1ed46597b91a7 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4argumentsobject.cpp | 14 ++++----- src/qml/jsruntime/qv4errorobject.cpp | 34 ++++++++++---------- src/qml/jsruntime/qv4functionobject.cpp | 13 ++++---- src/qml/jsruntime/qv4global_p.h | 1 + src/qml/jsruntime/qv4internalclass.cpp | 26 ++------------- src/qml/jsruntime/qv4lookup.cpp | 20 ++++++------ src/qml/jsruntime/qv4memberdata_p.h | 10 +++--- src/qml/jsruntime/qv4object.cpp | 16 +++++----- src/qml/jsruntime/qv4object_p.h | 12 ++++--- src/qml/jsruntime/qv4regexpobject.cpp | 28 +++++++---------- src/qml/jsruntime/qv4regexpobject_p.h | 10 +++++- src/qml/jsruntime/qv4runtime.cpp | 2 +- src/qml/jsruntime/qv4stringobject.cpp | 6 ++-- src/qml/jsruntime/qv4value_p.h | 38 ++++++++++++++++++++++ src/qml/jsruntime/qv4variantobject.cpp | 4 +-- src/qml/jsruntime/qv4variantobject_p.h | 4 +-- src/qml/memory/qv4mmdefs_p.h | 8 +++-- src/qml/qml/qqmlvmemetaobject.cpp | 54 +++++++++++++++++--------------- 18 files changed, 166 insertions(+), 134 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 4a83c4e8dc..318db4f904 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -61,20 +61,20 @@ void Heap::ArgumentsObject::init(QV4::CallContext *context) if (context->d()->strictMode) { Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(context->d()->engine->id_caller())); - *args->propertyData(CalleePropertyIndex + QV4::Object::GetterOffset) = v4->thrower(); - *args->propertyData(CalleePropertyIndex + QV4::Object::SetterOffset) = v4->thrower(); - *args->propertyData(CallerPropertyIndex + QV4::Object::GetterOffset) = v4->thrower(); - *args->propertyData(CallerPropertyIndex + QV4::Object::SetterOffset) = v4->thrower(); + args->setProperty(CalleePropertyIndex + QV4::Object::GetterOffset, *v4->thrower()); + args->setProperty(CalleePropertyIndex + QV4::Object::SetterOffset, *v4->thrower()); + args->setProperty(CallerPropertyIndex + QV4::Object::GetterOffset, *v4->thrower()); + args->setProperty(CallerPropertyIndex + QV4::Object::SetterOffset, *v4->thrower()); args->arrayReserve(context->argc()); args->arrayPut(0, context->args(), context->argc()); args->d()->fullyCreated = true; } else { Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); - *args->propertyData(CalleePropertyIndex) = context->d()->function->asReturnedValue(); + args->setProperty(CalleePropertyIndex, context->d()->function); } Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length())); - *args->propertyData(LengthPropertyIndex) = Primitive::fromInt32(context->d()->callData->argc); + args->setProperty(LengthPropertyIndex, Primitive::fromInt32(context->d()->callData->argc)); } void ArgumentsObject::fullyCreate() @@ -92,7 +92,7 @@ void ArgumentsObject::fullyCreate() if (numAccessors) { d()->mappedArguments.set(scope.engine, md->allocate(engine(), numAccessors)); for (uint i = 0; i < numAccessors; ++i) { - d()->mappedArguments->values[i] = context()->callData->args[i]; + d()->mappedArguments->values.set(scope.engine, i, context()->callData->args[i]); arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor); } } diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index daa4f2d9a6..58742a0b84 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -78,10 +78,10 @@ void Heap::ErrorObject::init() if (internalClass == scope.engine->errorProtoClass) return; - *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction(); - *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined(); - *propertyData(QV4::ErrorObject::Index_FileName) = Encode::undefined(); - *propertyData(QV4::ErrorObject::Index_LineNumber) = Encode::undefined(); + setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d()); + setProperty(scope.engine, QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset, Primitive::undefinedValue()); + setProperty(scope.engine, QV4::ErrorObject::Index_FileName, Primitive::undefinedValue()); + setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::undefinedValue()); } void Heap::ErrorObject::init(const Value &message, ErrorType t) @@ -92,17 +92,17 @@ void Heap::ErrorObject::init(const Value &message, ErrorType t) Scope scope(internalClass->engine); Scoped e(scope, this); - *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction(); - *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined(); + setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d()); + setProperty(scope.engine, QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset, Primitive::undefinedValue()); e->d()->stackTrace = new StackTrace(scope.engine->stackTrace()); if (!e->d()->stackTrace->isEmpty()) { - *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace->at(0).source); - *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace->at(0).line); + setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source)); + setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::fromInt32(e->d()->stackTrace->at(0).line)); } if (!message.isUndefined()) - *propertyData(QV4::ErrorObject::Index_Message) = message; + setProperty(scope.engine, QV4::ErrorObject::Index_Message, message); } void Heap::ErrorObject::init(const Value &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t) @@ -113,8 +113,8 @@ void Heap::ErrorObject::init(const Value &message, const QString &fileName, int Scope scope(internalClass->engine); Scoped e(scope, this); - *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction(); - *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined(); + setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d()); + setProperty(scope.engine, QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset, Primitive::undefinedValue()); e->d()->stackTrace = new StackTrace(scope.engine->stackTrace()); StackFrame frame; @@ -124,12 +124,12 @@ void Heap::ErrorObject::init(const Value &message, const QString &fileName, int e->d()->stackTrace->prepend(frame); if (!e->d()->stackTrace->isEmpty()) { - *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace->at(0).source); - *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace->at(0).line); + setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source)); + setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::fromInt32(e->d()->stackTrace->at(0).line)); } if (!message.isUndefined()) - *propertyData(QV4::ErrorObject::Index_Message) = message; + setProperty(scope.engine, QV4::ErrorObject::Index_Message, message); } const char *ErrorObject::className(Heap::ErrorObject::ErrorType t) @@ -319,9 +319,9 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, He ScopedObject o(scope); ctor->defineReadonlyProperty(engine->id_prototype(), (o = obj)); ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); - *obj->propertyData(Index_Constructor) = ctor; - *obj->propertyData(Index_Message) = engine->id_empty(); - *obj->propertyData(Index_Name) = engine->newString(QString::fromLatin1(ErrorObject::className(t))); + obj->setProperty(Index_Constructor, ctor->d()); + obj->setProperty(Index_Message, engine->id_empty()->d()); + obj->setProperty(Index_Name, engine->newString(QString::fromLatin1(ErrorObject::className(t)))); if (t == Heap::ErrorObject::Error) obj->defineDefaultProperty(engine->id_toString(), method_toString, 0); } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 55b0175a47..5c8f03dc72 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -106,7 +106,7 @@ void Heap::FunctionObject::init() function = nullptr; this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d()); Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()) == Index_Prototype); - *propertyData(Index_Prototype) = Encode::undefined(); + setProperty(internalClass->engine, Index_Prototype, Primitive::undefinedValue()); } @@ -126,10 +126,10 @@ void FunctionObject::init(String *n, bool createProto) if (createProto) { ScopedObject proto(s, scope()->engine->newObject(s.engine->protoClass, s.engine->objectPrototype())); Q_ASSERT(s.engine->protoClass->find(s.engine->id_constructor()) == Heap::FunctionObject::Index_ProtoConstructor); - *proto->propertyData(Heap::FunctionObject::Index_ProtoConstructor) = this->asReturnedValue(); - *propertyData(Heap::FunctionObject::Index_Prototype) = proto.asReturnedValue(); + proto->setProperty(Heap::FunctionObject::Index_ProtoConstructor, d()); + setProperty(Heap::FunctionObject::Index_Prototype, proto); } else { - *propertyData(Heap::FunctionObject::Index_Prototype) = Encode::undefined(); + setProperty(Heap::FunctionObject::Index_Prototype, Primitive::undefinedValue()); } if (n) @@ -346,7 +346,8 @@ void FunctionPrototype::method_bind(const BuiltinFunction *, Scope &scope, CallD if (callData->argc > 1) { boundArgs = MemberData::allocate(scope.engine, callData->argc - 1); boundArgs->d()->values.size = callData->argc - 1; - memcpy(boundArgs->data(), callData->args + 1, (callData->argc - 1)*sizeof(Value)); + for (uint i = 0; i < static_cast(callData->argc - 1); ++i) + boundArgs->set(scope.engine, i, callData->args[i + 1]); } ExecutionContext *global = scope.engine->rootContext(); @@ -426,7 +427,7 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function ScopedString name(s, function->name()); f->init(name, true); Q_ASSERT(internalClass && internalClass->find(s.engine->id_length()) == Index_Length); - *propertyData(Index_Length) = Primitive::fromInt32(f->formalParameterCount()); + setProperty(s.engine, Index_Length, Primitive::fromInt32(f->formalParameterCount())); if (scope->d()->strictMode) { ScopedProperty pd(s); diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index cd8fb91f7a..68418ba770 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -201,6 +201,7 @@ struct Property; struct Value; template struct HeapValue; template struct ValueArray; +template struct HeapValueArray; struct Lookup; struct ArrayData; struct VTable; diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index bac71b4537..9b18a5566e 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -126,26 +126,6 @@ InternalClass::InternalClass(const QV4::InternalClass &other) Q_ASSERT(extensible); } -static void insertHoleIntoPropertyData(Object *object, int idx) -{ - int icSize = object->internalClass()->size; - int from = idx; - int to = from + 1; - if (from < icSize) - memmove(object->propertyData(to), object->propertyData(from), - (icSize - from - 1) * sizeof(Value)); -} - -static void removeFromPropertyData(Object *object, int idx, bool accessor = false) -{ - int delta = (accessor ? 2 : 1); - int oldSize = object->internalClass()->size + delta; - int to = idx; - int from = to + delta; - if (from < oldSize) - memmove(object->propertyData(to), object->d()->propertyData(from), (oldSize - to)*sizeof(Value)); -} - void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index) { uint idx; @@ -157,10 +137,10 @@ void InternalClass::changeMember(Object *object, String *string, PropertyAttribu object->setInternalClass(newClass); if (newClass->size > oldClass->size) { Q_ASSERT(newClass->size == oldClass->size + 1); - insertHoleIntoPropertyData(object, idx + 1); + object->d()->memberData->values.insertData(newClass->engine, idx + 1, Primitive::emptyValue()); } else if (newClass->size < oldClass->size) { Q_ASSERT(newClass->size == oldClass->size - 1); - removeFromPropertyData(object, idx + 1); + object->d()->memberData->values.removeData(newClass->engine, idx + 1); } } @@ -318,7 +298,7 @@ void InternalClass::removeMember(Object *object, Identifier *id) Q_ASSERT(object->internalClass()->size == oldClass->size - (accessor ? 2 : 1)); // remove the entry in the property data - removeFromPropertyData(object, propIdx, accessor); + object->d()->memberData->values.removeData(oldClass->engine, propIdx, accessor ? 2 : 1); t.lookup = object->internalClass(); Q_ASSERT(t.lookup); diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index bd677483b5..f322d5a001 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -59,7 +59,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu if (index != UINT_MAX) { level = i; *attrs = obj->internalClass->propertyData.at(index); - Value *v = obj->propertyData(index); + const Value *v = obj->propertyData(index); return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs); } @@ -72,7 +72,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu index = obj->internalClass->find(name); if (index != UINT_MAX) { *attrs = obj->internalClass->propertyData.at(index); - Value *v = obj->propertyData(index); + const Value *v = obj->propertyData(index); return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs); } @@ -94,7 +94,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs if (index != UINT_MAX) { level = i; *attrs = obj->internalClass->propertyData.at(index); - Value *v = obj->propertyData(index); + const Value *v = obj->propertyData(index); return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs); } @@ -107,7 +107,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs index = obj->internalClass->find(name); if (index != UINT_MAX) { *attrs = obj->internalClass->propertyData.at(index); - Value *v = obj->propertyData(index); + const Value *v = obj->propertyData(index); return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs); } @@ -772,7 +772,7 @@ void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Va { Object *o = object.as(); if (o && o->internalClass() == l->classList[0]) { - *o->propertyData(l->index) = value; + o->setProperty(l->index, value); return; } @@ -785,7 +785,7 @@ void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, co if (o && o->internalClass() == l->classList[0]) { if (!o->prototype()) { o->setInternalClass(l->classList[3]); - *o->propertyData(l->index) = value; + o->setProperty(l->index, value); return; } } @@ -801,7 +801,7 @@ void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, co Heap::Object *p = o->prototype(); if (p && p->internalClass == l->classList[1]) { o->setInternalClass(l->classList[3]); - *o->propertyData(l->index) = value; + o->setProperty(l->index, value); return; } } @@ -819,7 +819,7 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, co p = p->prototype; if (p && p->internalClass == l->classList[2]) { o->setInternalClass(l->classList[3]); - *o->propertyData(l->index) = value; + o->setProperty(l->index, value); return; } } @@ -834,11 +834,11 @@ void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, c Object *o = object.as(); if (o) { if (o->internalClass() == l->classList[0]) { - *o->propertyData(l->index) = value; + o->setProperty(l->index, value); return; } if (o->internalClass() == l->classList[1]) { - *o->propertyData(l->index2) = value; + o->setProperty(l->index2, value); return; } } diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index 302553464e..dff7c09a4c 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -60,7 +60,7 @@ namespace QV4 { namespace Heap { #define MemberDataMembers(class, Member) \ - Member(class, ValueArray, ValueArray, values) + Member(class, ValueArray, HeapValueArray, values) DECLARE_HEAP_OBJECT(MemberData, Base) { DECLARE_MARK_TABLE(MemberData); @@ -85,9 +85,11 @@ struct MemberData : Managed bool isNull() const { return !memberData; } }; - Value &operator[] (uint idx) { return d()->values[idx]; } - const Value *data() const { return d()->values.v; } - Value *data() { return d()->values.v; } + const Value &operator[] (uint idx) const { return d()->values[idx]; } + const Value *data() const { return d()->values.data(); } + void set(ExecutionEngine *e, uint index, Value v) { d()->values.set(e, index, v); } + void set(ExecutionEngine *e, uint index, Heap::Base *b) { d()->values.set(e, index, b); } + inline uint size() const { return d()->values.size; } static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = 0); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 3fe1ac71b4..ce8fdc6d6d 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -76,9 +76,9 @@ void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) con void Object::setProperty(uint index, const Property *p) { - *propertyData(index) = p->value; + setProperty(index, p->value); if (internalClass()->propertyData.at(index).isAccessor()) - *propertyData(index + SetterOffset) = p->set; + setProperty(index + SetterOffset, p->set); } bool Object::setPrototype(Object *proto) @@ -117,7 +117,7 @@ bool Object::putValue(uint memberIndex, const Value &value) PropertyAttributes attrs = ic->propertyData[memberIndex]; if (attrs.isAccessor()) { - FunctionObject *set = propertyData(memberIndex + SetterOffset)->as(); + const FunctionObject *set = propertyData(memberIndex + SetterOffset)->as(); if (set) { Scope scope(ic->engine); ScopedFunctionObject setter(scope, set); @@ -133,7 +133,7 @@ bool Object::putValue(uint memberIndex, const Value &value) if (!attrs.isWritable()) goto reject; - *propertyData(memberIndex) = value; + setProperty(memberIndex, value); return true; reject: @@ -264,10 +264,10 @@ void Object::insertMember(String *s, const Property *p, PropertyAttributes attri InternalClass::addMember(this, s, attributes, &idx); if (attributes.isAccessor()) { - *propertyData(idx + GetterOffset) = p->value; - *propertyData(idx + SetterOffset) = p->set; + setProperty(idx + GetterOffset, p->value); + setProperty(idx + SetterOffset, p->set); } else { - *propertyData(idx) = p->value; + setProperty(idx, p->value); } } @@ -526,7 +526,7 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value) l->classList[0] = o->internalClass(); l->index = idx; l->setter = Lookup::setter0; - *o->propertyData(idx) = value; + o->setProperty(idx, value); return; } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 3db52bf3d3..c0169ed035 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -78,8 +78,9 @@ DECLARE_HEAP_OBJECT(Object, Base) { void init() { Base::init(); } void destroy() { Base::destroy(); } - const Value *propertyData(uint index) const { return memberData->values.v + index; } - Value *propertyData(uint index) { return memberData->values.v + index; } + const Value *propertyData(uint index) const { return memberData->values.data() + index; } + void setProperty(ExecutionEngine *e, uint index, Value v) const { memberData->values.set(e, index, v); } + void setProperty(ExecutionEngine *e, uint index, Heap::Base *b) const { memberData->values.set(e, index, b); } }; Q_STATIC_ASSERT(Object::markTable == ((2 << 4) | (2 << 6) | (2 << 8))); @@ -195,13 +196,14 @@ struct Q_QML_EXPORT Object: Managed { void setInternalClass(InternalClass *ic); const Value *propertyData(uint index) const { return d()->propertyData(index); } - Value *propertyData(uint index) { return d()->propertyData(index); } Heap::ArrayData *arrayData() const { return d()->arrayData; } void setArrayData(ArrayData *a) { d()->arrayData.set(engine(), a->d()); } void getProperty(uint index, Property *p, PropertyAttributes *attrs) const; void setProperty(uint index, const Property *p); + void setProperty(uint index, Value v) const { d()->setProperty(engine(), index, v); } + void setProperty(uint index, Heap::Base *b) const { d()->setProperty(engine(), index, b); } const ObjectVTable *vtable() const { return reinterpret_cast(d()->vtable()); } Heap::Object *prototype() const { return d()->prototype; } @@ -469,7 +471,7 @@ struct ArrayObject : Object { private: void commonInit() - { *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0); } + { setProperty(internalClass->engine, LengthPropertyIndex, Primitive::fromInt32(0)); } }; } @@ -509,7 +511,7 @@ struct ArrayObject: Object { inline void Object::setArrayLengthUnchecked(uint l) { if (isArrayObject()) - *propertyData(Heap::ArrayObject::LengthPropertyIndex) = Primitive::fromUInt32(l); + setProperty(Heap::ArrayObject::LengthPropertyIndex, Primitive::fromUInt32(l)); } inline void Object::push_back(const Value &v) diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 7b15494ea9..f8ad11fa98 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -145,7 +145,7 @@ void Heap::RegExpObject::init(const QRegExp &re) void RegExpObject::initProperties() { - *propertyData(Index_LastIndex) = Primitive::fromInt32(0); + setProperty(Index_LastIndex, Primitive::fromInt32(0)); Q_ASSERT(value()); @@ -157,16 +157,10 @@ void RegExpObject::initProperties() p.replace('/', QLatin1String("\\/")); } - *propertyData(Index_Source) = engine()->newString(p); - *propertyData(Index_Global) = Primitive::fromBoolean(global()); - *propertyData(Index_IgnoreCase) = Primitive::fromBoolean(value()->ignoreCase); - *propertyData(Index_Multiline) = Primitive::fromBoolean(value()->multiLine); -} - -Value *RegExpObject::lastIndexProperty() -{ - Q_ASSERT(0 == internalClass()->find(engine()->id_lastIndex())); - return propertyData(0); + setProperty(Index_Source, engine()->newString(p)); + setProperty(Index_Global, Primitive::fromBoolean(global())); + setProperty(Index_IgnoreCase, Primitive::fromBoolean(value()->ignoreCase)); + setProperty(Index_Multiline, Primitive::fromBoolean(value()->multiLine)); } // Converts a JS RegExp to a QRegExp. @@ -344,9 +338,9 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat RETURN_UNDEFINED(); QString s = str->toQString(); - int offset = r->global() ? r->lastIndexProperty()->toInt32() : 0; + int offset = r->global() ? r->lastIndex() : 0; if (offset < 0 || offset > s.length()) { - *r->lastIndexProperty() = Primitive::fromInt32(0); + r->setLastIndex(0); RETURN_RESULT(Encode::null()); } @@ -357,7 +351,7 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat regExpCtor->d()->clearLastMatch(); if (result == -1) { - *r->lastIndexProperty() = Primitive::fromInt32(0); + r->setLastIndex(0); RETURN_RESULT(Encode::null()); } @@ -373,8 +367,8 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat array->arrayPut(i, v); } array->setArrayLengthUnchecked(len); - *array->propertyData(Index_ArrayIndex) = Primitive::fromInt32(result); - *array->propertyData(Index_ArrayInput) = str; + array->setProperty(Index_ArrayIndex, Primitive::fromInt32(result)); + array->setProperty(Index_ArrayInput, str); RegExpCtor::Data *dd = regExpCtor->d(); dd->lastMatch.set(scope.engine, array); @@ -383,7 +377,7 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat dd->lastMatchEnd = matchOffsets[1]; if (r->global()) - *r->lastIndexProperty() = Primitive::fromInt32(matchOffsets[1]); + r->setLastIndex(matchOffsets[1]); scope.result = array; } diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index c2eeb32b88..0fcfe93135 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -128,7 +128,15 @@ struct RegExpObject: Object { void initProperties(); - Value *lastIndexProperty(); + int lastIndex() const { + Q_ASSERT(Index_LastIndex == internalClass()->find(engine()->id_lastIndex())); + return propertyData(Index_LastIndex)->toInt32(); + } + void setLastIndex(int index) { + Q_ASSERT(Index_LastIndex == internalClass()->find(engine()->id_lastIndex())); + return setProperty(Index_LastIndex, Primitive::fromInt32(index)); + } + QRegExp toQRegExp() const; QString toString() const; QString source() const; diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 4459af0e66..7708b81d8a 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1311,7 +1311,7 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4:: } for (uint i = 0; i < klass->size; ++i) - *o->propertyData(i) = *args++; + o->setProperty(i, *args++); if (arrayValueCount > 0) { ScopedValue entry(scope); diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 628c220bae..81f5c3566c 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -78,14 +78,14 @@ void Heap::StringObject::init() Object::init(); Q_ASSERT(vtable() == QV4::StringObject::staticVTable()); string.set(internalClass->engine, internalClass->engine->id_empty()->d()); - *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0); + setProperty(internalClass->engine, LengthPropertyIndex, Primitive::fromInt32(0)); } void Heap::StringObject::init(const QV4::String *str) { Object::init(); string.set(internalClass->engine, str->d()); - *propertyData(LengthPropertyIndex) = Primitive::fromInt32(length()); + setProperty(internalClass->engine, LengthPropertyIndex, Primitive::fromInt32(length())); } Heap::String *Heap::StringObject::getIndex(uint index) const @@ -556,7 +556,7 @@ void StringPrototype::method_replace(const BuiltinFunction *, Scope &scope, Call offset = qMax(offset + 1, matchOffsets[oldSize + 1]); } if (regExp->global()) - *regExp->lastIndexProperty() = Primitive::fromUInt32(0); + regExp->setLastIndex(0); numStringMatches = nMatchOffsets / (regExp->value()->captureCount() * 2); numCaptures = regExp->value()->captureCount(); } else { diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 93b0dfb6d4..4c46eccbd3 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -716,6 +716,44 @@ struct HeapValue : Value { } }; +template +struct HeapValueArray { + uint size; + uint alloc; + Value values[1]; + + void set(ExecutionEngine *e, uint index, Value v) { + Q_UNUSED(e); + Q_ASSERT(index < alloc); + values[index] = v; + } + void set(ExecutionEngine *e, uint index, Heap::Base *b) { + Q_UNUSED(e); + Q_ASSERT(index < alloc); + values[index] = b; + } + inline const Value &operator[] (uint index) const { + Q_ASSERT(index < alloc); + return values[index]; + } + inline const Value *data() const { + return values; + } + + void insertData(ExecutionEngine *e, uint index, Value v) { + for (uint i = size - 1; i > index; --i) { + values[i] = values[i - 1]; + } + set(e, index, v); + } + void removeData(ExecutionEngine *e, uint index, int n = 1) { + Q_UNUSED(e); + for (uint i = index; i < size - n; ++i) { + values[i] = values[i + n]; + } + } +}; + template struct ValueArray { uint size; diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp index 5cab4c5386..f2ff5d307e 100644 --- a/src/qml/jsruntime/qv4variantobject.cpp +++ b/src/qml/jsruntime/qv4variantobject.cpp @@ -84,7 +84,7 @@ bool VariantObject::isEqualTo(Managed *m, Managed *other) return false; } -void VariantObject::addVmePropertyReference() +void VariantObject::addVmePropertyReference() const { if (d()->isScarce() && ++d()->vmePropertyReferenceCount == 1) { // remove from the ep->scarceResources list @@ -94,7 +94,7 @@ void VariantObject::addVmePropertyReference() } } -void VariantObject::removeVmePropertyReference() +void VariantObject::removeVmePropertyReference() const { if (d()->isScarce() && --d()->vmePropertyReferenceCount == 0) { // and add to the ep->scarceResources list diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h index ef51b6632d..e281602bb5 100644 --- a/src/qml/jsruntime/qv4variantobject_p.h +++ b/src/qml/jsruntime/qv4variantobject_p.h @@ -96,8 +96,8 @@ struct VariantObject : Object V4_PROTOTYPE(variantPrototype) V4_NEEDS_DESTROY - void addVmePropertyReference(); - void removeVmePropertyReference(); + void addVmePropertyReference() const; + void removeVmePropertyReference() const; static bool isEqualTo(Managed *m, Managed *other); }; diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index 63e51f9742..9c84a49e90 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -278,6 +278,10 @@ struct MarkFlagEvaluator> { static Q_CONSTEXPR quint64 value = static_cast(Mark_ValueArray) << (2*o / sizeof(quintptr)); }; template +struct MarkFlagEvaluator> { + static Q_CONSTEXPR quint64 value = static_cast(Mark_ValueArray) << (o >> 2); +}; +template struct MarkFlagEvaluator> { static Q_CONSTEXPR quint64 value = static_cast(Mark_Value) << (2 *o / sizeof(quintptr)); }; @@ -288,7 +292,7 @@ struct MarkFlagEvaluator> { #define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_Pointer(c, type, name) Pointer name; #define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_NoMark(c, type, name) type name; #define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_HeapValue(c, type, name) HeapValue<0> name; -#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_ValueArray(c, type, name) ValueArray<0> name; +#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_ValueArray(c, type, name) type<0> name; #define HEAP_OBJECT_MEMBER_EXPANSION(c, gcType, type, name) \ HEAP_OBJECT_MEMBER_EXPANSION_##gcType(c, type, name) @@ -300,7 +304,7 @@ struct MarkFlagEvaluator> { #define HEAP_OBJECT_MEMBER_EXPANSION_HeapValue(c, type, name) \ HeapValue name; #define HEAP_OBJECT_MEMBER_EXPANSION_ValueArray(c, type, name) \ - ValueArray name; + type name; #define HEAP_OBJECT_MARK_EXPANSION(class, gcType, type, name) \ MarkFlagEvaluator::value | diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 2c3476f63a..f464a099e0 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -104,8 +104,10 @@ void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *) if (v4) { QV4::Scope scope(v4); QV4::Scoped sp(scope, m_target->propertyAndMethodStorage.value()); - if (sp) - *(sp->data() + m_index) = QV4::Primitive::nullValue(); + if (sp) { + QV4::MemberData::Index index{ sp->d(), static_cast(m_index) }; + index.set(v4, QV4::Primitive::nullValue()); + } } m_target->activate(m_target->object, m_target->methodOffset() + m_index, 0); @@ -329,7 +331,7 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, if (size) { QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, size); propertyAndMethodStorage.set(v4, data); - std::fill(data->values.v, data->values.v + data->values.size, QV4::Encode::undefined()); + std::fill(data->values.values, data->values.values + data->values.size, QV4::Encode::undefined()); } // Need JS wrapper to ensure properties/methods are marked. @@ -364,77 +366,77 @@ void QQmlVMEMetaObject::writeProperty(int id, int v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = QV4::Primitive::fromInt32(v); + md->set(cache->engine, id, QV4::Primitive::fromInt32(v)); } void QQmlVMEMetaObject::writeProperty(int id, bool v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = QV4::Primitive::fromBoolean(v); + md->set(cache->engine, id, QV4::Primitive::fromBoolean(v)); } void QQmlVMEMetaObject::writeProperty(int id, double v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = QV4::Primitive::fromDouble(v); + md->set(cache->engine, id, QV4::Primitive::fromDouble(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QString& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newString(v); + md->set(cache->engine, id, cache->engine->newString(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QDate& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, QObject* v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = QV4::QObjectWrapper::wrap(cache->engine, v); + md->set(cache->engine, id, QV4::Value::fromReturnedValue(QV4::QObjectWrapper::wrap(cache->engine, v))); QQmlVMEVariantQObjectPtr *guard = getQObjectGuardForProperty(id); if (v && !guard) { @@ -592,7 +594,7 @@ QList *QQmlVMEMetaObject::readPropertyAsList(int id) const if (!v || (int)v->d()->data().userType() != qMetaTypeId >()) { QVariant variant(qVariantFromValue(QList())); v = cache->engine->newVariantObject(variant); - *(md->data() + id) = v; + md->set(cache->engine, id, v); } return static_cast *>(v->d()->data().data()); } @@ -742,7 +744,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { QVariant propertyAsVariant; - if (QV4::VariantObject *v = (md->data() + id)->as()) + if (const QV4::VariantObject *v = (md->data() + id)->as()) propertyAsVariant = v->d()->data(); QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType); } @@ -815,9 +817,9 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * case QV4::CompiledData::Property::Quaternion: Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { - QV4::VariantObject *v = (md->data() + id)->as(); + const QV4::VariantObject *v = (md->data() + id)->as(); if (!v) { - *(md->data() + id) = cache->engine->newVariantObject(QVariant()); + md->set(cache->engine, id, cache->engine->newVariantObject(QVariant())); v = (md->data() + id)->as(); QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data()); } @@ -1028,7 +1030,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) // Importantly, if the current value is a scarce resource, we need to ensure that it // gets automatically released by the engine if no other references to it exist. - QV4::VariantObject *oldVariant = (md->data() + id)->as(); + const QV4::VariantObject *oldVariant = (md->data() + id)->as(); if (oldVariant) oldVariant->removeVmePropertyReference(); @@ -1054,7 +1056,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) guard->setGuardedValue(valueObject, this, id); // Write the value and emit change signal as appropriate. - *(md->data() + id) = value; + md->set(cache->engine, id, value); activate(object, methodOffset() + id, 0); } @@ -1067,7 +1069,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) // Importantly, if the current value is a scarce resource, we need to ensure that it // gets automatically released by the engine if no other references to it exist. - QV4::VariantObject *oldv = (md->data() + id)->as(); + const QV4::VariantObject *oldv = (md->data() + id)->as(); if (oldv) oldv->removeVmePropertyReference(); @@ -1081,7 +1083,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) // Write the value and emit change signal as appropriate. QVariant currentValue = readPropertyAsVariant(id); - *(md->data() + id) = newv; + md->set(cache->engine, id, newv); if ((currentValue.userType() != value.userType() || currentValue != value)) activate(object, methodOffset() + id, 0); } else { @@ -1093,14 +1095,14 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) } else { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) { - QV4::VariantObject *v = (md->data() + id)->as(); + const QV4::VariantObject *v = (md->data() + id)->as(); needActivate = (!v || v->d()->data().userType() != value.userType() || v->d()->data() != value); if (v) v->removeVmePropertyReference(); - *(md->data() + id) = cache->engine->newVariantObject(value); - v = static_cast(md->data() + id); + md->set(cache->engine, id, cache->engine->newVariantObject(value)); + v = static_cast(md->data() + id); v->addVmePropertyReference(); } } @@ -1139,7 +1141,7 @@ void QQmlVMEMetaObject::setVmeMethod(int index, const QV4::Value &function) QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return; - *(md->data() + methodIndex + compiledObject->nProperties) = function; + md->set(cache->engine, methodIndex + compiledObject->nProperties, function); } QV4::ReturnedValue QQmlVMEMetaObject::vmeProperty(int index) const -- cgit v1.2.3 From d7aa952e143accc18d54707d956d019272197078 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 3 Feb 2017 20:58:22 +0100 Subject: Make writes to ArrayData write-barrier safe Change-Id: I2e46100fe72fd83b36b3195130eefce5289d1627 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4arraydata.cpp | 65 +++++++++++++++++++------------------ src/qml/jsruntime/qv4arraydata_p.h | 19 +++++++---- src/qml/jsruntime/qv4engine.cpp | 4 ++- src/qml/jsruntime/qv4lookup.cpp | 4 +-- src/qml/jsruntime/qv4memberdata.cpp | 1 + src/qml/jsruntime/qv4object.cpp | 7 ++-- src/qml/jsruntime/qv4runtime.cpp | 2 +- 7 files changed, 58 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index ef1a7bee3c..f8c2d3f82b 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -159,7 +159,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt } newData->setAlloc(alloc); newData->setType(newType); - newData->setAttrs(enforceAttributes ? reinterpret_cast(newData->d()->values.v + alloc) : 0); + newData->setAttrs(enforceAttributes ? reinterpret_cast(newData->d()->values.values + alloc) : 0); o->setArrayData(newData); if (d) { @@ -173,10 +173,12 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt if (toCopy > d->d()->values.alloc - offset) { uint copyFromStart = toCopy - (d->d()->values.alloc - offset); - memcpy(newData->d()->values.v + toCopy - copyFromStart, d->d()->values.v, sizeof(Value)*copyFromStart); + // no write barrier required here + memcpy(newData->d()->values.values + toCopy - copyFromStart, d->d()->values.values, sizeof(Value)*copyFromStart); toCopy -= copyFromStart; } - memcpy(newData->d()->values.v, d->d()->values.v + offset, sizeof(Value)*toCopy); + // no write barrier required here + memcpy(newData->d()->values.values, d->d()->values.values + offset, sizeof(Value)*toCopy); } if (newType != Heap::ArrayData::Sparse) @@ -201,8 +203,8 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt n->value = i; } else { storeValue(lastFree, i); - sparse->values[i].setEmpty(); - lastFree = &sparse->values[i].rawValueRef(); + sparse->values.values[i].setEmpty(); + lastFree = &sparse->values.values[i].rawValueRef(); } } } @@ -210,8 +212,8 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt if (toCopy < sparse->values.alloc) { for (uint i = toCopy; i < sparse->values.alloc; ++i) { storeValue(lastFree, i); - sparse->values[i].setEmpty(); - lastFree = &sparse->values[i].rawValueRef(); + sparse->values.values[i].setEmpty(); + lastFree = &sparse->values.values[i].rawValueRef(); } storeValue(lastFree, UINT_MAX); } @@ -247,7 +249,7 @@ bool SimpleArrayData::put(Object *o, uint index, const Value &value) Heap::SimpleArrayData *dd = o->d()->arrayData.cast(); Q_ASSERT(index >= dd->values.size || !dd->attrs || !dd->attrs[index].isAccessor()); // ### honour attributes - dd->data(index) = value; + dd->setData(o->engine(), index, value); if (index >= dd->values.size) { if (dd->attrs) dd->attrs[index] = Attr_Data; @@ -263,7 +265,7 @@ bool SimpleArrayData::del(Object *o, uint index) return true; if (!dd->attrs || dd->attrs[index].isConfigurable()) { - dd->data(index) = Primitive::emptyValue(); + dd->setData(o->engine(), index, Primitive::emptyValue()); if (dd->attrs) dd->attrs[index] = Attr_Data; return true; @@ -296,7 +298,7 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n) } dd->values.size += n; for (uint i = 0; i < n; ++i) - dd->data(i) = values[i].asReturnedValue(); + dd->setData(o->engine(), i, values[i]); } ReturnedValue SimpleArrayData::pop_front(Object *o) @@ -343,10 +345,11 @@ bool SimpleArrayData::putArray(Object *o, uint index, const Value *values, uint reallocate(o, index + n + 1, false); dd = o->d()->arrayData.cast(); } + QV4::ExecutionEngine *e = o->engine(); for (uint i = dd->values.size; i < index; ++i) - dd->data(i) = Primitive::emptyValue(); + dd->setData(e, i, Primitive::emptyValue()); for (uint i = 0; i < n; ++i) - dd->data(index + i) = values[i]; + dd->setData(e, index + i, values[i]); dd->values.size = qMax(dd->values.size, index + n); return true; } @@ -354,7 +357,7 @@ bool SimpleArrayData::putArray(Object *o, uint index, const Value *values, uint void SparseArrayData::free(Heap::ArrayData *d, uint idx) { Q_ASSERT(d && d->type == Heap::ArrayData::Sparse); - Value *v = d->values.v + idx; + Value *v = d->values.values + idx; if (d->attrs && d->attrs[idx].isAccessor()) { // double slot, free both. Order is important, so we have a double slot for allocation again afterwards. v[1].setEmpty(Value::fromReturnedValue(d->freeList).emptyValue()); @@ -398,7 +401,7 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot) dd->attrs[idx] = Attr_Accessor; return idx; } - last = &dd->values[Value::fromReturnedValue(*last).value()].rawValueRef(); + last = &dd->values.values[Value::fromReturnedValue(*last).value()].rawValueRef(); } } else { if (Value::fromReturnedValue(dd->freeList).value() == UINT_MAX) { @@ -435,7 +438,7 @@ bool SparseArrayData::put(Object *o, uint index, const Value &value) if (n->value == UINT_MAX) n->value = allocate(o); s = o->d()->arrayData.cast(); - s->values[n->value] = value; + s->setArrayData(o->engine(), n->value, value); if (s->attrs) s->attrs[n->value] = Attr_Data; return true; @@ -463,11 +466,11 @@ bool SparseArrayData::del(Object *o, uint index) if (isAccessor) { // free up both indices - dd->values[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); - dd->values[pidx].setEmpty(pidx + 1); + dd->values.values[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); + dd->values.values[pidx].setEmpty(pidx + 1); } else { Q_ASSERT(dd->type == Heap::ArrayData::Sparse); - dd->values[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); + dd->values.values[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); } dd->freeList = Primitive::emptyValue(pidx).asReturnedValue(); @@ -499,7 +502,7 @@ void SparseArrayData::push_front(Object *o, const Value *values, uint n) for (int i = static_cast(n) - 1; i >= 0; --i) { uint idx = allocate(o); d = o->d()->arrayData.cast(); - d->values[idx] = values[i]; + d->setArrayData(o->engine(), idx, values[i]); d->sparse->push_front(idx); } } @@ -603,10 +606,10 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n) uint chunk = toCopy; if (chunk > os->values.alloc - os->offset) chunk -= os->values.alloc - os->offset; - obj->arrayPut(oldSize, os->values.v + os->offset, chunk); + obj->arrayPut(oldSize, os->values.data() + os->offset, chunk); toCopy -= chunk; if (toCopy) - obj->arrayPut(oldSize + chunk, os->values.v, toCopy); + obj->arrayPut(oldSize + chunk, os->values.data(), toCopy); } return oldSize + n; @@ -624,10 +627,10 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor) if (index >= d->values.size) { // mark possible hole in the array for (uint i = d->values.size; i < index; ++i) - d->data(i) = Primitive::emptyValue(); + d->setData(o->engine(), i, Primitive::emptyValue()); d->values.size = index + 1; } - d->values[d->mappedIndex(index)] = *v; + d->setData(o->engine(), index, *v); return; } } @@ -638,9 +641,9 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor) if (n->value == UINT_MAX) n->value = SparseArrayData::allocate(o, isAccessor); s = o->d()->arrayData.cast(); - s->values[n->value] = *v; + s->setArrayData(o->engine(), n->value, *v); if (isAccessor) - s->values[n->value + Object::SetterOffset] = v[Object::SetterOffset]; + s->setArrayData(o->engine(), n->value + Object::SetterOffset, v[Object::SetterOffset]); } @@ -777,7 +780,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c break; PropertyAttributes a = sparse->attrs() ? sparse->attrs()[n->value] : Attr_Data; - d->data(i) = thisObject->getValue(sparse->arrayData()[n->value], a); + d->setData(engine, i, Value::fromReturnedValue(thisObject->getValue(sparse->arrayData()[n->value], a))); d->attrs[i] = a.isAccessor() ? Attr_Data : a; n = n->nextNode(); @@ -787,7 +790,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c while (n != sparse->sparse()->end()) { if (n->value >= len) break; - d->data(i) = sparse->arrayData()[n->value]; + d->setData(engine, i, sparse->arrayData()[n->value]); n = n->nextNode(); ++i; } @@ -800,7 +803,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c thisObject->initSparseArray(); while (n != sparse->sparse()->end()) { PropertyAttributes a = sparse->attrs() ? sparse->attrs()[n->value] : Attr_Data; - thisObject->arraySet(n->value, reinterpret_cast(sparse->arrayData() + n->value), a); + thisObject->arraySet(n->value, reinterpret_cast(sparse->arrayData() + n->value), a); n = n->nextNode(); } @@ -818,8 +821,8 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c if (!d->data(len).isEmpty()) break; Q_ASSERT(!d->attrs || !d->attrs[len].isAccessor()); - d->data(i) = d->data(len); - d->data(len) = Primitive::emptyValue(); + d->setData(engine, i, d->data(len)); + d->setData(engine, len, Primitive::emptyValue()); } } @@ -830,7 +833,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c ArrayElementLessThan lessThan(engine, thisObject, comparefn); - Value *begin = thisObject->arrayData()->values.v; + Value *begin = thisObject->arrayData()->values.values; sortHelper(begin, begin + len, *begin, lessThan); #ifdef CHECK_SPARSE_ARRAYS diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index 65cf69f6cd..f7f007d128 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -96,7 +96,7 @@ namespace Heap { Member(class, NoMark, PropertyAttributes *, attrs) \ Member(class, NoMark, ReturnedValue, freeList) \ Member(class, NoMark, SparseArray *, sparse) \ - Member(class, ValueArray, ValueArray, values) + Member(class, ValueArray, HeapValueArray, values) DECLARE_HEAP_OBJECT(ArrayData, Base) { DECLARE_MARK_TABLE(ArrayData); @@ -135,14 +135,20 @@ DECLARE_HEAP_OBJECT(ArrayData, Base) { return vtable()->length(this); } + void setArrayData(ExecutionEngine *e, uint index, Value newVal) { + values.set(e, index, newVal); + } + uint mappedIndex(uint index) const; }; V4_ASSERT_IS_TRIVIAL(ArrayData) struct SimpleArrayData : public ArrayData { uint mappedIndex(uint index) const { return (index + offset) % values.alloc; } - Value data(uint index) const { return values[mappedIndex(index)]; } - Value &data(uint index) { return values[mappedIndex(index)]; } + const Value &data(uint index) const { return values[mappedIndex(index)]; } + void setData(ExecutionEngine *e, uint index, Value newVal) { + values.set(e, mappedIndex(index), newVal); + } PropertyAttributes attributes(uint i) const { return attrs ? attrs[i] : Attr_Data; @@ -190,8 +196,10 @@ struct Q_QML_EXPORT ArrayData : public Managed void setType(Type t) { d()->type = t; } PropertyAttributes *attrs() const { return d()->attrs; } void setAttrs(PropertyAttributes *a) { d()->attrs = a; } - const Value *arrayData() const { return d()->values.v; } - Value *arrayData() { return d()->values.v; } + const Value *arrayData() const { return d()->values.data(); } + void setArrayData(ExecutionEngine *e, uint index, Value newVal) { + d()->setArrayData(e, index, newVal); + } const ArrayVTable *vtable() const { return d()->vtable(); } bool isSparse() const { return type() == Heap::ArrayData::Sparse; } @@ -229,7 +237,6 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData uint mappedIndex(uint index) const { return d()->mappedIndex(index); } Value data(uint index) const { return d()->data(index); } - Value &data(uint index) { return d()->data(index); } uint &len() { return d()->values.size; } uint len() const { return d()->values.size; } diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index f38580e5f8..02cd19008a 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -604,7 +604,9 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int leng d->offset = 0; d->values.alloc = length; d->values.size = length; - memcpy(&d->values.v, values, length*sizeof(Value)); + // this doesn't require a write barrier, things will be ok, when the new array data gets inserted into + // the parent object + memcpy(&d->values.values, values, length*sizeof(Value)); a->d()->arrayData.set(this, d); a->setArrayLengthUnchecked(length); } diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index f322d5a001..9fc11a2d2d 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -218,7 +218,7 @@ void Lookup::indexedSetterFallback(Lookup *, ExecutionEngine *engine, const Valu if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { Heap::SimpleArrayData *s = o->d()->arrayData.cast(); if (idx < s->values.size) { - s->data(idx) = value; + s->setData(engine, idx, value); return; } } @@ -240,7 +240,7 @@ void Lookup::indexedSetterObjectInt(Lookup *l, ExecutionEngine *engine, const Va if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) { Heap::SimpleArrayData *s = o->arrayData.cast(); if (idx < s->values.size) { - s->data(idx) = v; + s->setData(engine, idx, v); return; } } diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index ce1c8b614e..8f862d63e9 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -53,6 +53,7 @@ Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberD size_t alloc = MemoryManager::align(sizeof(Heap::MemberData) + (n - 1)*sizeof(Value)); Heap::MemberData *m = e->memoryManager->allocManaged(alloc); if (old) + // no write barrier required here memcpy(m, old, sizeof(Heap::MemberData) + (old->values.size - 1) * sizeof(Value)); else m->init(); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index ce8fdc6d6d..d400c2ae64 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -581,7 +581,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint * int k = it->arrayNode->key(); uint pidx = it->arrayNode->value; Heap::SparseArrayData *sa = o->d()->arrayData.cast(); - Property *p = reinterpret_cast(sa->values.v + pidx); + const Property *p = reinterpret_cast(sa->values.data() + pidx); it->arrayNode = it->arrayNode->nextNode(); PropertyAttributes a = sa->attrs ? sa->attrs[pidx] : Attr_Data; if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { @@ -598,7 +598,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint * // dense arrays while (it->arrayIndex < o->d()->arrayData->values.size) { Heap::SimpleArrayData *sa = o->d()->arrayData.cast(); - Value &val = sa->data(it->arrayIndex); + const Value &val = sa->data(it->arrayIndex); PropertyAttributes a = o->arrayData()->attributes(it->arrayIndex); ++it->arrayIndex; if (!val.isEmpty() @@ -1146,7 +1146,8 @@ void Object::copyArrayData(Object *other) dd->values.size = other->d()->arrayData->values.size; dd->offset = other->d()->arrayData->offset; } - memcpy(d()->arrayData->values.v, other->d()->arrayData->values.v, other->d()->arrayData->values.alloc*sizeof(Value)); + // ### need a write barrier + memcpy(d()->arrayData->values.values, other->d()->arrayData->values.values, other->d()->arrayData->values.alloc*sizeof(Value)); } setArrayLengthUnchecked(other->getLength()); } diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 7708b81d8a..2e833eda7b 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -644,7 +644,7 @@ void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, co if (o->arrayType() == Heap::ArrayData::Simple) { Heap::SimpleArrayData *s = static_cast(o->arrayData()); if (s && idx < s->values.size && !s->data(idx).isEmpty()) { - s->data(idx) = value; + s->setData(engine, idx, value); return; } } -- cgit v1.2.3 From 1a61d609345b0222c41f93f445a6fd517a76cf48 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 3 Feb 2017 21:05:43 +0100 Subject: move locals over to be write barrier safe Change-Id: I56b1dab62ff432273ee8549b0496bd0f3fc655ea Reviewed-by: Simon Hausmann --- src/qml/jit/qv4assembler.cpp | 2 +- src/qml/jsruntime/qv4arraydata_p.h | 2 +- src/qml/jsruntime/qv4context.cpp | 11 ++++++++--- src/qml/jsruntime/qv4global_p.h | 1 - src/qml/jsruntime/qv4memberdata_p.h | 2 +- src/qml/jsruntime/qv4value_p.h | 23 +---------------------- src/qml/jsruntime/qv4vme_moth.cpp | 2 +- src/qml/memory/qv4mm.cpp | 2 +- src/qml/memory/qv4mmdefs_p.h | 4 ---- 9 files changed, 14 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 83baef8453..0b8be97ef5 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -286,7 +286,7 @@ typename Assembler::Pointer Assembler: } break; case IR::ArgLocal::Local: case IR::ArgLocal::ScopedLocal: { - offset = qOffsetOf(CallContext::Data, locals.v) + al->index * sizeof(Value); + offset = qOffsetOf(CallContext::Data, locals.values) + al->index * sizeof(Value); } break; default: Q_UNREACHABLE(); diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index f7f007d128..c2c81e886b 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -96,7 +96,7 @@ namespace Heap { Member(class, NoMark, PropertyAttributes *, attrs) \ Member(class, NoMark, ReturnedValue, freeList) \ Member(class, NoMark, SparseArray *, sparse) \ - Member(class, ValueArray, HeapValueArray, values) + Member(class, ValueArray, ValueArray, values) DECLARE_HEAP_OBJECT(ArrayData, Base) { DECLARE_MARK_TABLE(ArrayData); diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 667b8dbb24..be53b14786 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -82,10 +82,15 @@ Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData uint nLocals = compiledFunction->nLocals; c->locals.size = nLocals; c->locals.alloc = localsAndFormals; +#if QT_POINTER_SIZE == 8 + // memory allocated from the JS heap is 0 initialized, so skip the std::fill() below + Q_ASSERT(Primitive::undefinedValue().asReturnedValue() == 0); +#else if (nLocals) - std::fill(c->locals.v, c->locals.v + nLocals, Primitive::undefinedValue()); + std::fill(c->locals.values, c->locals.values + nLocals, Primitive::undefinedValue()); +#endif - c->callData = reinterpret_cast(c->locals.v + nLocals); + c->callData = reinterpret_cast(c->locals.values + nLocals); ::memcpy(c->callData, callData, sizeof(CallData) - sizeof(Value) + static_cast(callData->argc) * sizeof(Value)); if (callData->argc < static_cast(compiledFunction->nFormals)) std::fill(c->callData->args + c->callData->argc, c->callData->args + compiledFunction->nFormals, Primitive::undefinedValue()); @@ -330,7 +335,7 @@ void ExecutionContext::setProperty(String *name, const Value &value) } else { Q_ASSERT(c->type = Heap::ExecutionContext::Type_CallContext); index -= c->v4Function->nFormals; - static_cast(c)->locals[index] = value; + static_cast(c)->locals.set(scope.engine, index, value); } return; } diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 68418ba770..cd8fb91f7a 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -201,7 +201,6 @@ struct Property; struct Value; template struct HeapValue; template struct ValueArray; -template struct HeapValueArray; struct Lookup; struct ArrayData; struct VTable; diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index dff7c09a4c..fbe66757e0 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -60,7 +60,7 @@ namespace QV4 { namespace Heap { #define MemberDataMembers(class, Member) \ - Member(class, ValueArray, HeapValueArray, values) + Member(class, ValueArray, ValueArray, values) DECLARE_HEAP_OBJECT(MemberData, Base) { DECLARE_MARK_TABLE(MemberData); diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 4c46eccbd3..bb2132c85e 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -717,7 +717,7 @@ struct HeapValue : Value { }; template -struct HeapValueArray { +struct ValueArray { uint size; uint alloc; Value values[1]; @@ -754,27 +754,6 @@ struct HeapValueArray { } }; -template -struct ValueArray { - uint size; - uint alloc; - Value v[1]; - - void set(ExecutionEngine *e, uint index, Value newVal) { - Q_UNUSED(e); - v[index] = newVal; - } - - inline Value &operator[] (uint index) { - Q_ASSERT(index < alloc); - return v[index]; - } - inline const Value &operator[] (uint index) const { - Q_ASSERT(index < alloc); - return v[index]; - } -}; - } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 73db76e105..80a40be5d2 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -417,7 +417,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code } else if (scope->type == QV4::Heap::ExecutionContext::Type_CallContext) { QV4::Heap::CallContext *cc = static_cast(scope); scopes[2*i + 2] = cc->callData->args; - scopes[2*i + 3] = cc->locals.v; + scopes[2*i + 3] = cc->locals.values; } else { scopes[2*i + 2] = 0; scopes[2*i + 3] = 0; diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 39272850b4..f42d509942 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -771,7 +771,7 @@ void MemoryManager::drainMarkStack(Value *markBase) Q_ASSERT(m == Mark_ValueArray); // qDebug() << "marking Value Array at offset" << hex << (mem - reinterpret_cast(h)); ValueArray<0> *a = reinterpret_cast *>(mem); - Value *v = a->v; + Value *v = a->values; const Value *end = v + a->alloc; while (v < end) { v->mark(engine); diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index 9c84a49e90..3f65e97d86 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -278,10 +278,6 @@ struct MarkFlagEvaluator> { static Q_CONSTEXPR quint64 value = static_cast(Mark_ValueArray) << (2*o / sizeof(quintptr)); }; template -struct MarkFlagEvaluator> { - static Q_CONSTEXPR quint64 value = static_cast(Mark_ValueArray) << (o >> 2); -}; -template struct MarkFlagEvaluator> { static Q_CONSTEXPR quint64 value = static_cast(Mark_Value) << (2 *o / sizeof(quintptr)); }; -- cgit v1.2.3 From c13baa8873589c46d19f256ba551a95a6b56d94f Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 6 Feb 2017 10:56:53 +0100 Subject: Make moth write barrier friendly Variable stores to locals and arguments of CallContext's need to go through the write barrier. To make this possible, store the pointer to the base context alongside the pointer to those variables. Change-Id: I648338598f5d8689e4478fc2b0e7c82cddfb9cd8 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4vme_moth.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 80a40be5d2..e669c3a06e 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -249,10 +249,8 @@ int qt_v4DebuggerHook(const char *json) return -NoSuchCommand; // Failure. } -static void qt_v4CheckForBreak(QV4::ExecutionContext *context, QV4::Value **scopes, int scopeDepth) +static void qt_v4CheckForBreak(QV4::ExecutionContext *context) { - Q_UNUSED(scopes); - Q_UNUSED(scopeDepth); const int lineNumber = context->d()->lineNumber; QV4::Function *function = qt_v4ExtractFunction(context); QString engineName = function->sourceFile(); @@ -335,12 +333,13 @@ Param traceParam(const Param ¶m) return param; } # define VALUE(param) (*VALUEPTR(param)) -# define VALUEPTR(param) (scopes[traceParam(param).scope] + param.index) +# define VALUEPTR(param) (scopes[traceParam(param).scope].values + param.index) #else # define VALUE(param) (*VALUEPTR(param)) -# define VALUEPTR(param) (scopes[param.scope] + param.index) +# define VALUEPTR(param) (scopes[param.scope].values + param.index) #endif +// ### add write barrier here #define STOREVALUE(param, value) { \ QV4::ReturnedValue tmp = (value); \ if (engine->hasException) \ @@ -402,25 +401,29 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code } } - Q_ALLOCA_VAR(QV4::Value*, scopes, sizeof(QV4::Value *)*(2 + 2*scopeDepth)); + struct Scopes { + QV4::Value *values; + QV4::Heap::Base *base; // non 0 if a write barrier is required + }; + Q_ALLOCA_VAR(Scopes, scopes, sizeof(Scopes)*(2 + 2*scopeDepth)); { - scopes[0] = const_cast(context->d()->compilationUnit->constants); + scopes[0] = { const_cast(context->d()->compilationUnit->constants), 0 }; // stack gets setup in push instruction - scopes[1] = 0; + scopes[1] = { 0, 0 }; QV4::Heap::ExecutionContext *scope = context->d(); int i = 0; while (scope) { if (scope->type == QV4::Heap::ExecutionContext::Type_SimpleCallContext) { QV4::Heap::SimpleCallContext *cc = static_cast(scope); - scopes[2*i + 2] = cc->callData->args; - scopes[2*i + 3] = 0; + scopes[2*i + 2] = { cc->callData->args, 0 }; + scopes[2*i + 3] = { 0, 0 }; } else if (scope->type == QV4::Heap::ExecutionContext::Type_CallContext) { QV4::Heap::CallContext *cc = static_cast(scope); - scopes[2*i + 2] = cc->callData->args; - scopes[2*i + 3] = cc->locals.values; + scopes[2*i + 2] = { cc->callData->args, cc }; + scopes[2*i + 3] = { cc->locals.values, cc }; } else { - scopes[2*i + 2] = 0; - scopes[2*i + 3] = 0; + scopes[2*i + 2] = { 0, 0 }; + scopes[2*i + 3] = { 0, 0 }; } ++i; scope = scope->outer; @@ -561,7 +564,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code TRACE(inline, "stack size: %u", instr.value); stackSize = instr.value; stack = scope.alloc(stackSize); - scopes[1] = stack; + scopes[1].values = stack; MOTH_END_INSTR(Push) MOTH_BEGIN_INSTR(CallValue) @@ -919,13 +922,13 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code if (debugger && debugger->pauseAtNextOpportunity()) debugger->maybeBreakAtInstruction(); if (qt_v4IsDebugging) - qt_v4CheckForBreak(context, scopes, scopeDepth); + qt_v4CheckForBreak(context); MOTH_END_INSTR(Debug) MOTH_BEGIN_INSTR(Line) engine->current->lineNumber = instr.lineNumber; if (qt_v4IsDebugging) - qt_v4CheckForBreak(context, scopes, scopeDepth); + qt_v4CheckForBreak(context); MOTH_END_INSTR(Line) #endif // QT_NO_QML_DEBUGGER -- cgit v1.2.3 From b214d6cc2f96837d6502c9a3068bbd0d08b5b929 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 6 Feb 2017 10:57:04 +0100 Subject: Add an actual write barrier and centralize it in one place All stores into the Heap from C++ and Moth should now go through the write barrier. Change-Id: Iae9347754b90d68c10fade9f345842e86ec460cd Reviewed-by: Simon Hausmann --- .../qmldbg_debugger/qv4datacollector.cpp | 4 +- src/qml/jit/qv4assembler_p.h | 2 +- src/qml/jsruntime/qv4engine_p.h | 4 +- src/qml/jsruntime/qv4managed_p.h | 1 + src/qml/jsruntime/qv4value_p.h | 46 ------- src/qml/jsruntime/qv4vme_moth.cpp | 9 +- src/qml/memory/memory.pri | 3 +- src/qml/memory/qv4heap_p.h | 20 --- src/qml/memory/qv4writebarrier_p.h | 152 +++++++++++++++++++++ 9 files changed, 168 insertions(+), 73 deletions(-) create mode 100644 src/qml/memory/qv4writebarrier_p.h (limited to 'src') diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index 225a1fa27d..b76cd8e65a 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -366,8 +366,8 @@ QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicat { class ExceptionStateSaver { - quint32 *hasExceptionLoc; - quint32 hadException; + quint8 *hasExceptionLoc; + quint8 hadException; public: ExceptionStateSaver(QV4::ExecutionEngine *engine) diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 720c522e1d..36e812afb3 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -1249,7 +1249,7 @@ public: const RegisterInformation &fpRegistersToSave); void checkException() { - load32(Address(EngineRegister, qOffsetOf(QV4::ExecutionEngine, hasException)), ScratchRegister); + this->load8(Address(EngineRegister, qOffsetOf(QV4::ExecutionEngine, hasException)), ScratchRegister); Jump exceptionThrown = branch32(RelationalCondition::NotEqual, ScratchRegister, TrustedImm32(0)); if (catchBlock) addPatch(catchBlock, exceptionThrown); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 69aa389c44..2ac3a77e29 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -100,7 +100,9 @@ public: Heap::ExecutionContext *current; Value *jsStackTop; - quint32 hasException; + quint8 hasException; + quint8 writeBarrierActive = false; + quint16 unused = 0; qint32 callDepth; MemoryManager *memoryManager; diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index d4cc31b96a..3dc54b13da 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -53,6 +53,7 @@ #include "qv4global_p.h" #include "qv4value_p.h" #include +#include QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index bb2132c85e..6d98692e94 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -708,52 +708,6 @@ inline unsigned int Value::toUInt32() const return (unsigned int)toInt32(); } -template -struct HeapValue : Value { - void set(ExecutionEngine *e, const Value &newVal) { - Q_UNUSED(e); - setRawValue(newVal.rawValue()); - } -}; - -template -struct ValueArray { - uint size; - uint alloc; - Value values[1]; - - void set(ExecutionEngine *e, uint index, Value v) { - Q_UNUSED(e); - Q_ASSERT(index < alloc); - values[index] = v; - } - void set(ExecutionEngine *e, uint index, Heap::Base *b) { - Q_UNUSED(e); - Q_ASSERT(index < alloc); - values[index] = b; - } - inline const Value &operator[] (uint index) const { - Q_ASSERT(index < alloc); - return values[index]; - } - inline const Value *data() const { - return values; - } - - void insertData(ExecutionEngine *e, uint index, Value v) { - for (uint i = size - 1; i > index; --i) { - values[i] = values[i - 1]; - } - set(e, index, v); - } - void removeData(ExecutionEngine *e, uint index, int n = 1) { - Q_UNUSED(e); - for (uint i = index; i < size - n; ++i) { - values[i] = values[i + n]; - } - } -}; - } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index e669c3a06e..09f767dc13 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -344,8 +344,13 @@ Param traceParam(const Param ¶m) QV4::ReturnedValue tmp = (value); \ if (engine->hasException) \ goto catchException; \ - VALUE(param) = tmp; \ - } + if (Q_LIKELY(!engine->writeBarrierActive || !scopes[param.scope].base)) { \ + VALUE(param) = tmp; \ + } else { \ + QV4::WriteBarrier::write(engine, scopes[param.scope].base, VALUEPTR(param), QV4::Value::fromReturnedValue(tmp)); \ + } \ +} + // qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro #ifdef CHECK_EXCEPTION #undef CHECK_EXCEPTION diff --git a/src/qml/memory/memory.pri b/src/qml/memory/memory.pri index 38fadbf23f..7956e4a9a1 100644 --- a/src/qml/memory/memory.pri +++ b/src/qml/memory/memory.pri @@ -7,7 +7,8 @@ SOURCES += \ HEADERS += \ $$PWD/qv4mm_p.h \ - $$PWD/qv4mmdefs_p.h + $$PWD/qv4mmdefs_p.h \ + $$PWD/qv4writebarrier_p.h } HEADERS += \ diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index 2cf3e721f9..bcd1af7705 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -164,26 +164,6 @@ struct Q_QML_EXPORT Base { }; V4_ASSERT_IS_TRIVIAL(Base) -template -struct Pointer { - static Q_CONSTEXPR size_t offset = o; - T operator->() const { return ptr; } - operator T () const { return ptr; } - - void set(ExecutionEngine *e, T newVal) { - Q_UNUSED(e); - ptr = newVal; - } - - template - Type *cast() { return static_cast(ptr); } - -private: - T ptr; -}; -typedef Pointer V4PointerCheck; -V4_ASSERT_IS_TRIVIAL(V4PointerCheck) - } #ifdef QT_NO_QOBJECT diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h new file mode 100644 index 0000000000..1b4505c17f --- /dev/null +++ b/src/qml/memory/qv4writebarrier_p.h @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ +#ifndef QV4WRITEBARRIER_P_H +#define QV4WRITEBARRIER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +namespace WriteBarrier { + +inline void write(QV4::ExecutionEngine *engine, QV4::Heap::Base *base, QV4::Value *slot, QV4::Value value) +{ + Q_UNUSED(engine); + Q_UNUSED(base); + *slot = value; +} + +inline void write(QV4::ExecutionEngine *engine, QV4::Heap::Base *base, QV4::Heap::Base **slot, QV4::Heap::Base *value) +{ + Q_UNUSED(engine); + Q_UNUSED(base); + *slot = value; +} + +} + +namespace Heap { + +template +struct Pointer { + static Q_CONSTEXPR size_t offset = o; + T operator->() const { return ptr; } + operator T () const { return ptr; } + + void set(ExecutionEngine *e, T newVal) { + Q_UNUSED(e); + ptr = newVal; + } + + template + Type *cast() { return static_cast(ptr); } + +private: + T ptr; +}; +typedef Pointer V4PointerCheck; +V4_ASSERT_IS_TRIVIAL(V4PointerCheck) + +} + +template +struct HeapValue : Value { + void set(ExecutionEngine *e, const Value &newVal) { + Q_UNUSED(e); + setRawValue(newVal.rawValue()); + } +}; + +template +struct ValueArray { + uint size; + uint alloc; + Value values[1]; + + void set(ExecutionEngine *e, uint index, Value v) { + Q_UNUSED(e); + Q_ASSERT(index < alloc); + values[index] = v; + } + void set(ExecutionEngine *e, uint index, Heap::Base *b) { + Q_UNUSED(e); + Q_ASSERT(index < alloc); + values[index] = b; + } + inline const Value &operator[] (uint index) const { + Q_ASSERT(index < alloc); + return values[index]; + } + inline const Value *data() const { + return values; + } + + void insertData(ExecutionEngine *e, uint index, Value v) { + for (uint i = size - 1; i > index; --i) { + values[i] = values[i - 1]; + } + set(e, index, v); + } + void removeData(ExecutionEngine *e, uint index, int n = 1) { + Q_UNUSED(e); + for (uint i = index; i < size - n; ++i) { + values[i] = values[i + n]; + } + } +}; + +} + +QT_END_NAMESPACE + +#endif -- cgit v1.2.3 From 38221427bc21a11b96de7fa7666264c34298c0c0 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 6 Feb 2017 15:51:01 +0100 Subject: Get rid of QV4::Function::needsActivation() We can just as well simply check whether we have a simple or regular CallContext instead. Change-Id: Iddd4ca249ab6b3b13d7ef0a732c22a26bcb23dbb Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4context.cpp | 87 ++++++++++++++------------------- src/qml/jsruntime/qv4function.cpp | 13 ++--- src/qml/jsruntime/qv4function_p.h | 4 -- src/qml/jsruntime/qv4functionobject_p.h | 2 - 4 files changed, 44 insertions(+), 62 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index be53b14786..a9b0d67630 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -202,7 +202,6 @@ unsigned int SimpleCallContext::variableCount() const bool ExecutionContext::deleteProperty(String *name) { Scope scope(this); - bool hasWith = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { switch (ctx->d()->type) { @@ -213,7 +212,6 @@ bool ExecutionContext::deleteProperty(String *name) break; } case Heap::ExecutionContext::Type_WithContext: { - hasWith = true; ScopedObject withObject(scope, static_cast(ctx->d())->withObject); if (withObject->hasProperty(name)) return withObject->deleteProperty(name); @@ -225,15 +223,16 @@ bool ExecutionContext::deleteProperty(String *name) return global->deleteProperty(name); break; } - case Heap::ExecutionContext::Type_CallContext: + case Heap::ExecutionContext::Type_CallContext: { + Heap::CallContext *c = static_cast(ctx->d()); + uint index = c->v4Function->internalClass->find(name); + if (index < UINT_MAX) + // ### throw in strict mode? + return false; + Q_FALLTHROUGH(); + } case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::SimpleCallContext *c = static_cast(ctx->d()); - if (c->v4Function && (c->v4Function->needsActivation() || hasWith)) { - uint index = c->v4Function->internalClass->find(name); - if (index < UINT_MAX) - // ### throw in strict mode? - return false; - } ScopedObject qml(scope, c->activation); if (qml && qml->hasProperty(name)) return qml->deleteProperty(name); @@ -376,13 +375,10 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (name->equals(d()->engine->id_this())) return thisObject().asReturnedValue(); - bool hasWith = false; - bool hasCatchScope = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { switch (ctx->d()->type) { case Heap::ExecutionContext::Type_CatchContext: { - hasCatchScope = true; Heap::CatchContext *c = static_cast(ctx->d()); if (c->exceptionVarName->isEqualTo(name->d())) return c->exceptionValue.asReturnedValue(); @@ -390,7 +386,6 @@ ReturnedValue ExecutionContext::getProperty(String *name) } case Heap::ExecutionContext::Type_WithContext: { ScopedObject w(scope, static_cast(ctx->d())->withObject); - hasWith = true; bool hasProperty = false; v = w->get(name, &hasProperty); if (hasProperty) { @@ -406,18 +401,23 @@ ReturnedValue ExecutionContext::getProperty(String *name) return v->asReturnedValue(); break; } - case Heap::ExecutionContext::Type_CallContext: + case Heap::ExecutionContext::Type_CallContext: { + Heap::CallContext *c = static_cast(ctx->d()); + uint index = c->v4Function->internalClass->find(name); + if (index < UINT_MAX) { + if (index < c->v4Function->nFormals) + return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); + Q_ASSERT(c->type = Heap::ExecutionContext::Type_CallContext); + return c->locals[index - c->v4Function->nFormals].asReturnedValue(); + } + if (c->v4Function->isNamedExpression()) { + if (c->function && name->equals(ScopedString(scope, c->v4Function->name()))) + return c->function->asReturnedValue(); + } + Q_FALLTHROUGH(); + } case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::SimpleCallContext *c = static_cast(ctx->d()); - if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { - uint index = c->v4Function->internalClass->find(name); - if (index < UINT_MAX) { - if (index < c->v4Function->nFormals) - return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); - Q_ASSERT(c->type = Heap::ExecutionContext::Type_CallContext); - return static_cast(c)->locals[index - c->v4Function->nFormals].asReturnedValue(); - } - } ScopedObject activation(scope, c->activation); if (activation) { bool hasProperty = false; @@ -425,12 +425,6 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (hasProperty) return v->asReturnedValue(); } - if (c->v4Function->isNamedExpression()) { - Q_ASSERT(c->type == Heap::CallContext::Type_CallContext); - Heap::CallContext *ctx = static_cast(c); - if (ctx->function && name->equals(ScopedString(scope, c->v4Function->name()))) - return ctx->function->asReturnedValue(); - } break; } case Heap::ExecutionContext::Type_QmlContext: { @@ -457,13 +451,10 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) if (name->equals(d()->engine->id_this())) return thisObject().asReturnedValue(); - bool hasWith = false; - bool hasCatchScope = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { switch (ctx->d()->type) { case Heap::ExecutionContext::Type_CatchContext: { - hasCatchScope = true; Heap::CatchContext *c = static_cast(ctx->d()); if (c->exceptionVarName->isEqualTo(name->d())) return c->exceptionValue.asReturnedValue(); @@ -471,7 +462,6 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) } case Heap::ExecutionContext::Type_WithContext: { ScopedObject w(scope, static_cast(ctx->d())->withObject); - hasWith = true; bool hasProperty = false; v = w->get(name, &hasProperty); if (hasProperty) { @@ -488,19 +478,22 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) return v->asReturnedValue(); break; } - case Heap::ExecutionContext::Type_CallContext: + case Heap::ExecutionContext::Type_CallContext: { + Heap::CallContext *c = static_cast(ctx->d()); + uint index = c->v4Function->internalClass->find(name); + if (index < UINT_MAX) { + if (index < c->v4Function->nFormals) + return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); + return c->locals[index - c->v4Function->nFormals].asReturnedValue(); + } + if (c->v4Function->isNamedExpression()) { + if (c->function && name->equals(ScopedString(scope, c->v4Function->name()))) + return c->function->asReturnedValue(); + } + Q_FALLTHROUGH(); + } case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::SimpleCallContext *c = static_cast(ctx->d()); - if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { - Q_ASSERT(c->type == Heap::CallContext::Type_CallContext); - Heap::CallContext *ctx = static_cast(c); - uint index = c->v4Function->internalClass->find(name); - if (index < UINT_MAX) { - if (index < c->v4Function->nFormals) - return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); - return ctx->locals[index - c->v4Function->nFormals].asReturnedValue(); - } - } ScopedObject activation(scope, c->activation); if (activation) { bool hasProperty = false; @@ -508,12 +501,6 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) if (hasProperty) return v->asReturnedValue(); } - if (c->v4Function->isNamedExpression()) { - Q_ASSERT(c->type == Heap::CallContext::Type_CallContext); - Heap::CallContext *ctx = static_cast(c); - if (ctx->function && name->equals(ScopedString(scope, c->v4Function->name()))) - return ctx->function->asReturnedValue(); - } break; } case Heap::ExecutionContext::Type_QmlContext: { diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index dd3208c7e9..b3feae4293 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -83,11 +83,12 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, for (quint32 i = 0; i < compiledFunction->nLocals; ++i) internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable); - activationRequired = compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject)); - - canUseSimpleCall = !needsActivation() && !(compiledFunction->flags & CompiledData::Function::HasCatchOrWith) && - compiledFunction->nFormals <= QV4::Global::ReservedArgumentCount && - compiledFunction->nLocals == 0 && !isNamedExpression(); + canUseSimpleCall = compiledFunction->nInnerFunctions == 0 && + !(compiledFunction->flags & CompiledData::Function::HasDirectEval) && + !(compiledFunction->flags & CompiledData::Function::UsesArgumentsObject) && + !(compiledFunction->flags & CompiledData::Function::HasCatchOrWith) && + nFormals <= QV4::Global::ReservedArgumentCount && + compiledFunction->nLocals == 0 && !isNamedExpression(); } Function::~Function() @@ -119,7 +120,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QListnLocals; ++i) internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable); - activationRequired = true; + canUseSimpleCall = false; } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index ff5febd19c..b11c8af94a 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -69,7 +69,6 @@ struct Q_QML_EXPORT Function { // first nArguments names in internalClass are the actual arguments InternalClass *internalClass; uint nFormals; - bool activationRequired; bool hasQmlDependencies; bool canUseSimpleCall; @@ -89,9 +88,6 @@ struct Q_QML_EXPORT Function { inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; } inline bool isNamedExpression() const { return compiledFunction->flags & CompiledData::Function::IsNamedExpression; } - inline bool needsActivation() const - { return activationRequired; } - inline bool canUseSimpleFunction() const { return canUseSimpleCall; } QQmlSourceLocation sourceLocation() const diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index c7dac7d3e5..d375153058 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -84,7 +84,6 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) { unsigned int formalParameterCount() { return function ? function->nFormals : 0; } unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; } - bool needsActivation() const { return function ? function->needsActivation() : false; } const QV4::Object *protoProperty() const { return propertyData(Index_Prototype)->cast(); } }; @@ -160,7 +159,6 @@ struct Q_QML_EXPORT FunctionObject: Object { static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function); - bool needsActivation() const { return d()->needsActivation(); } bool strictMode() const { return d()->function ? d()->function->isStrict() : false; } bool isBinding() const; bool isBoundFunction() const; -- cgit v1.2.3 From 3e80f3bef90d35bc6c8cec32de875b694988d668 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 7 Feb 2017 08:56:24 +0100 Subject: Make the decision about whether to use a Simple callcontext earlier All required information is already available when creating the CompiledData::Function, so determine at that point whether we use a Simple or full CallContext. Change-Id: Ife489ca2ca6eaf2ffc7843544a56e8bd86590e9d Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4compileddata_p.h | 3 ++- src/qml/compiler/qv4compiler.cpp | 2 ++ src/qml/compiler/qv4jsir_p.h | 6 ++++++ src/qml/jsruntime/qv4function.cpp | 7 +------ 4 files changed, 11 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 13a0c4b075..a1833f2937 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -211,7 +211,8 @@ struct Function HasDirectEval = 0x2, UsesArgumentsObject = 0x4, IsNamedExpression = 0x8, - HasCatchOrWith = 0x10 + HasCatchOrWith = 0x10, + CanUseSimpleCall = 0x20 }; // Absolute offset into file where the code for this function is located. Only used when the function diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 9cfac4a676..e9709f5fb4 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -296,6 +296,8 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *i function->flags |= CompiledData::Function::IsNamedExpression; if (irFunction->hasTry || irFunction->hasWith) function->flags |= CompiledData::Function::HasCatchOrWith; + if (irFunction->canUseSimpleCall()) + function->flags |= CompiledData::Function::CanUseSimpleCall; function->nFormals = irFunction->formals.size(); function->formalsOffset = currentOffset; currentOffset += function->nFormals * sizeof(quint32); diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 23ebe0c962..da2c350393 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -1352,6 +1352,12 @@ struct Function { int getNewStatementId() { return _statementCount++; } int statementCount() const { return _statementCount; } + bool canUseSimpleCall() const { + return nestedFunctions.isEmpty() && + locals.isEmpty() && formals.size() <= QV4::Global::ReservedArgumentCount && + !hasTry && !hasWith && !isNamedExpression && !usesArgumentsObject && !hasDirectEval; + } + private: BasicBlock *getOrCreateBasicBlock(int index); void setStatementCount(int cnt); diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index b3feae4293..ed9e3699f2 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -83,12 +83,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, for (quint32 i = 0; i < compiledFunction->nLocals; ++i) internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable); - canUseSimpleCall = compiledFunction->nInnerFunctions == 0 && - !(compiledFunction->flags & CompiledData::Function::HasDirectEval) && - !(compiledFunction->flags & CompiledData::Function::UsesArgumentsObject) && - !(compiledFunction->flags & CompiledData::Function::HasCatchOrWith) && - nFormals <= QV4::Global::ReservedArgumentCount && - compiledFunction->nLocals == 0 && !isNamedExpression(); + canUseSimpleCall = compiledFunction->flags & CompiledData::Function::CanUseSimpleCall; } Function::~Function() -- cgit v1.2.3 From 7fa8393aac00d6c18048099fd6c4fb77e9ff739a Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 8 Feb 2017 14:18:42 +0100 Subject: Add missing 64 bit shift operations to the X64 macro assembler Change-Id: I1e593e5ed0bb24ed3a158d98495209945c8bb309 Reviewed-by: Simon Hausmann --- src/3rdparty/masm/assembler/MacroAssemblerX86_64.h | 51 +++++++++++++++++++++- src/3rdparty/masm/assembler/X86Assembler.h | 42 ++++++++++-------- 2 files changed, 73 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h index 3566702413..14757f4ea2 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h @@ -327,14 +327,61 @@ public: m_assembler.xorq_ir(imm.m_value, srcDest); } + void lshift64(TrustedImm32 imm, RegisterID dest) + { + m_assembler.shlq_i8r(imm.m_value, dest); + } + + void lshift64(RegisterID src, RegisterID dest) + { + if (src == X86Registers::ecx) + m_assembler.shlq_CLr(dest); + else { + ASSERT(src != dest); + + // Can only shift by ecx, so we do some swapping if we see anything else. + swap(src, X86Registers::ecx); + m_assembler.shlq_CLr(dest == X86Registers::ecx ? src : dest); + swap(src, X86Registers::ecx); + } + } + + void rshift64(TrustedImm32 imm, RegisterID dest) + { + m_assembler.sarq_i8r(imm.m_value, dest); + } + + void rshift64(RegisterID src, RegisterID dest) + { + if (src == X86Registers::ecx) + m_assembler.sarq_CLr(dest); + else { + ASSERT(src != dest); + + // Can only shift by ecx, so we do some swapping if we see anything else. + swap(src, X86Registers::ecx); + m_assembler.sarq_CLr(dest == X86Registers::ecx ? src : dest); + swap(src, X86Registers::ecx); + } + } + void urshift64(TrustedImm32 imm, RegisterID dest) { m_assembler.shrq_i8r(imm.m_value, dest); } - void lshift64(TrustedImm32 imm, RegisterID dest) + void urshift64(RegisterID src, RegisterID dest) { - m_assembler.shlq_i8r(imm.m_value, dest); + if (src == X86Registers::ecx) + m_assembler.shrq_CLr(dest); + else { + ASSERT(src != dest); + + // Can only shift by ecx, so we do some swapping if we see anything else. + swap(src, X86Registers::ecx); + m_assembler.shrq_CLr(dest == X86Registers::ecx ? src : dest); + swap(src, X86Registers::ecx); + } } void load64(ImplicitAddress address, RegisterID dest) diff --git a/src/3rdparty/masm/assembler/X86Assembler.h b/src/3rdparty/masm/assembler/X86Assembler.h index 24462ef38f..e79cea7414 100644 --- a/src/3rdparty/masm/assembler/X86Assembler.h +++ b/src/3rdparty/masm/assembler/X86Assembler.h @@ -723,6 +723,21 @@ public: } } + void sarq_CLr(RegisterID dst) + { + m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst); + } + + void sarq_i8r(int imm, RegisterID dst) + { + if (imm == 1) + m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst); + else { + m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst); + m_formatter.immediate8(imm); + } + } + void shrq_i8r(int imm, RegisterID dst) { // ### doesn't work when removing the "0 &&" @@ -734,6 +749,11 @@ public: } } + void shrq_CLr(RegisterID dst) + { + m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SHR, dst); + } + void shlq_i8r(int imm, RegisterID dst) { // ### doesn't work when removing the "0 &&" @@ -745,7 +765,10 @@ public: } } - + void shlq_CLr(RegisterID dst) + { + m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SHL, dst); + } #endif void sarl_i8r(int imm, RegisterID dst) @@ -793,23 +816,6 @@ public: m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SHL, dst); } -#if CPU(X86_64) - void sarq_CLr(RegisterID dst) - { - m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst); - } - - void sarq_i8r(int imm, RegisterID dst) - { - if (imm == 1) - m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst); - else { - m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst); - m_formatter.immediate8(imm); - } - } -#endif - void imull_rr(RegisterID src, RegisterID dst) { m_formatter.twoByteOp(OP2_IMUL_GvEv, dst, src); -- cgit v1.2.3 From acd9771544811c8dca28575b7d546abbb0271fbb Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 7 Feb 2017 09:20:45 +0100 Subject: Add a method to determine whether an ArgLocal requires a write barrier Change-Id: I0d585797849dc22f22e5173b8da94fecf8952c97 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4jsir_p.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index da2c350393..8ddeb71f69 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -1358,6 +1358,16 @@ struct Function { !hasTry && !hasWith && !isNamedExpression && !usesArgumentsObject && !hasDirectEval; } + bool argLocalRequiresWriteBarrier(ArgLocal *al) const { + uint scope = al->scope; + const IR::Function *f = this; + while (scope) { + f = f->outer; + --scope; + } + return !f->canUseSimpleCall(); + } + private: BasicBlock *getOrCreateBasicBlock(int index); void setStatementCount(int cnt); -- cgit v1.2.3 From d06b171582104db5f0b61ee782fb835dd6038d62 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 7 Feb 2017 10:39:48 +0100 Subject: Mark where we need a write barrier in the JIT Separate the loadAddress calls into loadAddressForReading and loadAddressForWriting. In the second case, add an out argument that specifies whether the write will need a barrier. Pass the write barrier type that is required for a store down into the actual store methods. Change-Id: I3f7634ab82d82f1b20dab331e083d1a662cd314e Reviewed-by: Simon Hausmann --- src/qml/jit/qv4assembler.cpp | 19 ++- src/qml/jit/qv4assembler_p.h | 239 +++++++++++++++++++++---------------- src/qml/jit/qv4binop.cpp | 2 +- src/qml/jit/qv4isel_masm.cpp | 89 +++++++------- src/qml/jit/qv4isel_masm_p.h | 6 +- src/qml/memory/qv4writebarrier_p.h | 5 + 6 files changed, 208 insertions(+), 152 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 0b8be97ef5..59470aeea2 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -246,13 +246,16 @@ void Assembler::generateCJumpOnCompare(RelationalCondition } template -typename Assembler::Pointer Assembler::loadAddress(RegisterID tmp, IR::Expr *e) +typename Assembler::Pointer +Assembler::loadAddressForWriting(RegisterID tmp, IR::Expr *e, WriteBarrier::Type *barrier) { + if (barrier) + *barrier = WriteBarrier::NoBarrier; IR::Temp *t = e->asTemp(); if (t) return loadTempAddress(t); else - return loadArgLocalAddress(tmp, e->asArgLocal()); + return loadArgLocalAddressForWriting(tmp, e->asArgLocal(), barrier); } template @@ -265,7 +268,8 @@ typename Assembler::Pointer Assembler: } template -typename Assembler::Pointer Assembler::loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al) +typename Assembler::Pointer +Assembler::loadArgLocalAddressForWriting(RegisterID baseReg, IR::ArgLocal *al, WriteBarrier::Type *barrier) { int32_t offset = 0; int scope = al->scope; @@ -291,6 +295,8 @@ typename Assembler::Pointer Assembler: default: Q_UNREACHABLE(); } + if (barrier) + *barrier = _function->argLocalRequiresWriteBarrier(al) ? WriteBarrier::Barrier : WriteBarrier::NoBarrier; return Pointer(baseReg, offset); } @@ -329,8 +335,9 @@ void Assembler::loadStringRef(RegisterID reg, const QString template void Assembler::storeValue(QV4::Primitive value, IR::Expr *destination) { - Address addr = loadAddress(ScratchRegister, destination); - storeValue(value, addr); + WriteBarrier::Type barrier; + Address addr = loadAddressForWriting(ScratchRegister, destination, &barrier); + storeValue(value, addr, barrier); } template @@ -419,7 +426,7 @@ typename Assembler::Jump Assembler::ge // It's not a number type, so it cannot be in a register. Q_ASSERT(src->asArgLocal() || src->asTemp()->kind != IR::Temp::PhysicalRegister || src->type == IR::BoolType); - Assembler::Pointer tagAddr = loadAddress(Assembler::ScratchRegister, src); + Assembler::Pointer tagAddr = loadAddressForReading(Assembler::ScratchRegister, src); tagAddr.offset += 4; load32(tagAddr, Assembler::ScratchRegister); diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 36e812afb3..6e95b29ca7 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -57,6 +57,7 @@ #include "private/qv4value_p.h" #include "private/qv4context_p.h" #include "private/qv4engine_p.h" +#include "private/qv4writebarrier_p.h" #include "qv4targetplatform_p.h" #include @@ -158,29 +159,33 @@ struct RegisterSizeDependentAssemblerMacroAssembler::loadDouble(addr, dest); } - static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr) + static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr, WriteBarrier::Type barrier) { + Q_UNUSED(barrier); as->MacroAssembler::storeDouble(source, addr); } static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target) { - Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target); - as->storeDouble(source, ptr); + WriteBarrier::Type barrier; + Pointer ptr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier); + as->storeDouble(source, ptr, barrier); } - static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination) + static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination, WriteBarrier::Type barrier) { + Q_UNUSED(barrier); as->store32(TrustedImm32(value.int_32()), destination); destination.offset += 4; as->store32(TrustedImm32(value.tag()), destination); } template - static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination) + static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination, WriteBarrier::Type barrier) { + Q_UNUSED(barrier); as->loadDouble(source, TargetPlatform::FPGpr0); - as->storeDouble(TargetPlatform::FPGpr0, destination); + as->storeDouble(TargetPlatform::FPGpr0, destination, barrier); } static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target) @@ -193,8 +198,9 @@ struct RegisterSizeDependentAssemblermoveIntsToDouble(TargetPlatform::LowReturnValueRegister, TargetPlatform::HighReturnValueRegister, dest, TargetPlatform::FPGpr0); } - static void storeReturnValue(JITAssembler *as, const Pointer &dest) + static void storeReturnValue(JITAssembler *as, const Pointer &dest, WriteBarrier::Type barrier) { + Q_UNUSED(barrier); Address destination = dest; as->store32(TargetPlatform::LowReturnValueRegister, destination); destination.offset += 4; @@ -234,7 +240,7 @@ struct RegisterSizeDependentAssemblerloadAddress(TargetPlatform::ScratchRegister, t); + Pointer addr = as->loadAddressForReading(TargetPlatform::ScratchRegister, t); as->load32(addr, lowReg); addr.offset += 4; as->load32(addr, highReg); @@ -295,7 +301,7 @@ struct RegisterSizeDependentAssemblerloadAddress(scratchRegister, right); + Pointer tagAddr = as->loadAddressForReading(scratchRegister, right); as->load32(tagAddr, tagRegister); Jump j = as->branch32(JITAssembler::invert(cond), tagRegister, TrustedImm32(0)); as->addPatch(falseBlock, j); @@ -312,7 +318,7 @@ struct RegisterSizeDependentAssemblertype == IR::VarType); // load the tag: - Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, source); + Pointer addr = as->loadAddressForReading(TargetPlatform::ScratchRegister, source); Pointer tagAddr = addr; tagAddr.offset += 4; as->load32(tagAddr, TargetPlatform::ReturnValueRegister); @@ -323,7 +329,9 @@ struct RegisterSizeDependentAssemblerasTemp(); if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { as->load32(addr, TargetPlatform::ReturnValueRegister); - Pointer targetAddr = as->loadAddress(TargetPlatform::ScratchRegister, target); + WriteBarrier::Type barrier; + Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier); + Q_UNUSED(barrier); as->store32(TargetPlatform::ReturnValueRegister, targetAddr); targetAddr.offset += 4; as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr); @@ -335,14 +343,15 @@ struct RegisterSizeDependentAssemblerloadAddress(TargetPlatform::ScratchRegister, source)); + as->loadAddressForReading(TargetPlatform::ScratchRegister, source)); as->storeInt32(TargetPlatform::ReturnValueRegister, target); intDone.link(as); } - static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr) + static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr, WriteBarrier::Type barrier) { + Q_UNUSED(barrier); as->store32(registerWithPtr, destAddr); destAddr.offset += 4; as->store32(TrustedImm32(QV4::Value::Managed_Type_Internal_32), destAddr); @@ -391,8 +400,9 @@ struct RegisterSizeDependentAssemblermove64ToDouble(TargetPlatform::ReturnValueRegister, dest); } - static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr) + static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr, WriteBarrier::Type barrier) { + Q_UNUSED(barrier); as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister); as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister); as->store64(TargetPlatform::ReturnValueRegister, addr); @@ -402,7 +412,9 @@ struct RegisterSizeDependentAssemblermoveDoubleTo64(source, TargetPlatform::ReturnValueRegister); as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister); - Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target); + WriteBarrier::Type barrier; + Pointer ptr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier); + Q_UNUSED(barrier); as->store64(TargetPlatform::ReturnValueRegister, ptr); } @@ -412,8 +424,9 @@ struct RegisterSizeDependentAssemblermove64ToDouble(TargetPlatform::ReturnValueRegister, dest); } - static void storeReturnValue(JITAssembler *as, const Pointer &dest) + static void storeReturnValue(JITAssembler *as, const Pointer &dest, WriteBarrier::Type barrier) { + Q_UNUSED(barrier); as->store64(TargetPlatform::ReturnValueRegister, dest); } @@ -455,7 +468,7 @@ struct RegisterSizeDependentAssemblercopyValue(TargetPlatform::ReturnValueRegister, t); + as->copyValue(TargetPlatform::ReturnValueRegister, t, WriteBarrier::NoBarrier); } } @@ -464,18 +477,19 @@ struct RegisterSizeDependentAssemblermove(TrustedImm64(retVal.rawValue()), TargetPlatform::ReturnValueRegister); } - static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination) + static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination, WriteBarrier::Type barrier) { + Q_UNUSED(barrier); as->store64(TrustedImm64(value.rawValue()), destination); } template - static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination) + static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination, WriteBarrier::Type barrier) { // Use ReturnValueRegister as "scratch" register because loadArgument // and storeArgument are functions that may need a scratch register themselves. loadArgumentInRegister(as, source, TargetPlatform::ReturnValueRegister, 0); - as->storeReturnValue(destination); + as->storeReturnValue(destination, barrier); } static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target) @@ -511,7 +525,7 @@ struct RegisterSizeDependentAssemblerloadArgLocalAddress(dest, al); + Pointer addr = as->loadArgLocalAddressForReading(dest, al); as->load64(addr, dest); } else { QV4::Value undefined = QV4::Primitive::undefinedValue(); @@ -580,7 +594,7 @@ struct RegisterSizeDependentAssemblerloadAddress(scratchRegister, right); + Pointer addr = as->loadAddressForReading(scratchRegister, right); as->load64(addr, tagRegister); const TrustedImm64 tag(0); generateCJumpOnCompare(as, cond, tagRegister, tag, nextBlock, currentBlock, trueBlock, falseBlock); @@ -589,7 +603,7 @@ struct RegisterSizeDependentAssemblertype == IR::VarType); - Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, source); + Pointer addr = as->loadAddressForReading(TargetPlatform::ScratchRegister, source); as->load64(addr, TargetPlatform::ScratchRegister); as->move(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister); @@ -613,14 +627,16 @@ struct RegisterSizeDependentAssemblerloadAddress(TargetPlatform::ScratchRegister, source)); + as->loadAddressForReading(TargetPlatform::ScratchRegister, source)); isIntConvertible.link(as); success.link(as); IR::Temp *targetTemp = target->asTemp(); if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { - Pointer targetAddr = as->loadAddress(TargetPlatform::ScratchRegister, target); + WriteBarrier::Type barrier; + Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier); + Q_UNUSED(barrier); as->store32(TargetPlatform::ReturnValueRegister, targetAddr); targetAddr.offset += 4; as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr); @@ -629,8 +645,9 @@ struct RegisterSizeDependentAssemblerstore64(registerWithPtr, destAddr); } @@ -962,9 +979,16 @@ public: Jump branchDouble(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right); Jump branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right); - Pointer loadAddress(RegisterID tmp, IR::Expr *t); + Pointer loadAddressForWriting(RegisterID tmp, IR::Expr *t, WriteBarrier::Type *barrier); + Pointer loadAddressForReading(RegisterID tmp, IR::Expr *t) { + return loadAddressForWriting(tmp, t, 0); + } + Pointer loadTempAddress(IR::Temp *t); - Pointer loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al); + Pointer loadArgLocalAddressForWriting(RegisterID baseReg, IR::ArgLocal *al, WriteBarrier::Type *barrier); + Pointer loadArgLocalAddressForReading(RegisterID baseReg, IR::ArgLocal *al) { + return loadArgLocalAddressForWriting(baseReg, al, 0); + } Pointer loadStringAddress(RegisterID reg, const QString &string); Address loadConstant(IR::Const *c, RegisterID baseReg); Address loadConstant(const Primitive &v, RegisterID baseReg); @@ -986,16 +1010,16 @@ public: Pointer addr(_stackLayout->savedRegPointer(argumentNumber)); switch (t->type) { case IR::BoolType: - storeBool((RegisterID) t->index, addr); + storeBool((RegisterID) t->index, addr, WriteBarrier::NoBarrier); break; case IR::SInt32Type: - storeInt32((RegisterID) t->index, addr); + storeInt32((RegisterID) t->index, addr, WriteBarrier::NoBarrier); break; case IR::UInt32Type: - storeUInt32((RegisterID) t->index, addr); + storeUInt32((RegisterID) t->index, addr, WriteBarrier::NoBarrier); break; case IR::DoubleType: - storeDouble((FPRegisterID) t->index, addr); + storeDouble((FPRegisterID) t->index, addr, WriteBarrier::NoBarrier); break; default: Q_UNIMPLEMENTED(); @@ -1026,7 +1050,7 @@ public: if (!temp.value) { RegisterSizeDependentOps::zeroRegister(this, dest); } else { - Pointer addr = toAddress(dest, temp.value, argumentNumber); + Pointer addr = toAddress(dest, temp.value, argumentNumber, 0); loadArgumentInRegister(addr, dest, argumentNumber); } } @@ -1039,7 +1063,7 @@ public: void loadArgumentInRegister(Reference temp, RegisterID dest, int argumentNumber) { Q_ASSERT(temp.value); - Pointer addr = loadAddress(dest, temp.value); + Pointer addr = loadAddressForReading(dest, temp.value); loadArgumentInRegister(addr, dest, argumentNumber); } @@ -1072,8 +1096,10 @@ public: move(imm32, dest); } - void storeReturnValue(RegisterID dest) + void storeReturnValue(RegisterID dest, WriteBarrier::Type barrier = WriteBarrier::NoBarrier) { + Q_UNUSED(barrier); + Q_ASSERT(barrier == WriteBarrier::NoBarrier); move(ReturnValueRegister, dest); } @@ -1081,7 +1107,7 @@ public: { subPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister); Pointer tmp(StackPointerRegister, 0); - storeReturnValue(tmp); + storeReturnValue(tmp, WriteBarrier::NoBarrier); toUInt32Register(tmp, dest); addPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister); } @@ -1091,9 +1117,9 @@ public: RegisterSizeDependentOps::storeReturnValue(this, dest); } - void storeReturnValue(const Pointer &dest) + void storeReturnValue(const Pointer &dest, WriteBarrier::Type barrier) { - RegisterSizeDependentOps::storeReturnValue(this, dest); + RegisterSizeDependentOps::storeReturnValue(this, dest, barrier); } void storeReturnValue(IR::Expr *target) @@ -1101,22 +1127,19 @@ public: if (!target) return; - if (IR::Temp *temp = target->asTemp()) { - if (temp->kind == IR::Temp::PhysicalRegister) { - if (temp->type == IR::DoubleType) - storeReturnValue((FPRegisterID) temp->index); - else if (temp->type == IR::UInt32Type) - storeUInt32ReturnValue((RegisterID) temp->index); - else - storeReturnValue((RegisterID) temp->index); - return; - } else { - Pointer addr = loadTempAddress(temp); - storeReturnValue(addr); - } - } else if (IR::ArgLocal *al = target->asArgLocal()) { - Pointer addr = loadArgLocalAddress(ScratchRegister, al); - storeReturnValue(addr); + IR::Temp *temp = target->asTemp(); + if (temp && temp->kind == IR::Temp::PhysicalRegister) { + if (temp->type == IR::DoubleType) + storeReturnValue((FPRegisterID) temp->index); + else if (temp->type == IR::UInt32Type) + storeUInt32ReturnValue((RegisterID) temp->index); + else + storeReturnValue((RegisterID) temp->index); + return; + } else { + WriteBarrier::Type barrier; + Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier); + storeReturnValue(addr, barrier); } } @@ -1153,7 +1176,7 @@ public: void loadArgumentOnStack(PointerToValue temp, int argumentNumber) { if (temp.value) { - Pointer ptr = toAddress(ScratchRegister, temp.value, argumentNumber); + Pointer ptr = toAddress(ScratchRegister, temp.value, argumentNumber, 0); loadArgumentOnStack(ptr, argumentNumber); } else { RegisterSizeDependentOps::zeroStackSlot(this, StackSlot); @@ -1173,7 +1196,7 @@ public: { Q_ASSERT (temp.value); - Pointer ptr = loadAddress(ScratchRegister, temp.value); + Pointer ptr = loadAddressForReading(ScratchRegister, temp.value); loadArgumentOnStack(ptr, argumentNumber); } @@ -1184,7 +1207,7 @@ public: moveDouble((FPRegisterID) sourceTemp->index, dest); return; } - Pointer ptr = loadAddress(ScratchRegister, source); + Pointer ptr = loadAddressForReading(ScratchRegister, source); loadDouble(ptr, dest); } @@ -1203,30 +1226,43 @@ public: RegisterSizeDependentOps::loadDouble(this, addr, dest); } - void storeDouble(FPRegisterID source, Address addr) + void storeDouble(FPRegisterID source, Address addr, WriteBarrier::Type barrier) { - RegisterSizeDependentOps::storeDouble(this, source, addr); + RegisterSizeDependentOps::storeDouble(this, source, addr, barrier); } template - void copyValue(Result result, Source source); + void copyValue(Result result, Source source, WriteBarrier::Type barrier); template - void copyValue(Result result, IR::Expr* source); + void copyValue(Result result, IR::Expr* source, WriteBarrier::Type barrier); // The scratch register is used to calculate the temp address for the source. - void memcopyValue(Pointer target, IR::Expr *source, RegisterID scratchRegister) + void memcopyValue(Pointer target, IR::Expr *source, RegisterID scratchRegister, WriteBarrier::Type barrier) { Q_ASSERT(!source->asTemp() || source->asTemp()->kind != IR::Temp::PhysicalRegister); Q_ASSERT(target.base != scratchRegister); - TargetConfiguration::MacroAssembler::loadDouble(loadAddress(scratchRegister, source), FPGpr0); - TargetConfiguration::MacroAssembler::storeDouble(FPGpr0, target); + loadRawValue(loadAddressForReading(scratchRegister, source), FPGpr0); + storeRawValue(FPGpr0, target, barrier); } // The scratch register is used to calculate the temp address for the source. void memcopyValue(IR::Expr *target, Pointer source, FPRegisterID fpScratchRegister, RegisterID scratchRegister) { - TargetConfiguration::MacroAssembler::loadDouble(source, fpScratchRegister); - TargetConfiguration::MacroAssembler::storeDouble(fpScratchRegister, loadAddress(scratchRegister, target)); + loadRawValue(source, fpScratchRegister); + WriteBarrier::Type barrier; + Pointer dest = loadAddressForWriting(scratchRegister, target, &barrier); + storeRawValue(fpScratchRegister, dest, barrier); + } + + void loadRawValue(Pointer source, FPRegisterID dest) + { + TargetConfiguration::MacroAssembler::loadDouble(source, dest); + } + + void storeRawValue(FPRegisterID source, Pointer dest, WriteBarrier::Type barrier) + { + Q_UNUSED(barrier); + TargetConfiguration::MacroAssembler::storeDouble(source, dest); } void storeValue(QV4::Primitive value, RegisterID destination) @@ -1236,9 +1272,9 @@ public: Q_UNREACHABLE(); } - void storeValue(QV4::Primitive value, Address destination) + void storeValue(QV4::Primitive value, Address destination, WriteBarrier::Type barrier) { - RegisterSizeDependentOps::storeValue(this, value, destination); + RegisterSizeDependentOps::storeValue(this, value, destination, barrier); } void storeValue(QV4::Primitive value, IR::Expr* temp); @@ -1411,8 +1447,10 @@ public: generateFunctionCallImp(needsExceptionCheck, r, functionName, function, arg1, VoidType(), VoidType(), VoidType(), VoidType(), VoidType()); } - Pointer toAddress(RegisterID tmpReg, IR::Expr *e, int offset) + Pointer toAddress(RegisterID tmpReg, IR::Expr *e, int offset, WriteBarrier::Type *barrier) { + if (barrier) + *barrier = WriteBarrier::NoBarrier; if (IR::Const *c = e->asConst()) { Address addr = _stackLayout->savedRegPointer(offset); Address tagAddr = addr; @@ -1428,11 +1466,12 @@ public: if (t->kind == IR::Temp::PhysicalRegister) return Pointer(_stackLayout->savedRegPointer(offset)); - return loadAddress(tmpReg, e); + return loadAddressForWriting(tmpReg, e, barrier); } - void storeBool(RegisterID reg, Pointer addr) + void storeBool(RegisterID reg, Pointer addr, WriteBarrier::Type barrier) { + Q_UNUSED(barrier); store32(reg, addr); addr.offset += 4; store32(TrustedImm32(QV4::Primitive::fromBoolean(0).tag()), addr); @@ -1452,8 +1491,9 @@ public: } } - Pointer addr = loadAddress(ScratchRegister, target); - storeBool(reg, addr); + WriteBarrier::Type barrier; + Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier); + storeBool(reg, addr, barrier); } void storeBool(bool value, IR::Expr *target) { @@ -1475,8 +1515,9 @@ public: move(src, dest); } - void storeInt32(RegisterID reg, Pointer addr) + void storeInt32(RegisterID reg, Pointer addr, WriteBarrier::Type barrier) { + Q_UNUSED(barrier); store32(reg, addr); addr.offset += 4; store32(TrustedImm32(QV4::Primitive::fromInt32(0).tag()), addr); @@ -1484,16 +1525,13 @@ public: void storeInt32(RegisterID reg, IR::Expr *target) { - if (IR::Temp *targetTemp = target->asTemp()) { - if (targetTemp->kind == IR::Temp::PhysicalRegister) { - move(reg, (RegisterID) targetTemp->index); - } else { - Pointer addr = loadTempAddress(targetTemp); - storeInt32(reg, addr); - } - } else if (IR::ArgLocal *al = target->asArgLocal()) { - Pointer addr = loadArgLocalAddress(ScratchRegister, al); - storeInt32(reg, addr); + IR::Temp *targetTemp = target->asTemp(); + if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) { + move(reg, (RegisterID) targetTemp->index); + } else { + WriteBarrier::Type barrier; + Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier); + storeInt32(reg, addr, barrier); } } @@ -1502,15 +1540,15 @@ public: move(src, dest); } - void storeUInt32(RegisterID reg, Pointer addr) + void storeUInt32(RegisterID reg, Pointer addr, WriteBarrier::Type barrier) { // The UInt32 representation in QV4::Value is really convoluted. See also toUInt32Register. Jump intRange = branch32(RelationalCondition::GreaterThanOrEqual, reg, TrustedImm32(0)); convertUInt32ToDouble(reg, FPGpr0, ReturnValueRegister); - storeDouble(FPGpr0, addr); + storeDouble(FPGpr0, addr, barrier); Jump done = jump(); intRange.link(this); - storeInt32(reg, addr); + storeInt32(reg, addr, barrier); done.link(this); } @@ -1520,8 +1558,9 @@ public: if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) { move(reg, (RegisterID) targetTemp->index); } else { - Pointer addr = loadAddress(ScratchRegister, target); - storeUInt32(reg, addr); + WriteBarrier::Type barrier; + Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier); + storeUInt32(reg, addr, barrier); } } @@ -1556,7 +1595,7 @@ public: if (t->kind == IR::Temp::PhysicalRegister) return (RegisterID) t->index; - return toInt32Register(loadAddress(scratchReg, e), scratchReg); + return toInt32Register(loadAddressForReading(scratchReg, e), scratchReg); } RegisterID toInt32Register(Pointer addr, RegisterID scratchReg) @@ -1576,7 +1615,7 @@ public: if (t->kind == IR::Temp::PhysicalRegister) return (RegisterID) t->index; - return toUInt32Register(loadAddress(scratchReg, e), scratchReg); + return toUInt32Register(loadAddressForReading(scratchReg, e), scratchReg); } RegisterID toUInt32Register(Pointer addr, RegisterID scratchReg) @@ -1648,31 +1687,31 @@ private: template template -void Assembler::copyValue(Result result, Source source) +void Assembler::copyValue(Result result, Source source, WriteBarrier::Type barrier) { - RegisterSizeDependentOps::copyValueViaRegisters(this, source, result); + RegisterSizeDependentOps::copyValueViaRegisters(this, source, result, barrier); } template template -void Assembler::copyValue(Result result, IR::Expr* source) +void Assembler::copyValue(Result result, IR::Expr* source, WriteBarrier::Type barrier) { if (source->type == IR::BoolType) { RegisterID reg = toInt32Register(source, ScratchRegister); - storeBool(reg, result); + storeBool(reg, result, barrier); } else if (source->type == IR::SInt32Type) { RegisterID reg = toInt32Register(source, ScratchRegister); - storeInt32(reg, result); + storeInt32(reg, result, barrier); } else if (source->type == IR::UInt32Type) { RegisterID reg = toUInt32Register(source, ScratchRegister); - storeUInt32(reg, result); + storeUInt32(reg, result, barrier); } else if (source->type == IR::DoubleType) { - storeDouble(toDoubleRegister(source), result); + storeDouble(toDoubleRegister(source), result, barrier); } else if (source->asTemp() || source->asArgLocal()) { - RegisterSizeDependentOps::copyValueViaRegisters(this, source, result); + RegisterSizeDependentOps::copyValueViaRegisters(this, source, result, barrier); } else if (IR::Const *c = source->asConst()) { QV4::Primitive v = convertToValue(c); - storeValue(v, result); + storeValue(v, result, barrier); } else { Q_UNREACHABLE(); } diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp index 22067bbb13..0e180eb4cc 100644 --- a/src/qml/jit/qv4binop.cpp +++ b/src/qml/jit/qv4binop.cpp @@ -492,7 +492,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource return false; } } else if (inplaceOpWithAddress) { // All cases of X = X op [address-of-Y] - Pointer rhsAddr = as->loadAddress(JITAssembler::ScratchRegister, rightSource); + Pointer rhsAddr = as->loadAddressForReading(JITAssembler::ScratchRegister, rightSource); switch (op) { case IR::OpBitAnd: as->and32(rhsAddr, targetReg); break; case IR::OpBitOr: as->or32 (rhsAddr, targetReg); break; diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 6d3066aea1..f4bbedad43 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -350,11 +350,11 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr bool isData = it->expr->asConst()->value; it = it->next; - _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr); + _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier); if (!isData) { it = it->next; - _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr); + _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier); } } @@ -376,10 +376,10 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr ++arrayValueCount; // Index - _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++)); + _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier); // Value - _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr); + _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier); it = it->next; } @@ -400,14 +400,14 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr ++arrayGetterSetterCount; // Index - _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++)); + _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier); // Getter - _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr); + _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier); it = it->next; // Setter - _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr); + _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier); it = it->next; } @@ -447,9 +447,11 @@ void InstructionSelection::callValue(IR::Expr *value, IR::ExprList template void InstructionSelection::loadThisObject(IR::Expr *temp) { - _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister); - _as->loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), JITTargetPlatform::ScratchRegister); - _as->copyValue(temp, Address(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject))); + WriteBarrier::Type barrier; + Pointer addr = _as->loadAddressForWriting(JITTargetPlatform::ScratchRegister, temp, &barrier); + _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ReturnValueRegister); + _as->loadPtr(Address(JITTargetPlatform::ReturnValueRegister, qOffsetOf(ExecutionContext::Data, callData)), JITTargetPlatform::ReturnValueRegister); + _as->copyValue(addr, Address(JITTargetPlatform::ReturnValueRegister, qOffsetOf(CallData, thisObject)), barrier); } template @@ -503,8 +505,9 @@ void InstructionSelection::loadString(const QString &str, IR::Expr { Pointer srcAddr = _as->loadStringAddress(JITTargetPlatform::ReturnValueRegister, str); _as->loadPtr(srcAddr, JITTargetPlatform::ReturnValueRegister); - Pointer destAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, target); - JITAssembler::RegisterSizeDependentOps::loadManagedPointer(_as, JITTargetPlatform::ReturnValueRegister, destAddr); + WriteBarrier::Type barrier; + Pointer destAddr = _as->loadAddressForWriting(JITTargetPlatform::ScratchRegister, target, &barrier); + JITAssembler::RegisterSizeDependentOps::loadManagedPointer(_as, JITTargetPlatform::ReturnValueRegister, destAddr, barrier); } template @@ -713,8 +716,10 @@ void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *t } } + WriteBarrier::Type barrier; + Pointer addr = _as->loadAddressForWriting(JITTargetPlatform::ReturnValueRegister, target, &barrier); // The target is not a physical register, nor is the source. So we can do a memory-to-memory copy: - _as->memcopyValue(_as->loadAddress(JITTargetPlatform::ReturnValueRegister, target), source, JITTargetPlatform::ScratchRegister); + _as->memcopyValue(addr, source, JITTargetPlatform::ScratchRegister, barrier); } template @@ -741,14 +746,13 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr * } else if (!sourceTemp || sourceTemp->kind == IR::Temp::StackSlot) { if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { // Note: a swap for two stack-slots can involve different types. - Pointer sAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); - Pointer tAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, target); - // use the implementation in JSC::MacroAssembler, as it doesn't do bit swizzling - auto platformAs = static_cast(_as); - platformAs->loadDouble(sAddr, JITTargetPlatform::FPGpr0); - platformAs->loadDouble(tAddr, JITTargetPlatform::FPGpr1); - platformAs->storeDouble(JITTargetPlatform::FPGpr1, sAddr); - platformAs->storeDouble(JITTargetPlatform::FPGpr0, tAddr); + WriteBarrier::Type barrierForSource, barrierForTarget; + Pointer sAddr = _as->loadAddressForWriting(JITTargetPlatform::ScratchRegister, source, &barrierForSource); + Pointer tAddr = _as->loadAddressForWriting(JITTargetPlatform::ReturnValueRegister, target, &barrierForTarget); + _as->loadRawValue(sAddr, JITTargetPlatform::FPGpr0); + _as->loadRawValue(tAddr, JITTargetPlatform::FPGpr1); + _as->storeRawValue(JITTargetPlatform::FPGpr1, sAddr, barrierForSource); + _as->storeRawValue(JITTargetPlatform::FPGpr0, tAddr, barrierForTarget); return; } } @@ -759,14 +763,15 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr * Q_ASSERT(memExpr); Q_ASSERT(regTemp); - Pointer addr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, memExpr); + WriteBarrier::Type barrier; + Pointer addr = _as->loadAddressForWriting(JITTargetPlatform::ReturnValueRegister, memExpr, &barrier); if (regTemp->type == IR::DoubleType) { _as->loadDouble(addr, JITTargetPlatform::FPGpr0); - _as->storeDouble((FPRegisterID) regTemp->index, addr); + _as->storeDouble((FPRegisterID) regTemp->index, addr, barrier); _as->moveDouble(JITTargetPlatform::FPGpr0, (FPRegisterID) regTemp->index); } else if (regTemp->type == IR::UInt32Type) { _as->toUInt32Register(addr, JITTargetPlatform::ScratchRegister); - _as->storeUInt32((RegisterID) regTemp->index, addr); + _as->storeUInt32((RegisterID) regTemp->index, addr, barrier); _as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index); } else { _as->load32(addr, JITTargetPlatform::ScratchRegister); @@ -915,13 +920,13 @@ void InstructionSelection::convertTypeToDouble(IR::Expr *source, I convertUIntToDouble(source, target); break; case IR::UndefinedType: - _as->loadDouble(_as->loadAddress(JITTargetPlatform::ScratchRegister, source), JITTargetPlatform::FPGpr0); + _as->loadDouble(_as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source), JITTargetPlatform::FPGpr0); _as->storeDouble(JITTargetPlatform::FPGpr0, target); break; case IR::StringType: case IR::VarType: { // load the tag: - Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); + Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source); tagAddr.offset += 4; _as->load32(tagAddr, JITTargetPlatform::ScratchRegister); @@ -940,7 +945,7 @@ void InstructionSelection::convertTypeToDouble(IR::Expr *source, I // it is a double: isDbl.link(_as); - Pointer addr2 = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); + Pointer addr2 = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source); IR::Temp *targetTemp = target->asTemp(); if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { _as->memcopyValue(target, addr2, JITTargetPlatform::FPGpr0, JITTargetPlatform::ReturnValueRegister); @@ -998,7 +1003,7 @@ void InstructionSelection::convertTypeToBool(IR::Expr *source, IR: _as->storeBool(JITTargetPlatform::ReturnValueRegister, target); case IR::VarType: default: - Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); + Pointer addr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source); Pointer tagAddr = addr; tagAddr.offset += 4; _as->load32(tagAddr, JITTargetPlatform::ReturnValueRegister); @@ -1063,7 +1068,7 @@ void InstructionSelection::convertTypeToSInt32(IR::Expr *source, I case IR::StringType: default: generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toInt, - _as->loadAddress(JITTargetPlatform::ScratchRegister, source)); + _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source)); _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target); break; } // switch (source->type) @@ -1075,21 +1080,21 @@ void InstructionSelection::convertTypeToUInt32(IR::Expr *source, I switch (source->type) { case IR::VarType: { // load the tag: - Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); + Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source); tagAddr.offset += 4; _as->load32(tagAddr, JITTargetPlatform::ScratchRegister); // check if it's an int32: Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister, TrustedImm32(Value::Integer_Type_Internal)); - Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); + Pointer addr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source); _as->storeUInt32(_as->toInt32Register(addr, JITTargetPlatform::ScratchRegister), target); Jump intDone = _as->jump(); // not an int: isNoInt.link(_as); generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toUInt, - _as->loadAddress(JITTargetPlatform::ScratchRegister, source)); + _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source)); _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target); intDone.link(_as); @@ -1194,7 +1199,7 @@ void InstructionSelection::visitCJump(IR::CJump *s) reg = JITTargetPlatform::ReturnValueRegister; _as->toInt32Register(t, reg); } else { - Address temp = _as->loadAddress(JITTargetPlatform::ScratchRegister, s->cond); + Address temp = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, s->cond); Address tag = temp; tag.offset += QV4::Value::tagOffset(); Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag, TrustedImm32(QV4::Value::Boolean_Type_Internal)); @@ -1299,9 +1304,9 @@ int InstructionSelection::prepareVariableArguments(IR::ExprList* a Q_ASSERT(arg != 0); Pointer dst(_as->stackLayout().argumentAddressForCall(i)); if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister) - _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister); + _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister, WriteBarrier::NoBarrier); else - _as->copyValue(dst, arg); + _as->copyValue(dst, arg, WriteBarrier::NoBarrier); } return argc; @@ -1321,9 +1326,9 @@ int InstructionSelection::prepareCallData(IR::ExprList* args, IR:: _as->store32(TrustedImm32(argc), p); p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, thisObject)); if (!thisObject) - _as->storeValue(QV4::Primitive::undefinedValue(), p); + _as->storeValue(QV4::Primitive::undefinedValue(), p, WriteBarrier::NoBarrier); else - _as->copyValue(p, thisObject); + _as->copyValue(p, thisObject, WriteBarrier::NoBarrier); int i = 0; for (IR::ExprList *it = args; it; it = it->next, ++i) { @@ -1331,9 +1336,9 @@ int InstructionSelection::prepareCallData(IR::ExprList* args, IR:: Q_ASSERT(arg != 0); Pointer dst(_as->stackLayout().argumentAddressForCall(i)); if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister) - _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister); + _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister, WriteBarrier::NoBarrier); else - _as->copyValue(dst, arg); + _as->copyValue(dst, arg, WriteBarrier::NoBarrier); } return argc; } @@ -1451,7 +1456,7 @@ bool InstructionSelection::visitCJumpStrictNull(IR::Binop *binop, return true; } - Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc); + Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, varSrc); tagAddr.offset += 4; const RegisterID tagReg = JITTargetPlatform::ScratchRegister; _as->load32(tagAddr, tagReg); @@ -1534,7 +1539,7 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, return true; } - Pointer otherAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, otherSrc); + Pointer otherAddr = _as->loadAddressForReading(JITTargetPlatform::ReturnValueRegister, otherSrc); otherAddr.offset += 4; // tag address // check if the tag of the var operand is indicates 'boolean' @@ -1583,7 +1588,7 @@ bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOr return true; } - Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc); + Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, varSrc); tagAddr.offset += 4; const RegisterID tagReg = JITTargetPlatform::ReturnValueRegister; _as->load32(tagAddr, tagReg); diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h index 5764c3946e..0d02284539 100644 --- a/src/qml/jit/qv4isel_masm_p.h +++ b/src/qml/jit/qv4isel_masm_p.h @@ -209,7 +209,7 @@ private: _as->convertInt32ToDouble((RegisterID) sourceTemp->index, (FPRegisterID) targetTemp->index); } else { - _as->convertInt32ToDouble(_as->loadAddress(JITTargetPlatform::ReturnValueRegister, sourceTemp), + _as->convertInt32ToDouble(_as->loadAddressForReading(JITTargetPlatform::ReturnValueRegister, sourceTemp), (FPRegisterID) targetTemp->index); } } else { @@ -223,7 +223,7 @@ private: _as->convertInt32ToDouble(_as->toInt32Register(source, JITTargetPlatform::ScratchRegister), JITTargetPlatform::FPGpr0); - _as->storeDouble(JITTargetPlatform::FPGpr0, _as->loadAddress(JITTargetPlatform::ReturnValueRegister, target)); + _as->storeDouble(JITTargetPlatform::FPGpr0, target); } void convertUIntToDouble(IR::Expr *source, IR::Expr *target) @@ -240,7 +240,7 @@ private: _as->convertUInt32ToDouble(_as->toUInt32Register(source, tmpReg), JITTargetPlatform::FPGpr0, tmpReg); - _as->storeDouble(JITTargetPlatform::FPGpr0, _as->loadAddress(tmpReg, target)); + _as->storeDouble(JITTargetPlatform::FPGpr0, target); } void convertIntToBool(IR::Expr *source, IR::Expr *target) diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h index 1b4505c17f..c0f508f962 100644 --- a/src/qml/memory/qv4writebarrier_p.h +++ b/src/qml/memory/qv4writebarrier_p.h @@ -59,6 +59,11 @@ namespace QV4 { namespace WriteBarrier { +enum Type { + NoBarrier, + Barrier +}; + inline void write(QV4::ExecutionEngine *engine, QV4::Heap::Base *base, QV4::Value *slot, QV4::Value value) { Q_UNUSED(engine); -- cgit v1.2.3 From 05de4e044f92dd278a00e410be8f070bc4d66e6f Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 15 Feb 2017 15:40:42 +0100 Subject: Smaller cleanup Change-Id: I68de47784c41b7aa2da5334c6a7f470d1180b752 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4regexpobject.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index f8ad11fa98..85e37ebe82 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -74,8 +74,8 @@ void Heap::RegExpObject::init() Object::init(); Scope scope(internalClass->engine); Scoped o(scope, this); - o->d()->value.set(scope.engine, QV4::RegExp::create(scope.engine, QString(), false, false)); - o->d()->global = false; + value.set(scope.engine, QV4::RegExp::create(scope.engine, QString(), false, false)); + global = false; o->initProperties(); } -- cgit v1.2.3 From 2a554434a571dcefd26cf10ef8c5ae8b3b7d66db Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 8 Feb 2017 16:21:02 +0100 Subject: Implement a real write barrier Implement a Steel write barrier for our objects. The barrier is interesting as it can also be used for incremental GC runs by simply turning the barrier on and leaving old objects marked as black. Change-Id: I0b273974d94a990dee3cd9298089b8b202c75bf2 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4jsir_p.h | 10 +++ src/qml/jit/qv4assembler.cpp | 22 +++--- src/qml/jit/qv4assembler_p.h | 155 +++++++++++++++++++++++++++++++++---- src/qml/jit/qv4isel_masm.cpp | 1 + src/qml/jsruntime/qv4context.cpp | 11 +++ src/qml/jsruntime/qv4context_p.h | 12 +-- src/qml/jsruntime/qv4engine.cpp | 6 +- src/qml/jsruntime/qv4engine_p.h | 8 +- src/qml/jsruntime/qv4lookup.cpp | 2 +- src/qml/jsruntime/qv4object_p.h | 2 + src/qml/memory/qv4heap_p.h | 6 ++ src/qml/memory/qv4mm.cpp | 2 + src/qml/memory/qv4mm_p.h | 13 ++-- src/qml/memory/qv4mmdefs_p.h | 11 +++ src/qml/memory/qv4writebarrier_p.h | 100 +++++++++++++++++++++--- 15 files changed, 296 insertions(+), 65 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 8ddeb71f69..756d90a033 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -1367,6 +1367,15 @@ struct Function { } return !f->canUseSimpleCall(); } + int localsCountForScope(ArgLocal *al) const { + uint scope = al->scope; + const IR::Function *f = this; + while (scope) { + f = f->outer; + --scope; + } + return f->locals.size(); + } private: BasicBlock *getOrCreateBasicBlock(int index); @@ -1436,6 +1445,7 @@ public: ArgLocal *newArgLocal = f->New(); newArgLocal->init(argLocal->kind, argLocal->index, argLocal->scope); newArgLocal->type = argLocal->type; + newArgLocal->isArgumentsOrEval = argLocal->isArgumentsOrEval; return newArgLocal; } diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 59470aeea2..687c35adfa 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -271,22 +271,28 @@ template typename Assembler::Pointer Assembler::loadArgLocalAddressForWriting(RegisterID baseReg, IR::ArgLocal *al, WriteBarrier::Type *barrier) { + if (barrier) + *barrier = _function->argLocalRequiresWriteBarrier(al) ? WriteBarrier::Barrier : WriteBarrier::NoBarrier; + int32_t offset = 0; int scope = al->scope; loadPtr(Address(EngineRegister, qOffsetOf(ExecutionEngine, current)), baseReg); - if (scope) { + while (scope) { loadPtr(Address(baseReg, qOffsetOf(ExecutionContext::Data, outer)), baseReg); --scope; - while (scope) { - loadPtr(Address(baseReg, qOffsetOf(ExecutionContext::Data, outer)), baseReg); - --scope; - } } switch (al->kind) { case IR::ArgLocal::Formal: case IR::ArgLocal::ScopedFormal: { - loadPtr(Address(baseReg, qOffsetOf(ExecutionContext::Data, callData)), baseReg); - offset = sizeof(CallData) + (al->index - 1) * sizeof(Value); + if (barrier && *barrier == WriteBarrier::Barrier) { + // if we need a barrier, the baseReg has to point to the ExecutionContext + // callData comes directly after locals, calculate the offset using that + offset = qOffsetOf(CallContext::Data, locals.values) + _function->localsCountForScope(al) * sizeof(Value); + offset += sizeof(CallData) + (al->index - 1) * sizeof(Value); + } else { + loadPtr(Address(baseReg, qOffsetOf(ExecutionContext::Data, callData)), baseReg); + offset = sizeof(CallData) + (al->index - 1) * sizeof(Value); + } } break; case IR::ArgLocal::Local: case IR::ArgLocal::ScopedLocal: { @@ -295,8 +301,6 @@ Assembler::loadArgLocalAddressForWriting(RegisterID baseReg default: Q_UNREACHABLE(); } - if (barrier) - *barrier = _function->argLocalRequiresWriteBarrier(al) ? WriteBarrier::Barrier : WriteBarrier::NoBarrier; return Pointer(baseReg, offset); } diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 6e95b29ca7..d56b54f491 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -154,6 +154,56 @@ struct RegisterSizeDependentAssemblerpush(TargetPlatform::EngineRegister); // free up one register for work + + RegisterID grayBitmap = returnValueUsed ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister; + as->move(base, grayBitmap); + Q_ASSERT(base != grayBitmap); + as->urshift32(TrustedImm32(Chunk::ChunkShift), grayBitmap); + as->lshift32(TrustedImm32(Chunk::ChunkShift), grayBitmap); + Q_STATIC_ASSERT(offsetof(Chunk, grayBitmap) == 0); + + RegisterID index = base; + as->move(base, index); + as->sub32(grayBitmap, index); + as->urshift32(TrustedImm32(Chunk::SlotSizeShift), index); + RegisterID grayIndex = TargetPlatform::EngineRegister; + as->move(index, grayIndex); + as->urshift32(TrustedImm32(Chunk::BitShift), grayIndex); + as->lshift32(TrustedImm32(2), grayIndex); // 4 bytes per quintptr + as->add32(grayIndex, grayBitmap); + as->and32(TrustedImm32(Chunk::Bits - 1), index); + + RegisterID bit = TargetPlatform::EngineRegister; + as->move(TrustedImm32(1), bit); + as->lshift32(index, bit); + + as->load32(Pointer(grayBitmap, 0), index); + as->or32(bit, index); + as->store32(index, Pointer(grayBitmap, 0)); + + as->pop(TargetPlatform::EngineRegister); + } + +#if WRITEBARRIER(steele) + static void emitWriteBarrier(JITAssembler *as, Address addr) + { +// RegisterID test = addr.base == TargetPlatform::ReturnValueRegister ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister; + // if (engine->writeBarrier) +// as->load8(Address(TargetPlatform::EngineRegister, offsetof(EngineBase, writeBarrierActive)), test); +// typename JITAssembler::Jump jump = as->branch32(JITAssembler::Equal, test, TrustedImm32(0)); + // ### emit fence + emitSetGrayBit(as, addr.base); +// jump.link(as); + } +#elif WRITEBARRIER(none) + static Q_ALWAYS_INLINE void emitWriteBarrier(JITAssembler *, Address) {} +#endif + static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest) { as->MacroAssembler::loadDouble(addr, dest); @@ -161,8 +211,9 @@ struct RegisterSizeDependentAssemblerMacroAssembler::storeDouble(source, addr); + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, addr); } static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target) @@ -174,18 +225,23 @@ struct RegisterSizeDependentAssemblerstore32(TrustedImm32(value.int_32()), destination); destination.offset += 4; as->store32(TrustedImm32(value.tag()), destination); + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, destination); } template static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination, WriteBarrier::Type barrier) { - Q_UNUSED(barrier); as->loadDouble(source, TargetPlatform::FPGpr0); - as->storeDouble(TargetPlatform::FPGpr0, destination, barrier); + // We need to pass NoBarrier to storeDouble and call emitWriteBarrier ourselves, as the + // code in storeDouble assumes the type we're storing is actually a double, something + // that isn't always the case here. + as->storeDouble(TargetPlatform::FPGpr0, destination, WriteBarrier::NoBarrier); + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, destination); } static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target) @@ -200,11 +256,12 @@ struct RegisterSizeDependentAssemblerstore32(TargetPlatform::LowReturnValueRegister, destination); destination.offset += 4; as->store32(TargetPlatform::HighReturnValueRegister, destination); + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, dest); } static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t) @@ -331,10 +388,11 @@ struct RegisterSizeDependentAssemblerload32(addr, TargetPlatform::ReturnValueRegister); WriteBarrier::Type barrier; Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier); - Q_UNUSED(barrier); as->store32(TargetPlatform::ReturnValueRegister, targetAddr); targetAddr.offset += 4; as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr); + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, targetAddr); } else { as->load32(addr, (RegisterID) targetTemp->index); } @@ -351,10 +409,11 @@ struct RegisterSizeDependentAssemblerstore32(registerWithPtr, destAddr); destAddr.offset += 4; as->store32(TrustedImm32(QV4::Value::Managed_Type_Internal_32), destAddr); + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, destAddr); } static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister) @@ -393,6 +452,56 @@ struct RegisterSizeDependentAssemblerpush(TargetPlatform::EngineRegister); // free up one register for work + + RegisterID grayBitmap = returnValueUsed ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister; + as->move(base, grayBitmap); + Q_ASSERT(base != grayBitmap); + as->urshift64(TrustedImm32(Chunk::ChunkShift), grayBitmap); + as->lshift64(TrustedImm32(Chunk::ChunkShift), grayBitmap); + Q_STATIC_ASSERT(offsetof(Chunk, grayBitmap) == 0); + + RegisterID index = base; + as->move(base, index); + as->sub64(grayBitmap, index); + as->urshift64(TrustedImm32(Chunk::SlotSizeShift), index); + RegisterID grayIndex = TargetPlatform::EngineRegister; + as->move(index, grayIndex); + as->urshift64(TrustedImm32(Chunk::BitShift), grayIndex); + as->lshift64(TrustedImm32(3), grayIndex); // 8 bytes per quintptr + as->add64(grayIndex, grayBitmap); + as->and64(TrustedImm32(Chunk::Bits - 1), index); + + RegisterID bit = TargetPlatform::EngineRegister; + as->move(TrustedImm32(1), bit); + as->lshift64(index, bit); + + as->load64(Pointer(grayBitmap, 0), index); + as->or64(bit, index); + as->store64(index, Pointer(grayBitmap, 0)); + + as->pop(TargetPlatform::EngineRegister); + } + +#if WRITEBARRIER(steele) + static void emitWriteBarrier(JITAssembler *as, Address addr) + { +// RegisterID test = addr.base == TargetPlatform::ReturnValueRegister ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister; + // if (engine->writeBarrier) +// as->load8(Address(TargetPlatform::EngineRegister, offsetof(EngineBase, writeBarrierActive)), test); +// typename JITAssembler::Jump jump = as->branch32(JITAssembler::Equal, test, TrustedImm32(0)); + // ### emit fence + emitSetGrayBit(as, addr.base); +// jump.link(as); + } +#elif WRITEBARRIER(none) + static Q_ALWAYS_INLINE void emitWriteBarrier(JITAssembler *, Address) {} +#endif + static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest) { as->load64(addr, TargetPlatform::ReturnValueRegister); @@ -402,10 +511,11 @@ struct RegisterSizeDependentAssemblermoveDoubleTo64(source, TargetPlatform::ReturnValueRegister); as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister); as->store64(TargetPlatform::ReturnValueRegister, addr); + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, addr); } static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target) @@ -414,8 +524,9 @@ struct RegisterSizeDependentAssemblerxor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister); WriteBarrier::Type barrier; Pointer ptr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier); - Q_UNUSED(barrier); as->store64(TargetPlatform::ReturnValueRegister, ptr); + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, ptr); } static void storeReturnValue(JITAssembler *as, FPRegisterID dest) @@ -426,8 +537,9 @@ struct RegisterSizeDependentAssemblerstore64(TargetPlatform::ReturnValueRegister, dest); + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, dest); } static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t) @@ -479,8 +591,9 @@ struct RegisterSizeDependentAssemblerstore64(TrustedImm64(value.rawValue()), destination); + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, destination); } template @@ -636,10 +749,11 @@ struct RegisterSizeDependentAssemblerkind == IR::Temp::StackSlot) { WriteBarrier::Type barrier; Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier); - Q_UNUSED(barrier); as->store32(TargetPlatform::ReturnValueRegister, targetAddr); targetAddr.offset += 4; as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr); + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, targetAddr); } else { as->storeInt32(TargetPlatform::ReturnValueRegister, target); } @@ -647,8 +761,9 @@ struct RegisterSizeDependentAssemblerstore64(registerWithPtr, destAddr); + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, destAddr); } static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister) @@ -1261,8 +1376,9 @@ public: void storeRawValue(FPRegisterID source, Pointer dest, WriteBarrier::Type barrier) { - Q_UNUSED(barrier); TargetConfiguration::MacroAssembler::storeDouble(source, dest); + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + RegisterSizeDependentOps::emitWriteBarrier(this, dest); } void storeValue(QV4::Primitive value, RegisterID destination) @@ -1279,6 +1395,11 @@ public: void storeValue(QV4::Primitive value, IR::Expr* temp); + void emitWriteBarrier(Address addr, WriteBarrier::Type barrier) { + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + RegisterSizeDependentOps::emitWriteBarrier(this, addr); + } + void enterStandardStackFrame(const RegisterInformation ®ularRegistersToSave, const RegisterInformation &fpRegistersToSave); void leaveStandardStackFrame(const RegisterInformation ®ularRegistersToSave, @@ -1471,10 +1592,11 @@ public: void storeBool(RegisterID reg, Pointer addr, WriteBarrier::Type barrier) { - Q_UNUSED(barrier); store32(reg, addr); addr.offset += 4; store32(TrustedImm32(QV4::Primitive::fromBoolean(0).tag()), addr); + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + RegisterSizeDependentOps::emitWriteBarrier(this, addr); } void storeBool(RegisterID src, RegisterID dest) @@ -1517,10 +1639,11 @@ public: void storeInt32(RegisterID reg, Pointer addr, WriteBarrier::Type barrier) { - Q_UNUSED(barrier); store32(reg, addr); addr.offset += 4; store32(TrustedImm32(QV4::Primitive::fromInt32(0).tag()), addr); + if (WriteBarrier::isRequired() && barrier == WriteBarrier::Barrier) + RegisterSizeDependentOps::emitWriteBarrier(this, addr); } void storeInt32(RegisterID reg, IR::Expr *target) diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index f4bbedad43..5b57d29bca 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -791,6 +791,7 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr * Q_UNREACHABLE(); } _as->store32(TrustedImm32(tag), addr); + _as->emitWriteBarrier(addr, barrier); } _as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index); } diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index a9b0d67630..7a0df5dbf3 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -176,6 +176,17 @@ void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionV this->exceptionValue.set(engine, exceptionValue); } +void Heap::WithContext::init(ExecutionContext *outerContext, Object *with) +{ + Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_WithContext); + outer.set(engine, outerContext); + callData = outer->callData; + lookups = outer->lookups; + constantTable = outer->constantTable; + compilationUnit = outer->compilationUnit; + + withObject.set(engine, with); +} Identifier * const *SimpleCallContext::formals() const { diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index a405da0f57..79e5f74d8f 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -186,17 +186,7 @@ V4_ASSERT_IS_TRIVIAL(CatchContext) DECLARE_HEAP_OBJECT(WithContext, ExecutionContext) { DECLARE_MARK_TABLE(WithContext); - void init(ExecutionContext *outerContext, Object *with) - { - Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_WithContext); - outer.set(engine, outerContext); - callData = outer->callData; - lookups = outer->lookups; - constantTable = outer->constantTable; - compilationUnit = outer->compilationUnit; - - withObject.set(engine, with); - } + void init(ExecutionContext *outerContext, Object *with); }; V4_ASSERT_IS_TRIVIAL(WithContext) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 02cd19008a..ab5ced9f58 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -130,9 +130,7 @@ QQmlEngine *ExecutionEngine::qmlEngine() const qint32 ExecutionEngine::maxCallDepth = -1; ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) - : current(0) - , hasException(false) - , callDepth(0) + : callDepth(0) , memoryManager(new QV4::MemoryManager(this)) , executableAllocator(new QV4::ExecutableAllocator) , regExpAllocator(new QV4::ExecutableAllocator) @@ -151,6 +149,8 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) , m_profiler(0) #endif { + writeBarrierActive = true; + if (maxCallDepth == -1) { bool ok = false; maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 2ac3a77e29..6de087a4e2 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -88,7 +88,7 @@ struct CompilationUnit; struct InternalClass; struct InternalClassPool; -struct Q_QML_EXPORT ExecutionEngine +struct Q_QML_EXPORT ExecutionEngine : public EngineBase { private: static qint32 maxCallDepth; @@ -97,12 +97,6 @@ private: friend struct ExecutionContext; friend struct Heap::ExecutionContext; public: - Heap::ExecutionContext *current; - - Value *jsStackTop; - quint8 hasException; - quint8 writeBarrierActive = false; - quint16 unused = 0; qint32 callDepth; MemoryManager *memoryManager; diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 9fc11a2d2d..11d7767e05 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -772,7 +772,7 @@ void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Va { Object *o = object.as(); if (o && o->internalClass() == l->classList[0]) { - o->setProperty(l->index, value); + o->setProperty(engine, l->index, value); return; } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index c0169ed035..df9d68525d 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -204,6 +204,8 @@ struct Q_QML_EXPORT Object: Managed { void setProperty(uint index, const Property *p); void setProperty(uint index, Value v) const { d()->setProperty(engine(), index, v); } void setProperty(uint index, Heap::Base *b) const { d()->setProperty(engine(), index, b); } + void setProperty(ExecutionEngine *engine, uint index, Value v) const { d()->setProperty(engine, index, v); } + void setProperty(ExecutionEngine *engine, uint index, Heap::Base *b) const { d()->setProperty(engine, index, b); } const ObjectVTable *vtable() const { return reinterpret_cast(d()->vtable()); } Heap::Object *prototype() const { return d()->prototype; } diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index bcd1af7705..7bedd705f9 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -113,6 +113,12 @@ struct Q_QML_EXPORT Base { Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase())); return Chunk::setBit(c->blackBitmap, h - c->realBase()); } + inline void setGrayBit() { + const HeapItem *h = reinterpret_cast(this); + Chunk *c = h->chunk(); + Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase())); + return Chunk::setBit(c->grayBitmap, h - c->realBase()); + } inline bool inUse() const { const HeapItem *h = reinterpret_cast(this); diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index f42d509942..8f4f2f4aa8 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -251,7 +251,9 @@ void Chunk::sweep() // DEBUG << "sweeping chunk" << this << (*freeList); HeapItem *o = realBase(); for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) { +#if WRITEBARRIER(none) Q_ASSERT((grayBitmap[i] | blackBitmap[i]) == blackBitmap[i]); // check that we don't have gray only objects +#endif quintptr toFree = objectBitmap[i] ^ blackBitmap[i]; Q_ASSERT((toFree & objectBitmap[i]) == toFree); // check all black objects are marked as being used quintptr e = extendsBitmap[i]; diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 6e9303acb6..3e542b0aa3 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -80,27 +80,28 @@ struct StackAllocator { StackAllocator(ChunkAllocator *chunkAlloc); T *allocate() { - T *m = nextFree->as(); + HeapItem *m = nextFree; if (Q_UNLIKELY(nextFree == lastInChunk)) { nextChunk(); } else { nextFree += requiredSlots; } -#if MM_DEBUG +#if !defined(QT_NO_DEBUG) || defined(MM_DEBUG) Chunk *c = m->chunk(); Chunk::setBit(c->objectBitmap, m - c->realBase()); #endif - return m; + return m->as(); } void free() { -#if MM_DEBUG - Chunk::clearBit(item->chunk()->objectBitmap, item - item->chunk()->realBase()); -#endif if (Q_UNLIKELY(nextFree == firstInChunk)) { prevChunk(); } else { nextFree -= requiredSlots; } +#if !defined(QT_NO_DEBUG) || defined(MM_DEBUG) + Chunk *c = nextFree->chunk(); + Chunk::clearBit(c->objectBitmap, nextFree - c->realBase()); +#endif } void nextChunk(); diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index 3f65e97d86..987e669040 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -255,6 +255,17 @@ Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize); Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits); Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits); +// Base class for the execution engine + +struct EngineBase { + Heap::ExecutionContext *current = 0; + + Value *jsStackTop = 0; + quint8 hasException = false; + quint8 writeBarrierActive = false; + quint16 unused = 0; +}; + // Some helper classes and macros to automate the generation of our // tables used for marking objects diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h index c0f508f962..838ed7a456 100644 --- a/src/qml/memory/qv4writebarrier_p.h +++ b/src/qml/memory/qv4writebarrier_p.h @@ -55,6 +55,11 @@ QT_BEGIN_NAMESPACE +#define WRITEBARRIER_steele -1 +#define WRITEBARRIER_none 1 + +#define WRITEBARRIER(x) (1/WRITEBARRIER_##x == 1) + namespace QV4 { namespace WriteBarrier { @@ -64,20 +69,79 @@ enum Type { Barrier }; -inline void write(QV4::ExecutionEngine *engine, QV4::Heap::Base *base, QV4::Value *slot, QV4::Value value) +enum NewValueType { + Primitive, + Object, + Unknown +}; + +// ### this needs to be filled with a real memory fence once marking is concurrent +Q_ALWAYS_INLINE void fence() {} + +#if WRITEBARRIER(steele) + +template +static Q_CONSTEXPR inline bool isRequired() { + return type != Primitive; +} + +inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Value value) +{ + *slot = value; + if (engine->writeBarrierActive && isRequired()) { + fence(); + base->setGrayBit(); + } +} + +inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Heap::Base *value) +{ + *slot = value; + if (engine->writeBarrierActive && isRequired()) { + fence(); + base->setGrayBit(); + } +} + +inline void write(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value) +{ + *slot = value; + if (engine->writeBarrierActive) { + fence(); + base->setGrayBit(); + } +} + +#elif WRITEBARRIER(none) + +template +static Q_CONSTEXPR inline bool isRequired() { + return false; +} + +inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Value value) +{ + Q_UNUSED(engine); + Q_UNUSED(base); + *slot = value; +} + +inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Heap::Base *value) { Q_UNUSED(engine); Q_UNUSED(base); *slot = value; } -inline void write(QV4::ExecutionEngine *engine, QV4::Heap::Base *base, QV4::Heap::Base **slot, QV4::Heap::Base *value) +inline void write(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value) { Q_UNUSED(engine); Q_UNUSED(base); *slot = value; } +#endif + } namespace Heap { @@ -88,9 +152,14 @@ struct Pointer { T operator->() const { return ptr; } operator T () const { return ptr; } + Heap::Base *base() { + Heap::Base *base = reinterpret_cast(this) - (offset/sizeof(Heap::Base)); + Q_ASSERT(base->inUse()); + return base; + } + void set(ExecutionEngine *e, T newVal) { - Q_UNUSED(e); - ptr = newVal; + WriteBarrier::write(e, base(), reinterpret_cast(&ptr), reinterpret_cast(newVal)); } template @@ -106,9 +175,14 @@ V4_ASSERT_IS_TRIVIAL(V4PointerCheck) template struct HeapValue : Value { + Heap::Base *base() { + Heap::Base *base = reinterpret_cast(this) - (offset/sizeof(Heap::Base)); + Q_ASSERT(base->inUse()); + return base; + } + void set(ExecutionEngine *e, const Value &newVal) { - Q_UNUSED(e); - setRawValue(newVal.rawValue()); + WriteBarrier::write(e, base(), this, newVal); } }; @@ -118,15 +192,17 @@ struct ValueArray { uint alloc; Value values[1]; + Heap::Base *base() { + Heap::Base *base = reinterpret_cast(this) - (offset/sizeof(Heap::Base)); + Q_ASSERT(base->inUse()); + return base; + } + void set(ExecutionEngine *e, uint index, Value v) { - Q_UNUSED(e); - Q_ASSERT(index < alloc); - values[index] = v; + WriteBarrier::write(e, base(), values + index, v); } void set(ExecutionEngine *e, uint index, Heap::Base *b) { - Q_UNUSED(e); - Q_ASSERT(index < alloc); - values[index] = b; + WriteBarrier::write(e, base(), values + index, b); } inline const Value &operator[] (uint index) const { Q_ASSERT(index < alloc); -- cgit v1.2.3 From e772081db104e09e95ed09e8d1f0076e07fc53f6 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 15 Feb 2017 15:40:27 +0100 Subject: Incremental garbage collection Add an incremental mode to the garbage collector, that will get used for many collections. This should significantly reduce average stop times for GC. Make sure that manual calls to gc() still do a full collection, to ensure consistency and keep tests that rely on gc() working. Change-Id: I87b13529377b7639ce993dbd99e85ff0a555acd8 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4compileddata.cpp | 13 ++- src/qml/jsapi/qjsengine.cpp | 2 +- src/qml/jsruntime/qv4engine.cpp | 28 +++--- src/qml/jsruntime/qv4engine_p.h | 2 +- src/qml/jsruntime/qv4identifiertable.cpp | 1 + src/qml/memory/qv4mm.cpp | 153 +++++++++++++++++++++++++++++-- src/qml/memory/qv4mm_p.h | 7 +- src/qml/memory/qv4mmdefs_p.h | 2 + src/qml/memory/qv4writebarrier_p.h | 17 ++-- src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 2 +- 10 files changed, 192 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index c25a139379..d0dfb81f80 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -132,8 +132,10 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) runtimeStrings = (QV4::Heap::String **)malloc(data->stringTableSize * sizeof(QV4::Heap::String*)); // memset the strings to 0 in case a GC run happens while we're within the loop below memset(runtimeStrings, 0, data->stringTableSize * sizeof(QV4::Heap::String*)); - for (uint i = 0; i < data->stringTableSize; ++i) + for (uint i = 0; i < data->stringTableSize; ++i) { runtimeStrings[i] = engine->newIdentifier(data->stringAt(i)); + runtimeStrings[i]->setMarkBit(); + } runtimeRegularExpressions = new QV4::Value[data->regexpTableSize]; // memset the regexps to 0 in case a GC run happens while we're within the loop below @@ -147,7 +149,14 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) flags |= IR::RegExp::RegExp_IgnoreCase; if (re->flags & CompiledData::RegExp::RegExp_Multiline) flags |= IR::RegExp::RegExp_Multiline; - runtimeRegularExpressions[i] = engine->newRegExpObject(data->stringAt(re->stringIndex), flags); + QV4::Heap::RegExpObject *ro = engine->newRegExpObject(data->stringAt(re->stringIndex), flags); + runtimeRegularExpressions[i] = ro; +#if WRITEBARRIER(steele) + if (engine->memoryManager->nextGCIsIncremental) { + ro->setMarkBit(); + ro->setGrayBit(); + } +#endif } if (data->lookupTableSize) { diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index e4c150057a..b52c859ecb 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -333,7 +333,7 @@ QJSEngine::~QJSEngine() */ void QJSEngine::collectGarbage() { - d->m_v4Engine->memoryManager->runGC(); + d->m_v4Engine->memoryManager->runGC(/* forceFullCollection = */ true); } #if QT_DEPRECATED_SINCE(5, 6) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index ab5ced9f58..899fd499df 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -931,23 +931,25 @@ void ExecutionEngine::requireArgumentsAccessors(int n) } } -void ExecutionEngine::markObjects() +void ExecutionEngine::markObjects(bool incremental) { - identifierTable->mark(this); + if (!incremental) { + identifierTable->mark(this); - for (int i = 0; i < nArgumentsAccessors; ++i) { - const Property &pd = argumentsAccessors[i]; - if (Heap::FunctionObject *getter = pd.getter()) - getter->mark(this); - if (Heap::FunctionObject *setter = pd.setter()) - setter->mark(this); - } + for (int i = 0; i < nArgumentsAccessors; ++i) { + const Property &pd = argumentsAccessors[i]; + if (Heap::FunctionObject *getter = pd.getter()) + getter->mark(this); + if (Heap::FunctionObject *setter = pd.setter()) + setter->mark(this); + } - classPool->markObjects(this); + classPool->markObjects(this); - for (QSet::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd(); - it != end; ++it) - (*it)->markObjects(this); + for (QSet::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd(); + it != end; ++it) + (*it)->markObjects(this); + } } ReturnedValue ExecutionEngine::throwError(const Value &value) diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 6de087a4e2..395a7c7250 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -450,7 +450,7 @@ public: void requireArgumentsAccessors(int n); - void markObjects(); + void markObjects(bool incremental); void initRootContext(); diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp index 3def6defbf..d3ef238716 100644 --- a/src/qml/jsruntime/qv4identifiertable.cpp +++ b/src/qml/jsruntime/qv4identifiertable.cpp @@ -81,6 +81,7 @@ void IdentifierTable::addEntry(Heap::String *str) str->identifier = new Identifier; str->identifier->string = str->toQString(); str->identifier->hashValue = hash; + str->setMarkBit(); bool grow = (alloc <= size*2); diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 8f4f2f4aa8..f3ee397d22 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -282,7 +282,7 @@ void Chunk::sweep() } } objectBitmap[i] = blackBitmap[i]; - blackBitmap[i] = 0; + grayBitmap[i] = 0; extendsBitmap[i] = e; o += Chunk::Bits; } @@ -321,13 +321,56 @@ void Chunk::freeAll() } } objectBitmap[i] = 0; - blackBitmap[i] = 0; + grayBitmap[i] = 0; extendsBitmap[i] = e; o += Chunk::Bits; } // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots."; } +void Chunk::resetBlackBits() +{ + memset(blackBitmap, 0, sizeof(blackBitmap)); +} + +#ifndef QT_NO_DEBUG +static uint nGrayItems = 0; +#endif + +void Chunk::collectGrayItems(ExecutionEngine *engine) +{ + // DEBUG << "sweeping chunk" << this << (*freeList); + HeapItem *o = realBase(); + for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) { +#if WRITEBARRIER(none) + Q_ASSERT((grayBitmap[i] | blackBitmap[i]) == blackBitmap[i]); // check that we don't have gray only objects +#endif + quintptr toMark = blackBitmap[i] & grayBitmap[i]; // correct for a Steele type barrier + Q_ASSERT((toMark & objectBitmap[i]) == toMark); // check all black objects are marked as being used + // DEBUG << hex << " index=" << i << toFree; + while (toMark) { + uint index = qCountTrailingZeroBits(toMark); + quintptr bit = (static_cast(1) << index); + + toMark ^= bit; // mask out marked slot + // DEBUG << " index" << hex << index << toFree; + + HeapItem *itemToFree = o + index; + Heap::Base *b = *itemToFree; + Q_ASSERT(b->inUse()); + engine->pushForGC(b); +#ifndef QT_NO_DEBUG + ++nGrayItems; +// qDebug() << "adding gray item" << b << "to mark stack"; +#endif + } + grayBitmap[i] = 0; + o += Chunk::Bits; + } + // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots."; + +} + void Chunk::sortIntoBins(HeapItem **bins, uint nBins) { // qDebug() << "sortIntoBins:"; @@ -557,6 +600,19 @@ void BlockAllocator::freeAll() } } +void BlockAllocator::resetBlackBits() +{ + for (auto c : chunks) + c->resetBlackBits(); +} + +void BlockAllocator::collectGrayItems(ExecutionEngine *engine) +{ + for (auto c : chunks) + c->collectGrayItems(engine); + +} + #if MM_DEBUG void BlockAllocator::stats() { DEBUG << "MM stats:"; @@ -609,7 +665,6 @@ static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocato void HugeItemAllocator::sweep() { auto isBlack = [this] (const HugeChunk &c) { bool b = c.chunk->first()->isBlack(); - Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase()); if (!b) freeHugeChunk(chunkAllocator, c); return !b; @@ -619,6 +674,24 @@ void HugeItemAllocator::sweep() { chunks.erase(newEnd, chunks.end()); } +void HugeItemAllocator::resetBlackBits() +{ + for (auto c : chunks) + Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase()); +} + +void HugeItemAllocator::collectGrayItems(ExecutionEngine *engine) +{ + for (auto c : chunks) + // Correct for a Steele type barrier + if (Chunk::testBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase()) && + Chunk::testBit(c.chunk->grayBitmap, c.chunk->first() - c.chunk->realBase())) { + HeapItem *i = c.chunk->first(); + Heap::Base *b = *i; + b->mark(engine); + } +} + void HugeItemAllocator::freeAll() { for (auto &c : chunks) { @@ -663,7 +736,8 @@ Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize) unmanagedHeapSize += unmanagedSize; if (unmanagedHeapSize > unmanagedHeapSizeGCLimit) { - runGC(); + if (!didGCRun) + runGC(); if (3*unmanagedHeapSizeGCLimit <= 4*unmanagedHeapSize) // more than 75% full, raise limit @@ -681,6 +755,7 @@ Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize) m = blockAllocator.allocate(stringSize, true); } +// qDebug() << "allocated string" << m; memset(m, 0, stringSize); return *m; } @@ -705,8 +780,11 @@ Heap::Base *MemoryManager::allocData(std::size_t size) // qDebug() << "unmanagedHeapSize:" << unmanagedHeapSize << "limit:" << unmanagedHeapSizeGCLimit << "unmanagedSize:" << unmanagedSize; - if (size > Chunk::DataSize) - return *hugeItemAllocator.allocate(size); + if (size > Chunk::DataSize) { + HeapItem *h = hugeItemAllocator.allocate(size); +// qDebug() << "allocating huge item" << h; + return *h; + } HeapItem *m = blockAllocator.allocate(size); if (!m) { @@ -716,6 +794,7 @@ Heap::Base *MemoryManager::allocData(std::size_t size) } memset(m, 0, size); +// qDebug() << "allocating data" << m; return *m; } @@ -740,6 +819,7 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nM o->memberData->init(); // qDebug() << " got" << o->memberData << o->memberData->size; } +// qDebug() << "allocating object with memberData" << o << o->memberData.operator->(); return o; } @@ -794,7 +874,13 @@ void MemoryManager::mark() { Value *markBase = engine->jsStackTop; - engine->markObjects(); + if (nextGCIsIncremental) { + // need to collect all gray items and push them onto the mark stack + blockAllocator.collectGrayItems(engine); + hugeItemAllocator.collectGrayItems(engine); + } + + engine->markObjects(nextGCIsIncremental); collectFromJSStack(); @@ -836,6 +922,12 @@ void MemoryManager::mark() void MemoryManager::sweep(bool lastSweep) { + if (lastSweep && nextGCIsIncremental) { + // ensure we properly clean up on destruction even if the GC is in incremental mode + blockAllocator.resetBlackBits(); + hugeItemAllocator.resetBlackBits(); + } + for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) { Managed *m = (*it).managed(); if (!m || m->markBit()) @@ -915,14 +1007,22 @@ size_t dumpBins(BlockAllocator *b, bool printOutput = true) return totalFragmentedSlots*Chunk::SlotSize; } -void MemoryManager::runGC() +void MemoryManager::runGC(bool forceFullCollection) { if (gcBlocked) { // qDebug() << "Not running GC."; return; } + if (forceFullCollection) { + // do a full GC + blockAllocator.resetBlackBits(); + hugeItemAllocator.resetBlackBits(); + nextGCIsIncremental = false; + } + QScopedValueRollback gcBlocker(gcBlocked, true); +// qDebug() << "runGC"; if (!gcStats) { // uint oldUsed = allocator.usedMem(); @@ -940,10 +1040,15 @@ void MemoryManager::runGC() #ifndef QT_NO_DEBUG qDebug() << " Triggered by alloc request of" << lastAllocRequestedSlots << "slots."; #endif + qDebug() << "Incremental:" << nextGCIsIncremental; qDebug() << "Allocated" << totalMem << "bytes in" << blockAllocator.chunks.size() << "chunks"; qDebug() << "Fragmented memory before GC" << (totalMem - usedBefore); dumpBins(&blockAllocator); +#ifndef QT_NO_DEBUG + nGrayItems = 0; +#endif + QElapsedTimer t; t.start(); mark(); @@ -960,6 +1065,10 @@ void MemoryManager::runGC() qDebug() << " unmanaged heap limit:" << unmanagedHeapSizeGCLimit; } size_t memInBins = dumpBins(&blockAllocator); +#ifndef QT_NO_DEBUG + if (nextGCIsIncremental) + qDebug() << " number of gray items:" << nGrayItems; +#endif qDebug() << "Marked object in" << markTime << "ms."; qDebug() << "Sweeped object in" << sweepTime << "ms."; qDebug() << "Used memory before GC:" << usedBefore; @@ -980,6 +1089,34 @@ void MemoryManager::runGC() // ensure we don't 'loose' any memory Q_ASSERT(blockAllocator.allocatedMem() == getUsedMem() + dumpBins(&blockAllocator, false)); } + +#if WRITEBARRIER(steele) + static int count = 0; + ++count; + if (aggressiveGC) { + nextGCIsIncremental = (count % 256); + } else { + size_t total = blockAllocator.totalSlots(); + size_t usedSlots = blockAllocator.usedSlotsAfterLastSweep; + if (!nextGCIsIncremental) { + // always try an incremental GC after a full one, unless there is anyway lots of memory pressure + nextGCIsIncremental = usedSlots * 4 < total * 3; + count = 0; + } else { + if (count > 16) + nextGCIsIncremental = false; + else + nextGCIsIncremental = usedSlots * 4 < total * 3; // less than 75% full + } + } +#else + nextGCIsIncremental = false; +#endif + if (!nextGCIsIncremental) { + // do a full GC + blockAllocator.resetBlackBits(); + hugeItemAllocator.resetBlackBits(); + } } size_t MemoryManager::getUsedMem() const diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 3e542b0aa3..f91175e78a 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -155,6 +155,8 @@ struct BlockAllocator { void sweep(); void freeAll(); + void resetBlackBits(); + void collectGrayItems(ExecutionEngine *engine); // bump allocations HeapItem *nextFree = 0; @@ -176,6 +178,8 @@ struct HugeItemAllocator { HeapItem *allocate(size_t size); void sweep(); void freeAll(); + void resetBlackBits(); + void collectGrayItems(ExecutionEngine *engine); size_t usedMem() const { size_t used = 0; @@ -418,7 +422,7 @@ public: return t->d(); } - void runGC(); + void runGC(bool forceFullCollection = false); void dumpStats() const; @@ -463,6 +467,7 @@ public: bool gcBlocked = false; bool aggressiveGC = false; bool gcStats = false; + bool nextGCIsIncremental = false; }; } diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index 987e669040..75f567b9e5 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -176,6 +176,8 @@ struct Chunk { void sweep(); void freeAll(); + void resetBlackBits(); + void collectGrayItems(ExecutionEngine *engine); void sortIntoBins(HeapItem **bins, uint nBins); }; diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h index 838ed7a456..de9c63c2ea 100644 --- a/src/qml/memory/qv4writebarrier_p.h +++ b/src/qml/memory/qv4writebarrier_p.h @@ -55,8 +55,8 @@ QT_BEGIN_NAMESPACE -#define WRITEBARRIER_steele -1 -#define WRITEBARRIER_none 1 +#define WRITEBARRIER_steele 1 +#define WRITEBARRIER_none -1 #define WRITEBARRIER(x) (1/WRITEBARRIER_##x == 1) @@ -87,8 +87,9 @@ static Q_CONSTEXPR inline bool isRequired() { inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Value value) { + Q_UNUSED(engine); *slot = value; - if (engine->writeBarrierActive && isRequired()) { + if (isRequired()) { fence(); base->setGrayBit(); } @@ -96,8 +97,9 @@ inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Value value inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Heap::Base *value) { + Q_UNUSED(engine); *slot = value; - if (engine->writeBarrierActive && isRequired()) { + if (isRequired()) { fence(); base->setGrayBit(); } @@ -105,11 +107,10 @@ inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Heap::Base inline void write(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value) { + Q_UNUSED(engine); *slot = value; - if (engine->writeBarrierActive) { - fence(); - base->setGrayBit(); - } + fence(); + base->setGrayBit(); } #elif WRITEBARRIER(none) diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index d359a0f62f..ec40c7846d 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -2019,7 +2019,7 @@ void GlobalExtensions::method_qsTrIdNoOp(const BuiltinFunction *, Scope &scope, void GlobalExtensions::method_gc(const BuiltinFunction *, Scope &scope, CallData *) { - scope.engine->memoryManager->runGC(); + scope.engine->memoryManager->runGC(/* forceFullCollection = */ true); scope.result = QV4::Encode::undefined(); } -- cgit v1.2.3 From 922057ee27127529d755b40bde6113372abc7263 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 13 Feb 2017 13:38:48 +0100 Subject: Better MM debugging Add some more verbose debugging output when we're not using a release build. Change-Id: I4fec5991263e970899a4cc33f9551f4abb21f5ea Reviewed-by: Simon Hausmann --- src/qml/memory/qv4mm.cpp | 69 +++++++++++++++++++++++++++++++++--------------- src/qml/memory/qv4mm_p.h | 4 +-- 2 files changed, 49 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index f3ee397d22..9c7915d2c3 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -60,7 +60,11 @@ #include "qv4alloca_p.h" #include "qv4profiling_p.h" -#define MM_DEBUG 0 +//#define MM_STATS + +#if !defined(MM_STATS) && !defined(QT_NO_DEBUG) +#define MM_STATS +#endif #if MM_DEBUG #define DEBUG qDebug() << "MM:" @@ -333,7 +337,7 @@ void Chunk::resetBlackBits() memset(blackBitmap, 0, sizeof(blackBitmap)); } -#ifndef QT_NO_DEBUG +#ifdef MM_STATS static uint nGrayItems = 0; #endif @@ -359,7 +363,7 @@ void Chunk::collectGrayItems(ExecutionEngine *engine) Heap::Base *b = *itemToFree; Q_ASSERT(b->inUse()); engine->pushForGC(b); -#ifndef QT_NO_DEBUG +#ifdef MM_STATS ++nGrayItems; // qDebug() << "adding gray item" << b << "to mark stack"; #endif @@ -380,7 +384,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins) #else const int start = 1; #endif -#ifndef QT_NO_DEBUG +#ifdef MM_STATS uint freeSlots = 0; uint allocatedSlots = 0; #endif @@ -390,7 +394,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins) if (!i) usedSlots |= (static_cast(1) << (HeaderSize/SlotSize)) - 1; #endif -#ifndef QT_NO_DEBUG +#ifdef MM_STATS allocatedSlots += qPopulationCount(usedSlots); // qDebug() << hex << " i=" << i << "used=" << usedSlots; #endif @@ -407,7 +411,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins) break; } usedSlots = (objectBitmap[i]|extendsBitmap[i]); -#ifndef QT_NO_DEBUG +#ifdef MM_STATS allocatedSlots += qPopulationCount(usedSlots); // qDebug() << hex << " i=" << i << "used=" << usedSlots; #endif @@ -418,7 +422,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins) usedSlots |= (quintptr(1) << index) - 1; uint freeEnd = i*Bits + index; uint nSlots = freeEnd - freeStart; -#ifndef QT_NO_DEBUG +#ifdef MM_STATS // qDebug() << hex << " got free slots from" << freeStart << "to" << freeEnd << "n=" << nSlots << "usedSlots=" << usedSlots; freeSlots += nSlots; #endif @@ -429,7 +433,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins) bins[bin] = freeItem; } } -#ifndef QT_NO_DEBUG +#ifdef MM_STATS Q_ASSERT(freeSlots + allocatedSlots == (EntriesInBitmap - start) * 8 * sizeof(quintptr)); #endif } @@ -717,15 +721,17 @@ MemoryManager::MemoryManager(ExecutionEngine *engine) #endif } -#ifndef QT_NO_DEBUG -static size_t lastAllocRequestedSlots = 0; +#ifdef MM_STATS +static int allocationCount = 0; +static int lastAllocRequestedSlots = 0; #endif Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize) { const size_t stringSize = align(sizeof(Heap::String)); -#ifndef QT_NO_DEBUG +#ifdef MM_STATS lastAllocRequestedSlots = stringSize >> Chunk::SlotSizeShift; + ++allocationCount; #endif bool didGCRun = false; @@ -762,8 +768,9 @@ Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize) Heap::Base *MemoryManager::allocData(std::size_t size) { -#ifndef QT_NO_DEBUG +#ifdef MM_STATS lastAllocRequestedSlots = size >> Chunk::SlotSizeShift; + ++allocationCount; #endif bool didRunGC = false; @@ -804,6 +811,9 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nM // ### Could optimize this and allocate both in one go through the block allocator if (nMembers) { +#ifdef MM_STATS + ++allocationCount; +#endif std::size_t memberSize = align(sizeof(Heap::MemberData) + (nMembers - 1)*sizeof(Value)); // qDebug() << "allocating member data for" << o << nMembers << memberSize; Heap::Base *m; @@ -823,10 +833,13 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nM return o; } +static uint markStackSize = 0; + void MemoryManager::drainMarkStack(Value *markBase) { while (engine->jsStackTop > markBase) { Heap::Base *h = engine->popForGC(); + ++markStackSize; Q_ASSERT(h); // at this point we should only have Heap::Base objects in this area on the stack. If not, weird things might happen. if (h->vtable()->markObjects) h->vtable()->markObjects(h, engine); @@ -874,18 +887,28 @@ void MemoryManager::mark() { Value *markBase = engine->jsStackTop; + markStackSize = 0; + if (nextGCIsIncremental) { // need to collect all gray items and push them onto the mark stack blockAllocator.collectGrayItems(engine); hugeItemAllocator.collectGrayItems(engine); } +// qDebug() << ">>>> Mark phase:"; +// qDebug() << " mark stack after gray items" << (engine->jsStackTop - markBase); + engine->markObjects(nextGCIsIncremental); +// qDebug() << " mark stack after engine->mark" << (engine->jsStackTop - markBase); + collectFromJSStack(); +// qDebug() << " mark stack after js stack collect" << (engine->jsStackTop - markBase); m_persistentValues->mark(engine); +// qDebug() << " mark stack after persistants" << (engine->jsStackTop - markBase); + // Preserve QObject ownership rules within JavaScript: A parent with c++ ownership // keeps all of its children alive in JavaScript. @@ -988,23 +1011,23 @@ bool MemoryManager::shouldRunGC() const size_t dumpBins(BlockAllocator *b, bool printOutput = true) { - size_t totalFragmentedSlots = 0; + size_t totalSlotMem = 0; if (printOutput) - qDebug() << "Fragmentation map:"; + qDebug() << "Slot map:"; for (uint i = 0; i < BlockAllocator::NumBins; ++i) { uint nEntries = 0; HeapItem *h = b->freeBins[i]; while (h) { ++nEntries; - totalFragmentedSlots += h->freeData.availableSlots; + totalSlotMem += h->freeData.availableSlots; h = h->freeData.next; } if (printOutput) qDebug() << " number of entries in slot" << i << ":" << nEntries; } if (printOutput) - qDebug() << " total mem in bins" << totalFragmentedSlots*Chunk::SlotSize; - return totalFragmentedSlots*Chunk::SlotSize; + qDebug() << " total mem in bins" << totalSlotMem*Chunk::SlotSize; + return totalSlotMem*Chunk::SlotSize; } void MemoryManager::runGC(bool forceFullCollection) @@ -1037,15 +1060,16 @@ void MemoryManager::runGC(bool forceFullCollection) const size_t largeItemsBefore = getLargeItemsMem(); qDebug() << "========== GC =========="; -#ifndef QT_NO_DEBUG +#ifdef MM_STATS qDebug() << " Triggered by alloc request of" << lastAllocRequestedSlots << "slots."; + qDebug() << " Allocations since last GC" << allocationCount; #endif qDebug() << "Incremental:" << nextGCIsIncremental; qDebug() << "Allocated" << totalMem << "bytes in" << blockAllocator.chunks.size() << "chunks"; qDebug() << "Fragmented memory before GC" << (totalMem - usedBefore); dumpBins(&blockAllocator); -#ifndef QT_NO_DEBUG +#ifdef MM_STATS nGrayItems = 0; #endif @@ -1065,15 +1089,16 @@ void MemoryManager::runGC(bool forceFullCollection) qDebug() << " unmanaged heap limit:" << unmanagedHeapSizeGCLimit; } size_t memInBins = dumpBins(&blockAllocator); -#ifndef QT_NO_DEBUG +#ifdef MM_STATS if (nextGCIsIncremental) qDebug() << " number of gray items:" << nGrayItems; #endif qDebug() << "Marked object in" << markTime << "ms."; + qDebug() << " " << markStackSize << "objects marked"; qDebug() << "Sweeped object in" << sweepTime << "ms."; qDebug() << "Used memory before GC:" << usedBefore; - qDebug() << "Used memory after GC:" << usedAfter; - qDebug() << "Freed up bytes:" << (usedBefore - usedAfter); + qDebug() << "Used memory after GC :" << usedAfter; + qDebug() << "Freed up bytes :" << (usedBefore - usedAfter); size_t lost = blockAllocator.allocatedMem() - memInBins - usedAfter; if (lost) qDebug() << "!!!!!!!!!!!!!!!!!!!!! LOST MEM:" << lost << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index f91175e78a..437e50cbe7 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -86,7 +86,7 @@ struct StackAllocator { } else { nextFree += requiredSlots; } -#if !defined(QT_NO_DEBUG) || defined(MM_DEBUG) +#if MM_DEBUG || !defined(QT_NO_DEBUG) Chunk *c = m->chunk(); Chunk::setBit(c->objectBitmap, m - c->realBase()); #endif @@ -98,7 +98,7 @@ struct StackAllocator { } else { nextFree -= requiredSlots; } -#if !defined(QT_NO_DEBUG) || defined(MM_DEBUG) +#if MM_DEBUG || !defined(QT_NO_DEBUG) Chunk *c = nextFree->chunk(); Chunk::clearBit(c->objectBitmap, nextFree - c->realBase()); #endif -- cgit v1.2.3 From da32817db4b012e54be8ff43b5e56d676ec7b5bb Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 14 Feb 2017 22:47:36 +0100 Subject: Optimize Base::mark() Change-Id: I7f7b485274c870b39492eb9446d910d35f960124 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4engine_p.h | 16 +++++++++++----- src/qml/memory/qv4mmdefs_p.h | 19 +++++++++++++------ 2 files changed, 24 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 395a7c7250..21b61a5aff 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -550,13 +550,19 @@ inline void Heap::Base::mark(QV4::ExecutionEngine *engine) { Q_ASSERT(inUse()); - if (isMarked()) - return; + const HeapItem *h = reinterpret_cast(this); + Chunk *c = h->chunk(); + size_t index = h - c->realBase(); + Q_ASSERT(!Chunk::testBit(c->extendsBitmap, index)); + quintptr *bitmap = c->blackBitmap + Chunk::bitmapIndex(index); + quintptr bit = Chunk::bitForIndex(index); + if (!(*bitmap & bit)) { #ifndef QT_NO_DEBUG - engine->assertObjectBelongsToEngine(*this); + engine->assertObjectBelongsToEngine(*this); #endif - setMarkBit(); - engine->pushForGC(this); + *bitmap |= bit; + engine->pushForGC(this); + } } inline void Value::mark(ExecutionEngine *e) diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index 75f567b9e5..f66630061d 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -111,22 +111,29 @@ struct Chunk { HeapItem *realBase(); HeapItem *first(); + static Q_ALWAYS_INLINE size_t bitmapIndex(size_t index) { + return index >> BitShift; + } + static Q_ALWAYS_INLINE quintptr bitForIndex(size_t index) { + return static_cast(1) << (index & (Bits - 1)); + } + static void setBit(quintptr *bitmap, size_t index) { // Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize); - bitmap += index >> BitShift; - quintptr bit = static_cast(1) << (index & (Bits - 1)); + bitmap += bitmapIndex(index); + quintptr bit = bitForIndex(index); *bitmap |= bit; } static void clearBit(quintptr *bitmap, size_t index) { // Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize); - bitmap += index >> BitShift; - quintptr bit = static_cast(1) << (index & (Bits - 1)); + bitmap += bitmapIndex(index); + quintptr bit = bitForIndex(index); *bitmap &= ~bit; } static bool testBit(quintptr *bitmap, size_t index) { // Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize); - bitmap += index >> BitShift; - quintptr bit = static_cast(1) << (index & (Bits - 1)); + bitmap += bitmapIndex(index); + quintptr bit = bitForIndex(index); return (*bitmap & bit); } static void setBits(quintptr *bitmap, size_t index, size_t nBits) { -- cgit v1.2.3 From 0bee9b94eb20d644a1df4fd0062527e680545f31 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 15 Feb 2017 12:21:36 +0100 Subject: Micro optimization the value that is being removed from the stack when popForGC() is being called will always be a valid Heap object, so we can use the unsafe accessor instead of the slower one that checks. Change-Id: I23d435c760d3ac7ba8ca28e46bdcbe36886f0dd9 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4engine_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 21b61a5aff..18571d88f2 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -122,7 +122,7 @@ public: } Heap::Base *popForGC() { --jsStackTop; - return jsStackTop->heapObject(); + return jsStackTop->m(); } QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) { -- cgit v1.2.3 From a10f1b1e4ac8072a733bebcde7f4aafcdd54c126 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 15 Feb 2017 12:23:20 +0100 Subject: Optimize allocObjectWithMemberData Use only one call into the block allocator in the common case. Change-Id: Ic9be82f03ba66c1eff3e27407458343b6cd6d30c Reviewed-by: Simon Hausmann --- src/qml/memory/qv4mm.cpp | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 9c7915d2c3..069084763c 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -807,26 +807,33 @@ Heap::Base *MemoryManager::allocData(std::size_t size) Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nMembers) { - Heap::Object *o = static_cast(allocData(size)); - - // ### Could optimize this and allocate both in one go through the block allocator - if (nMembers) { -#ifdef MM_STATS - ++allocationCount; -#endif + Heap::Object *o; + if (!nMembers) { + o = static_cast(allocData(size)); + } else { + // Allocate both in one go through the block allocator std::size_t memberSize = align(sizeof(Heap::MemberData) + (nMembers - 1)*sizeof(Value)); -// qDebug() << "allocating member data for" << o << nMembers << memberSize; - Heap::Base *m; - if (memberSize > Chunk::DataSize) - m = *hugeItemAllocator.allocate(memberSize); - else - m = *blockAllocator.allocate(memberSize, true); - memset(m, 0, memberSize); - o->memberData.set(engine, static_cast(m)); - o->memberData->setVtable(MemberData::staticVTable()); - o->memberData->values.alloc = static_cast((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); - o->memberData->values.size = o->memberData->values.alloc; - o->memberData->init(); + size_t totalSize = size + memberSize; + Heap::MemberData *m; + if (totalSize > Chunk::DataSize) { + o = static_cast(allocData(size)); + m = hugeItemAllocator.allocate(memberSize)->as(); + } else { + HeapItem *mh = reinterpret_cast(allocData(totalSize)); + Heap::Base *b = *mh; + o = static_cast(b); + mh += (size >> Chunk::SlotSizeShift); + m = mh->as(); + Chunk *c = mh->chunk(); + size_t index = mh - c->realBase(); + Chunk::setBit(c->objectBitmap, index); + Chunk::clearBit(c->extendsBitmap, index); + } + o->memberData.set(engine, m); + m->setVtable(MemberData::staticVTable()); + m->values.alloc = static_cast((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); + m->values.size = o->memberData->values.alloc; + m->init(); // qDebug() << " got" << o->memberData << o->memberData->size; } // qDebug() << "allocating object with memberData" << o << o->memberData.operator->(); @@ -1063,6 +1070,7 @@ void MemoryManager::runGC(bool forceFullCollection) #ifdef MM_STATS qDebug() << " Triggered by alloc request of" << lastAllocRequestedSlots << "slots."; qDebug() << " Allocations since last GC" << allocationCount; + allocationCount = 0; #endif qDebug() << "Incremental:" << nextGCIsIncremental; qDebug() << "Allocated" << totalMem << "bytes in" << blockAllocator.chunks.size() << "chunks"; -- cgit v1.2.3 From 78589bba88bcb3bce5a5996c762b324680d097a5 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 16 Feb 2017 10:25:52 +0100 Subject: Output mark/sweep times in micro seconds Change-Id: Iaef7f23c9a58f8df761a35ed0fa681f8b404a4a6 Reviewed-by: Simon Hausmann --- src/qml/memory/qv4mm.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 069084763c..233b83fcc0 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -1084,11 +1084,12 @@ void MemoryManager::runGC(bool forceFullCollection) QElapsedTimer t; t.start(); mark(); - qint64 markTime = t.restart(); + qint64 markTime = t.nsecsElapsed()/1000; + t.restart(); sweep(); const size_t usedAfter = getUsedMem(); const size_t largeItemsAfter = getLargeItemsMem(); - qint64 sweepTime = t.elapsed(); + qint64 sweepTime = t.nsecsElapsed()/1000; if (triggeredByUnmanagedHeap) { qDebug() << "triggered by unmanaged heap:"; @@ -1101,9 +1102,9 @@ void MemoryManager::runGC(bool forceFullCollection) if (nextGCIsIncremental) qDebug() << " number of gray items:" << nGrayItems; #endif - qDebug() << "Marked object in" << markTime << "ms."; + qDebug() << "Marked object in" << markTime << "us."; qDebug() << " " << markStackSize << "objects marked"; - qDebug() << "Sweeped object in" << sweepTime << "ms."; + qDebug() << "Sweeped object in" << sweepTime << "us."; qDebug() << "Used memory before GC:" << usedBefore; qDebug() << "Used memory after GC :" << usedAfter; qDebug() << "Freed up bytes :" << (usedBefore - usedAfter); -- cgit v1.2.3 From cb25abf2a818e76744426ff82619f7351132269f Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 16 Feb 2017 10:52:48 +0100 Subject: Don't grow GC memory after an incremental GC If the last GC was incremental, it would not clean up all garbage. Thus we should not look at the used memory after such a GC to determine whether we need to allocate additional memory. Change-Id: I57c33eeec63c16310920bc3dae074f4dcbb73d27 Reviewed-by: Simon Hausmann --- src/qml/memory/qv4mm.cpp | 6 ++++-- src/qml/memory/qv4mm_p.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 233b83fcc0..1a1d92aa0e 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -1010,8 +1010,7 @@ void MemoryManager::sweep(bool lastSweep) bool MemoryManager::shouldRunGC() const { size_t total = blockAllocator.totalSlots(); - size_t usedSlots = blockAllocator.usedSlotsAfterLastSweep; - if (total > MinSlotsGCLimit && usedSlots * GCOverallocation < total * 100) + if (total > MinSlotsGCLimit && usedSlotsAfterLastFullSweep * GCOverallocation < total * 100) return true; return false; } @@ -1124,6 +1123,9 @@ void MemoryManager::runGC(bool forceFullCollection) Q_ASSERT(blockAllocator.allocatedMem() == getUsedMem() + dumpBins(&blockAllocator, false)); } + if (!nextGCIsIncremental) + usedSlotsAfterLastFullSweep = blockAllocator.usedSlotsAfterLastSweep; + #if WRITEBARRIER(steele) static int count = 0; ++count; diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 437e50cbe7..7f02a4f929 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -463,6 +463,7 @@ public: std::size_t unmanagedHeapSize = 0; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items. std::size_t unmanagedHeapSizeGCLimit; + std::size_t usedSlotsAfterLastFullSweep = 0; bool gcBlocked = false; bool aggressiveGC = false; -- cgit v1.2.3 From 182469fc85257fccfa8024e132ad40a50b03c0f5 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Thu, 9 Mar 2017 13:59:40 +0100 Subject: Build fix for -no-feature-quick-shadereffect Change-Id: Ie1f601c6ae4c6c5d8d23b14a6670979d9c24e209 Reviewed-by: Simon Hausmann --- src/imports/imports.pro | 2 +- src/quick/items/context2d/qquickcanvasitem.cpp | 1 + src/quick/items/context2d/qquickcontext2d.cpp | 2 ++ src/quick/items/qquickpainteditem_p.h | 1 + src/quick/util/qquickanimatorjob.cpp | 3 ++- src/src.pro | 2 +- 6 files changed, 8 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/imports/imports.pro b/src/imports/imports.pro index 45719df874..0ba949f070 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -20,7 +20,7 @@ qtHaveModule(quick) { sharedimage \ testlib - qtConfig(quick-sprite):qtConfig(opengl(es1|es2)?): \ + qtConfig(quick-shadereffect):qtConfig(quick-sprite):qtConfig(opengl(es1|es2)?): \ SUBDIRS += particles } diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp index 1167f408f5..a81ab619ac 100644 --- a/src/quick/items/context2d/qquickcanvasitem.cpp +++ b/src/quick/items/context2d/qquickcanvasitem.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index e25cc5ccbe..0eeba5d6cd 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -42,7 +42,9 @@ #include "qquickcanvasitem_p.h" #include #include +#if QT_CONFIG(quick_shadereffect) #include +#endif #include #include diff --git a/src/quick/items/qquickpainteditem_p.h b/src/quick/items/qquickpainteditem_p.h index 742e786335..229fbf1007 100644 --- a/src/quick/items/qquickpainteditem_p.h +++ b/src/quick/items/qquickpainteditem_p.h @@ -52,6 +52,7 @@ // #include "qquickitem_p.h" +#include "qquickpainteditem.h" #include QT_BEGIN_NAMESPACE diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp index 4aacb09c97..89007cff1f 100644 --- a/src/quick/util/qquickanimatorjob.cpp +++ b/src/quick/util/qquickanimatorjob.cpp @@ -345,12 +345,13 @@ void QQuickTransformAnimatorJob::postSync() } QQuickItemPrivate *d = QQuickItemPrivate::get(m_target); +#if QT_CONFIG(quick_shadereffect) if (d->extra.isAllocated() && d->extra->layer && d->extra->layer->enabled()) { d = QQuickItemPrivate::get(d->extra->layer->m_effectSource); } - +#endif m_helper->node = d->itemNode(); } diff --git a/src/src.pro b/src/src.pro index 4e2de8da14..24e139415b 100644 --- a/src/src.pro +++ b/src/src.pro @@ -10,7 +10,7 @@ qtHaveModule(gui):qtConfig(animation) { quick \ qmltest - qtConfig(quick-sprite):qtConfig(opengl(es1|es2)?): \ + qtConfig(quick-shadereffect):qtConfig(quick-sprite):qtConfig(opengl(es1|es2)?): \ SUBDIRS += particles qtHaveModule(widgets): SUBDIRS += quickwidgets } -- cgit v1.2.3 From 323d8aafbf0fbe1911fbc8b286b2a05455dd4861 Mon Sep 17 00:00:00 2001 From: Marco Benelli Date: Fri, 24 Feb 2017 16:07:34 +0100 Subject: Update plugins.qmltypes for 5.9 Change-Id: I5e6dbd2012718890f5fcc92beebcd1829dc53a57 Reviewed-by: Thomas Hartmann --- src/imports/builtins/builtins.qmltypes | 32 ++++++++- src/imports/particles/plugins.qmltypes | 6 +- src/imports/qtquick2/plugins.qmltypes | 114 ++++++++++++++++++++++++--------- src/imports/testlib/plugins.qmltypes | 42 +++++++++++- src/imports/window/plugins.qmltypes | 56 ++++++++++------ 5 files changed, 197 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/imports/builtins/builtins.qmltypes b/src/imports/builtins/builtins.qmltypes index 88e3ac6634..ac95a8837b 100644 --- a/src/imports/builtins/builtins.qmltypes +++ b/src/imports/builtins/builtins.qmltypes @@ -149,6 +149,25 @@ Module { "AlignCenter": 132 } } + Enum { + name: "TextFlag" + values: { + "TextSingleLine": 256, + "TextDontClip": 512, + "TextExpandTabs": 1024, + "TextShowMnemonic": 2048, + "TextWordWrap": 4096, + "TextWrapAnywhere": 8192, + "TextDontPrint": 16384, + "TextIncludeTrailingSpaces": 134217728, + "TextHideMnemonic": 32768, + "TextJustificationForced": 65536, + "TextForceLeftToRight": 131072, + "TextForceRightToLeft": 262144, + "TextLongestVariant": 524288, + "TextBypassShaping": 1048576 + } + } Enum { name: "TextElideMode" values: { @@ -440,7 +459,8 @@ Module { "AA_SynthesizeMouseForUnhandledTabletEvents": 24, "AA_CompressHighFrequencyEvents": 25, "AA_DontCheckOpenGLContextThreadAffinity": 26, - "AA_AttributeCount": 27 + "AA_DisableShaderDiskCache": 27, + "AA_AttributeCount": 28 } } Enum { @@ -1096,7 +1116,8 @@ Module { "SystemLocaleLongDate": 5, "DefaultLocaleShortDate": 6, "DefaultLocaleLongDate": 7, - "RFC2822Date": 8 + "RFC2822Date": 8, + "ISODateWithMs": 9 } } Enum { @@ -1607,6 +1628,13 @@ Module { "MouseEventFlagMask": 255 } } + Enum { + name: "ChecksumType" + values: { + "ChecksumIso3309": 0, + "ChecksumItuV41": 1 + } + } } Component { name: "QEasingCurve"; prototype: "QQmlEasingValueType" } } diff --git a/src/imports/particles/plugins.qmltypes b/src/imports/particles/plugins.qmltypes index 5c4bd01980..6c7c98cc71 100644 --- a/src/imports/particles/plugins.qmltypes +++ b/src/imports/particles/plugins.qmltypes @@ -275,11 +275,11 @@ Module { Parameter { name: "arg"; type: "double" } } Method { - name: "setAcceleration" + name: "setMagnitude" Parameter { name: "arg"; type: "double" } } Method { - name: "setMagnitude" + name: "setAcceleration" Parameter { name: "arg"; type: "double" } } Method { @@ -552,7 +552,7 @@ Module { Parameter { name: "arg"; type: "bool" } } Method { - name: "setmirrored" + name: "setMirrored" Parameter { name: "arg"; type: "bool" } } } diff --git a/src/imports/qtquick2/plugins.qmltypes b/src/imports/qtquick2/plugins.qmltypes index 441cd743aa..a9534b5ccc 100644 --- a/src/imports/qtquick2/plugins.qmltypes +++ b/src/imports/qtquick2/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable -noforceqtquick QtQuick 2.8' +// 'qmlplugindump -nonrelocatable -noforceqtquick QtQuick 2.9' Module { dependencies: [] @@ -439,6 +439,13 @@ Module { } } } + Component { + name: "QPointingDeviceUniqueId" + exports: ["QtQuick/PointingDeviceUniqueId 2.9"] + isCreatable: false + exportMetaObjectRevisions: [0] + Property { name: "numericId"; type: "qlonglong"; isReadonly: true } + } Component { name: "QQmlApplication" prototype: "QObject" @@ -1159,6 +1166,8 @@ Module { Property { name: "supportsMultipleWindows"; type: "bool"; isReadonly: true } Property { name: "state"; type: "Qt::ApplicationState"; isReadonly: true } Property { name: "font"; type: "QFont"; isReadonly: true } + Property { name: "displayName"; type: "string" } + Property { name: "screens"; type: "QQuickScreenInfo"; isList: true; isReadonly: true } Signal { name: "stateChanged" Parameter { name: "state"; type: "Qt::ApplicationState" } @@ -1168,9 +1177,13 @@ Module { name: "QQuickBasePositioner" defaultProperty: "data" prototype: "QQuickImplicitSizeItem" - exports: ["QtQuick/Positioner 2.0", "QtQuick/Positioner 2.6"] + exports: [ + "QtQuick/Positioner 2.0", + "QtQuick/Positioner 2.6", + "QtQuick/Positioner 2.9" + ] isCreatable: false - exportMetaObjectRevisions: [0, 6] + exportMetaObjectRevisions: [0, 6, 9] attachedType: "QQuickPositionerAttached" Property { name: "spacing"; type: "double" } Property { name: "populate"; type: "QQuickTransition"; isPointer: true } @@ -1186,6 +1199,8 @@ Module { Signal { name: "leftPaddingChanged"; revision: 6 } Signal { name: "rightPaddingChanged"; revision: 6 } Signal { name: "bottomPaddingChanged"; revision: 6 } + Signal { name: "positioningComplete"; revision: 9 } + Method { name: "forceLayout"; revision: 9 } } Component { name: "QQuickBehavior" @@ -1502,8 +1517,8 @@ Module { name: "QQuickFlickable" defaultProperty: "flickableData" prototype: "QQuickItem" - exports: ["QtQuick/Flickable 2.0"] - exportMetaObjectRevisions: [0] + exports: ["QtQuick/Flickable 2.0", "QtQuick/Flickable 2.9"] + exportMetaObjectRevisions: [0, 9] Enum { name: "BoundsBehavior" values: { @@ -1563,6 +1578,8 @@ Module { isPointer: true } Property { name: "pixelAligned"; type: "bool" } + Property { name: "horizontalOvershoot"; revision: 9; type: "double"; isReadonly: true } + Property { name: "verticalOvershoot"; revision: 9; type: "double"; isReadonly: true } Property { name: "flickableData"; type: "QObject"; isList: true; isReadonly: true } Property { name: "flickableChildren"; type: "QQuickItem"; isList: true; isReadonly: true } Signal { name: "isAtBoundaryChanged" } @@ -1572,6 +1589,8 @@ Module { Signal { name: "flickEnded" } Signal { name: "dragStarted" } Signal { name: "dragEnded" } + Signal { name: "horizontalOvershootChanged"; revision: 9 } + Signal { name: "verticalOvershootChanged"; revision: 9 } Method { name: "resizeContent" Parameter { name: "w"; type: "double" } @@ -2084,8 +2103,13 @@ Module { name: "QQuickItem" defaultProperty: "data" prototype: "QObject" - exports: ["QtQuick/Item 2.0", "QtQuick/Item 2.1", "QtQuick/Item 2.4"] - exportMetaObjectRevisions: [0, 1, 2] + exports: [ + "QtQuick/Item 2.0", + "QtQuick/Item 2.1", + "QtQuick/Item 2.4", + "QtQuick/Item 2.7" + ] + exportMetaObjectRevisions: [0, 1, 2, 7] Enum { name: "TransformOrigin" values: { @@ -2210,23 +2234,21 @@ Module { Parameter { name: "point"; type: "QPointF" } } Method { - name: "mapToGlobal" - revision: 7 - type: "QPointF" - Parameter { name: "point"; type: "QPointF" } + name: "mapFromItem" + Parameter { type: "QQmlV4Function"; isPointer: true } } Method { - name: "mapFromGlobal" - revision: 7 - type: "QPointF" - Parameter { name: "point"; type: "QPointF" } + name: "mapToItem" + Parameter { type: "QQmlV4Function"; isPointer: true } } Method { - name: "mapFromItem" + name: "mapFromGlobal" + revision: 7 Parameter { type: "QQmlV4Function"; isPointer: true } } Method { - name: "mapToItem" + name: "mapToGlobal" + revision: 7 Parameter { type: "QQmlV4Function"; isPointer: true } } Method { name: "forceActiveFocus" } @@ -2259,6 +2281,11 @@ Module { type: "bool" Parameter { name: "fileName"; type: "string" } } + Method { + name: "saveToFile" + type: "bool" + Parameter { name: "fileName"; type: "string" } + } } Component { name: "QQuickItemLayer" @@ -2318,9 +2345,13 @@ Module { name: "QQuickItemView" defaultProperty: "flickableData" prototype: "QQuickFlickable" - exports: ["QtQuick/ItemView 2.1", "QtQuick/ItemView 2.3"] + exports: [ + "QtQuick/ItemView 2.1", + "QtQuick/ItemView 2.3", + "QtQuick/ItemView 2.7" + ] isCreatable: false - exportMetaObjectRevisions: [1, 2] + exportMetaObjectRevisions: [1, 2, 7] Enum { name: "LayoutDirection" values: { @@ -2494,6 +2525,10 @@ Module { name: "released" Parameter { name: "event"; type: "QQuickKeyEvent"; isPointer: true } } + Signal { + name: "shortcutOverride" + Parameter { name: "event"; type: "QQuickKeyEvent"; isPointer: true } + } Signal { name: "digit0Pressed" Parameter { name: "event"; type: "QQuickKeyEvent"; isPointer: true } @@ -2757,9 +2792,10 @@ Module { exports: [ "QtQuick/MouseArea 2.0", "QtQuick/MouseArea 2.4", - "QtQuick/MouseArea 2.5" + "QtQuick/MouseArea 2.5", + "QtQuick/MouseArea 2.9" ] - exportMetaObjectRevisions: [0, 1, 2] + exportMetaObjectRevisions: [0, 1, 2, 9] Property { name: "mouseX"; type: "double"; isReadonly: true } Property { name: "mouseY"; type: "double"; isReadonly: true } Property { name: "containsMouse"; type: "bool"; isReadonly: true } @@ -2774,6 +2810,7 @@ Module { Property { name: "propagateComposedEvents"; type: "bool" } Property { name: "cursorShape"; type: "Qt::CursorShape" } Property { name: "containsPress"; revision: 1; type: "bool"; isReadonly: true } + Property { name: "pressAndHoldInterval"; revision: 9; type: "int" } Signal { name: "hoveredChanged" } Signal { name: "scrollGestureEnabledChanged"; revision: 2 } Signal { @@ -2816,6 +2853,7 @@ Module { Signal { name: "exited" } Signal { name: "canceled" } Signal { name: "containsPressChanged"; revision: 1 } + Signal { name: "pressAndHoldIntervalChanged"; revision: 9 } } Component { name: "QQuickMultiPointTouchArea" @@ -3600,14 +3638,20 @@ Module { Component { name: "QQuickShortcut" prototype: "QObject" - exports: ["QtQuick/Shortcut 2.5", "QtQuick/Shortcut 2.6"] - exportMetaObjectRevisions: [0, 1] + exports: [ + "QtQuick/Shortcut 2.5", + "QtQuick/Shortcut 2.6", + "QtQuick/Shortcut 2.9" + ] + exportMetaObjectRevisions: [0, 1, 9] Property { name: "sequence"; type: "QVariant" } + Property { name: "sequences"; revision: 9; type: "QVariantList" } Property { name: "nativeText"; revision: 1; type: "string"; isReadonly: true } Property { name: "portableText"; revision: 1; type: "string"; isReadonly: true } Property { name: "enabled"; type: "bool" } Property { name: "autoRepeat"; type: "bool" } Property { name: "context"; type: "Qt::ShortcutContext" } + Signal { name: "sequencesChanged"; revision: 9 } Signal { name: "activated" } Signal { name: "activatedAmbiguously" } } @@ -3926,9 +3970,10 @@ Module { "QtQuick/Text 2.0", "QtQuick/Text 2.2", "QtQuick/Text 2.3", - "QtQuick/Text 2.6" + "QtQuick/Text 2.6", + "QtQuick/Text 2.9" ] - exportMetaObjectRevisions: [0, 2, 3, 6] + exportMetaObjectRevisions: [0, 2, 3, 6, 9] Enum { name: "HAlignment" values: { @@ -4038,6 +4083,7 @@ Module { Property { name: "leftPadding"; revision: 6; type: "double" } Property { name: "rightPadding"; revision: 6; type: "double" } Property { name: "bottomPadding"; revision: 6; type: "double" } + Property { name: "fontInfo"; revision: 9; type: "QJSValue"; isReadonly: true } Signal { name: "textChanged" Parameter { name: "text"; type: "string" } @@ -4093,7 +4139,9 @@ Module { Signal { name: "leftPaddingChanged"; revision: 6 } Signal { name: "rightPaddingChanged"; revision: 6 } Signal { name: "bottomPaddingChanged"; revision: 6 } + Signal { name: "fontInfoChanged"; revision: 9 } Method { name: "doLayout" } + Method { name: "forceLayout"; revision: 9 } Method { name: "linkAt" revision: 3 @@ -4390,9 +4438,10 @@ Module { "QtQuick/TextInput 2.2", "QtQuick/TextInput 2.4", "QtQuick/TextInput 2.6", - "QtQuick/TextInput 2.7" + "QtQuick/TextInput 2.7", + "QtQuick/TextInput 2.9" ] - exportMetaObjectRevisions: [0, 2, 3, 6, 7] + exportMetaObjectRevisions: [0, 2, 3, 6, 7, 9] Enum { name: "EchoMode" values: { @@ -4497,6 +4546,7 @@ Module { Property { name: "bottomPadding"; revision: 6; type: "double" } Signal { name: "accepted" } Signal { name: "editingFinished"; revision: 2 } + Signal { name: "textEdited"; revision: 9 } Signal { name: "fontChanged" Parameter { name: "font"; type: "QFont" } @@ -4657,13 +4707,16 @@ Module { Component { name: "QQuickTouchPoint" prototype: "QObject" - exports: ["QtQuick/TouchPoint 2.0"] - exportMetaObjectRevisions: [0] + exports: ["QtQuick/TouchPoint 2.0", "QtQuick/TouchPoint 2.9"] + exportMetaObjectRevisions: [0, 0] Property { name: "pointId"; type: "int"; isReadonly: true } + Property { name: "uniqueId"; revision: 9; type: "QPointingDeviceUniqueId"; isReadonly: true } Property { name: "pressed"; type: "bool"; isReadonly: true } Property { name: "x"; type: "double"; isReadonly: true } Property { name: "y"; type: "double"; isReadonly: true } + Property { name: "ellipseDiameters"; revision: 9; type: "QSizeF"; isReadonly: true } Property { name: "pressure"; type: "double"; isReadonly: true } + Property { name: "rotation"; revision: 9; type: "double"; isReadonly: true } Property { name: "velocity"; type: "QVector2D"; isReadonly: true } Property { name: "area"; type: "QRectF"; isReadonly: true } Property { name: "startX"; type: "double"; isReadonly: true } @@ -4672,6 +4725,9 @@ Module { Property { name: "previousY"; type: "double"; isReadonly: true } Property { name: "sceneX"; type: "double"; isReadonly: true } Property { name: "sceneY"; type: "double"; isReadonly: true } + Signal { name: "uniqueIdChanged"; revision: 9 } + Signal { name: "ellipseDiametersChanged"; revision: 9 } + Signal { name: "rotationChanged"; revision: 9 } } Component { name: "QQuickTransform"; prototype: "QObject" } Component { diff --git a/src/imports/testlib/plugins.qmltypes b/src/imports/testlib/plugins.qmltypes index 563778e55e..5d7ca51adc 100644 --- a/src/imports/testlib/plugins.qmltypes +++ b/src/imports/testlib/plugins.qmltypes @@ -4,10 +4,44 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable -noforceqtquick QtTest 1.1' +// 'qmlplugindump -nonrelocatable -noforceqtquick QtTest 1.2' Module { dependencies: ["QtQuick 2.0"] + Component { + name: "QQuickTouchEventSequence" + prototype: "QObject" + Method { + name: "press" + type: "QObject*" + Parameter { name: "touchId"; type: "int" } + Parameter { name: "item"; type: "QObject"; isPointer: true } + Parameter { name: "x"; type: "double" } + Parameter { name: "y"; type: "double" } + } + Method { + name: "move" + type: "QObject*" + Parameter { name: "touchId"; type: "int" } + Parameter { name: "item"; type: "QObject"; isPointer: true } + Parameter { name: "x"; type: "double" } + Parameter { name: "y"; type: "double" } + } + Method { + name: "release" + type: "QObject*" + Parameter { name: "touchId"; type: "int" } + Parameter { name: "item"; type: "QObject"; isPointer: true } + Parameter { name: "x"; type: "double" } + Parameter { name: "y"; type: "double" } + } + Method { + name: "stationary" + type: "QObject*" + Parameter { name: "touchId"; type: "int" } + } + Method { name: "commit"; type: "QObject*" } + } Component { name: "QuickTestEvent" prototype: "QObject" @@ -127,6 +161,12 @@ Module { Parameter { name: "yDelta"; type: "int" } Parameter { name: "delay"; type: "int" } } + Method { + name: "touchEvent" + type: "QQuickTouchEventSequence*" + Parameter { name: "item"; type: "QObject"; isPointer: true } + } + Method { name: "touchEvent"; type: "QQuickTouchEventSequence*" } } Component { name: "QuickTestResult" diff --git a/src/imports/window/plugins.qmltypes b/src/imports/window/plugins.qmltypes index a79bd8c332..cea2a910a7 100644 --- a/src/imports/window/plugins.qmltypes +++ b/src/imports/window/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable QtQuick.Window 2.2' +// 'qmlplugindump -nonrelocatable QtQuick.Window 2.3' Module { dependencies: ["QtQuick 2.8"] @@ -24,14 +24,28 @@ Module { Component { name: "QQuickScreen" prototype: "QObject" - exports: ["QtQuick.Window/Screen 2.0"] + exports: ["QtQuick.Window/Screen 2.0", "QtQuick.Window/Screen 2.3"] isCreatable: false - exportMetaObjectRevisions: [0] + exportMetaObjectRevisions: [0, 1] attachedType: "QQuickScreenAttached" } Component { name: "QQuickScreenAttached" + prototype: "QQuickScreenInfo" + Property { name: "orientationUpdateMask"; type: "Qt::ScreenOrientations" } + Method { + name: "angleBetween" + type: "int" + Parameter { name: "a"; type: "int" } + Parameter { name: "b"; type: "int" } + } + } + Component { + name: "QQuickScreenInfo" prototype: "QObject" + exports: ["QtQuick.Window/ScreenInfo 2.3"] + isCreatable: false + exportMetaObjectRevisions: [2] Property { name: "name"; type: "string"; isReadonly: true } Property { name: "width"; type: "int"; isReadonly: true } Property { name: "height"; type: "int"; isReadonly: true } @@ -42,25 +56,18 @@ Module { Property { name: "devicePixelRatio"; type: "double"; isReadonly: true } Property { name: "primaryOrientation"; type: "Qt::ScreenOrientation"; isReadonly: true } Property { name: "orientation"; type: "Qt::ScreenOrientation"; isReadonly: true } - Property { name: "orientationUpdateMask"; type: "Qt::ScreenOrientations" } + Property { name: "virtualX"; revision: 1; type: "int"; isReadonly: true } + Property { name: "virtualY"; revision: 1; type: "int"; isReadonly: true } Signal { name: "desktopGeometryChanged" } - Method { - name: "angleBetween" - type: "int" - Parameter { name: "a"; type: "int" } - Parameter { name: "b"; type: "int" } - } + Signal { name: "virtualXChanged"; revision: 1 } + Signal { name: "virtualYChanged"; revision: 1 } } Component { name: "QQuickWindow" defaultProperty: "data" prototype: "QWindow" - exports: [ - "QtQuick.Window/Window 2.0", - "QtQuick.Window/Window 2.1", - "QtQuick.Window/Window 2.2" - ] - exportMetaObjectRevisions: [0, 1, 2] + exports: ["QtQuick.Window/Window 2.0"] + exportMetaObjectRevisions: [0] Enum { name: "SceneGraphError" values: { @@ -125,11 +132,16 @@ Module { name: "QQuickWindowQmlImpl" defaultProperty: "data" prototype: "QQuickWindow" - exports: ["QtQuick.Window/Window 2.1", "QtQuick.Window/Window 2.2"] - exportMetaObjectRevisions: [0, 1] + exports: [ + "QtQuick.Window/Window 2.1", + "QtQuick.Window/Window 2.2", + "QtQuick.Window/Window 2.3" + ] + exportMetaObjectRevisions: [0, 1, 2] attachedType: "QQuickWindowAttached" Property { name: "visible"; type: "bool" } Property { name: "visibility"; type: "Visibility" } + Property { name: "screen"; revision: 2; type: "QObject"; isPointer: true } Signal { name: "visibleChanged" Parameter { name: "arg"; type: "bool" } @@ -138,6 +150,7 @@ Module { name: "visibilityChanged" Parameter { name: "visibility"; type: "QWindow::Visibility" } } + Signal { name: "screenChanged"; revision: 2 } } Component { name: "QWindow" @@ -153,6 +166,13 @@ Module { "FullScreen": 5 } } + Enum { + name: "AncestorMode" + values: { + "ExcludeTransients": 0, + "IncludeTransients": 1 + } + } Property { name: "title"; type: "string" } Property { name: "modality"; type: "Qt::WindowModality" } Property { name: "flags"; type: "Qt::WindowFlags" } -- cgit v1.2.3 From 1ba5c5bb017237501fd8e1e97fc00b4817f19fa4 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 13 Mar 2017 08:44:22 +0100 Subject: Fix accidental assignment in assertion Change-Id: I5b63697c0607f4300b7f203eeac74914f3fb43af Reviewed-by: Holger Freyther Reviewed-by: Lars Knoll --- src/qml/memory/qv4heap_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index 5a3797f397..97aa6ced38 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -144,7 +144,7 @@ struct Q_QML_EXPORT Base { else if (_livenessStatus == Destroyed) fprintf(stderr, "ERROR: use of object '%s' after call to destroy() !!\n", vtable()->className); - Q_ASSERT(_livenessStatus = Initialized); + Q_ASSERT(_livenessStatus == Initialized); } void _checkIsDestroyed() { if (_livenessStatus == Initialized) -- cgit v1.2.3 From 30635ee2424dbd08bb5c2170be0c2dc5f9d23b2c Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 13 Mar 2017 08:46:02 +0100 Subject: Fix accidental assignment in assertion Change-Id: Ic826901d120f8073727d06fccfe95e7d75e3d088 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4context.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 7a0df5dbf3..d2f2529979 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -343,7 +343,7 @@ void ExecutionContext::setProperty(String *name, const Value &value) if (index < c->v4Function->nFormals) { c->callData->args[c->v4Function->nFormals - index - 1] = value; } else { - Q_ASSERT(c->type = Heap::ExecutionContext::Type_CallContext); + Q_ASSERT(c->type == Heap::ExecutionContext::Type_CallContext); index -= c->v4Function->nFormals; static_cast(c)->locals.set(scope.engine, index, value); } @@ -418,7 +418,7 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (index < UINT_MAX) { if (index < c->v4Function->nFormals) return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); - Q_ASSERT(c->type = Heap::ExecutionContext::Type_CallContext); + Q_ASSERT(c->type == Heap::ExecutionContext::Type_CallContext); return c->locals[index - c->v4Function->nFormals].asReturnedValue(); } if (c->v4Function->isNamedExpression()) { -- cgit v1.2.3 From a91b83c0bbafbdfb290f2766d51d12e805506e30 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 9 Mar 2017 16:55:13 +0100 Subject: Clean up type dependency hashing for QML caching Instead of passing the engine parameter all the way through the data structure generator, along with the dependent type data structure that is unused otherwise, let's simply provide a function object for the dependency hashing. This is also in preparation for adding singleton types to the dependency hash. Task-number: QTBUG-58486 Change-Id: I5bb5e5c06b7b5c77195cec3da13141333cfea7a8 Reviewed-by: Lars Knoll --- src/qml/compiler/qqmlirbuilder.cpp | 9 ++++----- src/qml/compiler/qqmlirbuilder_p.h | 2 +- src/qml/compiler/qqmltypecompiler.cpp | 5 +++-- src/qml/compiler/qqmltypecompiler_p.h | 4 +++- src/qml/compiler/qv4compileddata.cpp | 7 +++---- src/qml/compiler/qv4compileddata_p.h | 7 ++++--- src/qml/qml/qqmltypeloader.cpp | 16 ++++++++++------ src/qml/qml/qqmltypeloader_p.h | 2 +- 8 files changed, 29 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index c0f953ca2c..8ead1c9b5d 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1359,7 +1359,7 @@ bool IRBuilder::isRedundantNullInitializerForPropertyDeclaration(Property *prope return QQmlJS::AST::cast(expr); } -QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, QQmlEngine *engine, const QV4::CompiledData::ResolvedTypeReferenceMap &dependentTypes) +QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::DependentTypesHasher &dependencyHasher) { QQmlRefPointer compilationUnit = output.javaScriptCompilationUnit; QV4::CompiledData::Unit *jsUnit = compilationUnit->createUnitData(&output); @@ -1402,17 +1402,16 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, QQmlEngine qmlUnit->stringTableSize = output.jsGenerator.stringTable.stringCount(); #ifndef V4_BOOTSTRAP - if (!dependentTypes.isEmpty()) { + if (dependencyHasher) { QCryptographicHash hash(QCryptographicHash::Md5); - if (dependentTypes.addToHash(&hash, engine)) { + if (dependencyHasher(&hash)) { QByteArray checksum = hash.result(); Q_ASSERT(checksum.size() == sizeof(qmlUnit->dependencyMD5Checksum)); memcpy(qmlUnit->dependencyMD5Checksum, checksum.constData(), sizeof(qmlUnit->dependencyMD5Checksum)); } } #else - Q_UNUSED(dependentTypes); - Q_UNUSED(engine); + Q_UNUSED(dependencyHasher); #endif // write imports diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index cc16dc2104..44f8cef16a 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -548,7 +548,7 @@ public: struct Q_QML_PRIVATE_EXPORT QmlUnitGenerator { - QV4::CompiledData::Unit *generate(Document &output, QQmlEngine *engine, const QV4::CompiledData::ResolvedTypeReferenceMap &dependentTypes); + QV4::CompiledData::Unit *generate(Document &output, const QV4::CompiledData::DependentTypesHasher &dependencyHasher = QV4::CompiledData::DependentTypesHasher()); private: typedef bool (Binding::*BindingFilter)() const; diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index b7262e4333..0f3ebac223 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -58,10 +58,11 @@ QT_BEGIN_NAMESPACE QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *parsedQML, const QQmlRefPointer &importCache, - const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache) + const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher) : resolvedTypes(resolvedTypeCache) , engine(engine) , typeData(typeData) + , dependencyHasher(dependencyHasher) , importCache(importCache) , document(parsedQML) { @@ -156,7 +157,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile() // Generate QML compiled type data structures QmlIR::QmlUnitGenerator qmlGenerator; - QV4::CompiledData::Unit *qmlUnit = qmlGenerator.generate(*document, QQmlEnginePrivate::get(engine), resolvedTypes); + QV4::CompiledData::Unit *qmlUnit = qmlGenerator.generate(*document, dependencyHasher); Q_ASSERT(document->javaScriptCompilationUnit); // The js unit owns the data and will free the qml unit. diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index de6abb4ced..7df4fb57cb 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -89,7 +89,8 @@ struct QQmlTypeCompiler { Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler) public: - QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document, const QQmlRefPointer &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache); + QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document, const QQmlRefPointer &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache, + const QV4::CompiledData::DependentTypesHasher &dependencyHasher); // --- interface used by QQmlPropertyCacheCreator typedef QmlIR::Object CompiledObject; @@ -139,6 +140,7 @@ private: QList errors; QQmlEnginePrivate *engine; QQmlTypeData *typeData; + const QV4::CompiledData::DependentTypesHasher &dependencyHasher; QQmlRefPointer importCache; QmlIR::Document *document; // index is string index of type name (use obj->inheritedTypeNameIndex) diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index d8ff22e9ed..b175abe1f5 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -310,10 +310,9 @@ void CompilationUnit::finalize(QQmlEnginePrivate *engine) totalObjectCount = objectCount; } -bool CompilationUnit::verifyChecksum(QQmlEngine *engine, - const ResolvedTypeReferenceMap &dependentTypes) const +bool CompilationUnit::verifyChecksum(const DependentTypesHasher &dependencyHasher) const { - if (dependentTypes.isEmpty()) { + if (!dependencyHasher) { for (size_t i = 0; i < sizeof(data->dependencyMD5Checksum); ++i) { if (data->dependencyMD5Checksum[i] != 0) return false; @@ -321,7 +320,7 @@ bool CompilationUnit::verifyChecksum(QQmlEngine *engine, return true; } QCryptographicHash hash(QCryptographicHash::Md5); - if (!dependentTypes.addToHash(&hash, engine)) + if (!dependencyHasher(&hash)) return false; QByteArray checksum = hash.result(); Q_ASSERT(checksum.size() == sizeof(data->dependencyMD5Checksum)); diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 2682365182..cb8ce8a649 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -809,8 +809,10 @@ struct ResolvedTypeReferenceMap: public QMap { bool addToHash(QCryptographicHash *hash, QQmlEngine *engine) const; }; + +using DependentTypesHasher = std::function; #else -struct ResolvedTypeReferenceMap {}; +struct DependentTypesHasher {}; #endif // index is per-object binding index @@ -879,8 +881,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount QVector dependentScripts; ResolvedTypeReferenceMap resolvedTypes; - bool verifyChecksum(QQmlEngine *engine, - const ResolvedTypeReferenceMap &dependentTypes) const; + bool verifyChecksum(const DependentTypesHasher &dependencyHasher) const; int metaTypeId; int listMetaTypeId; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 7ad18c8efb..dea8f3ed6f 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2227,8 +2227,12 @@ void QQmlTypeData::done() QQmlEngine *const engine = typeLoader()->engine(); + const auto dependencyHasher = [engine, resolvedTypeCache](QCryptographicHash *hash) { + return resolvedTypeCache.addToHash(hash, engine); + }; + // verify if any dependencies changed if we're using a cache - if (m_document.isNull() && !m_compiledData->verifyChecksum(engine, resolvedTypeCache)) { + if (m_document.isNull() && !m_compiledData->verifyChecksum(dependencyHasher)) { qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->url().toString(); if (!loadFromSource()) return; @@ -2238,7 +2242,7 @@ void QQmlTypeData::done() if (!m_document.isNull()) { // Compile component - compile(importCache, resolvedTypeCache); + compile(importCache, resolvedTypeCache, dependencyHasher); } else { createTypeAndPropertyCaches(importCache, resolvedTypeCache); } @@ -2487,12 +2491,13 @@ QString QQmlTypeData::stringAt(int index) const return m_document->jsGenerator.stringTable.stringForIndex(index); } -void QQmlTypeData::compile(const QQmlRefPointer &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache) +void QQmlTypeData::compile(const QQmlRefPointer &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache, + const QV4::CompiledData::DependentTypesHasher &dependencyHasher) { Q_ASSERT(m_compiledData.isNull()); QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine()); - QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), importCache, resolvedTypeCache); + QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), importCache, resolvedTypeCache, dependencyHasher); m_compiledData = compiler.compile(); if (!m_compiledData) { setError(compiler.compilationErrors()); @@ -2934,8 +2939,7 @@ void QQmlScriptBlob::dataReceived(const Data &data) irUnit.jsModule.unitFlags |= QV4::CompiledData::Unit::IsSharedLibrary; QmlIR::QmlUnitGenerator qmlGenerator; - QV4::CompiledData::ResolvedTypeReferenceMap emptyDependencies; - QV4::CompiledData::Unit *unitData = qmlGenerator.generate(irUnit, m_typeLoader->engine(), emptyDependencies); + QV4::CompiledData::Unit *unitData = qmlGenerator.generate(irUnit); Q_ASSERT(!unit->data); // The js unit owns the data and will free the qml unit. unit->data = unitData; diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 53cf4234e1..d85346c23e 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -453,7 +453,7 @@ private: QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache ) const; void compile(const QQmlRefPointer &importCache, - const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache); + const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher); void createTypeAndPropertyCaches(const QQmlRefPointer &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache); bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref); -- cgit v1.2.3 From 5b94de09cc738837d1539e28b3c0dccd17c18d29 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 9 Mar 2017 15:24:59 +0100 Subject: Fix caching of QML singleton types When a QML file depends on a QML singleton, we failed to include it in the dependency hash. Thus changes to the QML singleton did not result in a re-creation of the caches of files that use it. The list of singletons comes from random-ordered hashes in the qml import handling. We provide an order to the direct dependencies by sorting by the singleton type names. Task-number: QTBUG-58486 Change-Id: Ie7e9d006f9bf3a60af1f819ee439c29bc234bd8a Reviewed-by: Lars Knoll --- src/qml/qml/qqmltypeloader.cpp | 37 +++++++++++++++++++++++++++++++++++-- src/qml/qml/qqmltypeloader_p.h | 1 + 2 files changed, 36 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index dea8f3ed6f..3004fd2196 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2007,6 +2007,16 @@ QQmlTypeData::TypeDataCallback::~TypeDataCallback() { } +QString QQmlTypeData::TypeReference::qualifiedName() const +{ + QString result; + if (!prefix.isEmpty()) { + result = prefix + QLatin1Char('.'); + } + result.append(type->qmlTypeName()); + return result; +} + QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager) : QQmlTypeLoader::Blob(url, QmlFile, manager), m_typesResolved(false), m_implicitImportLoaded(false) @@ -2147,6 +2157,23 @@ void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer &typeRefs, QCryptographicHash *hash, QQmlEngine *engine) +{ + for (const auto &typeRef: typeRefs) { + if (typeRef.typeData) { + const auto unit = typeRef.typeData->compilationUnit(); + hash->addData(unit->data->md5Checksum, sizeof(unit->data->md5Checksum)); + } else if (typeRef.type) { + const auto propertyCache = QQmlEnginePrivate::get(engine)->cache(typeRef.type->metaObject()); + bool ok = false; + hash->addData(propertyCache->checksum(&ok)); + if (!ok) + return false; + } + } + return true; +} + void QQmlTypeData::done() { QDeferredCleanup cleanup([this]{ @@ -2227,8 +2254,10 @@ void QQmlTypeData::done() QQmlEngine *const engine = typeLoader()->engine(); - const auto dependencyHasher = [engine, resolvedTypeCache](QCryptographicHash *hash) { - return resolvedTypeCache.addToHash(hash, engine); + const auto dependencyHasher = [engine, resolvedTypeCache, this](QCryptographicHash *hash) { + if (!resolvedTypeCache.addToHash(hash, engine)) + return false; + return ::addTypeReferenceChecksumsToHash(m_compositeSingletons, hash, engine); }; // verify if any dependencies changed if we're using a cache @@ -2568,6 +2597,10 @@ void QQmlTypeData::resolveTypes() } } + std::stable_sort(m_compositeSingletons.begin(), m_compositeSingletons.end(), [](const TypeReference &lhs, const TypeReference &rhs){ + return lhs.qualifiedName() < rhs.qualifiedName(); + }); + for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd(); unresolvedRef != end; ++unresolvedRef) { diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index d85346c23e..e3c4a52c45 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -400,6 +400,7 @@ public: int minorVersion; QQmlTypeData *typeData; QString prefix; // used by CompositeSingleton types + QString qualifiedName() const; bool needsCreation; }; -- cgit v1.2.3 From 920e0ddaf987f160cd70deb29d14769092929403 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Thu, 9 Mar 2017 14:20:42 +0100 Subject: Build fix for -no-feature-quick-path Change-Id: Ib52d45a12b367fa08982535a69c14881beec597e Reviewed-by: Lars Knoll --- src/quick/items/context2d/qquickcontext2d.cpp | 10 ++++++++-- src/quick/items/qquickitemsmodule.cpp | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index 0eeba5d6cd..ce890771d9 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -49,8 +49,9 @@ #include #include +#if QT_CONFIG(quick_path) #include - +#endif #include #include @@ -569,9 +570,10 @@ struct QQuickJSContext2D : public QV4::Object static void method_set_shadowOffsetY(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); // should these two be on the proto? +#if QT_CONFIG(quick_path) static void method_get_path(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); static void method_set_path(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); - +#endif static void method_get_font(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); static void method_set_font(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); static void method_get_textAlign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); @@ -2034,6 +2036,7 @@ void QQuickJSContext2D::method_set_shadowOffsetY(const QV4::BuiltinFunction *, Q RETURN_UNDEFINED(); } +#if QT_CONFIG(quick_path) void QQuickJSContext2D::method_get_path(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { QV4::Scoped r(scope, callData->thisObject); @@ -2060,6 +2063,7 @@ void QQuickJSContext2D::method_set_path(const QV4::BuiltinFunction *, QV4::Scope r->d()->context->m_v4path.set(scope.engine, value); RETURN_UNDEFINED(); } +#endif // QT_CONFIG(quick_path) //rects /*! @@ -4207,7 +4211,9 @@ QQuickContext2DEngineData::QQuickContext2DEngineData(QV4::ExecutionEngine *v4) proto->defineAccessorProperty(QStringLiteral("fillStyle"), QQuickJSContext2D::method_get_fillStyle, QQuickJSContext2D::method_set_fillStyle); proto->defineAccessorProperty(QStringLiteral("shadowColor"), QQuickJSContext2D::method_get_shadowColor, QQuickJSContext2D::method_set_shadowColor); proto->defineAccessorProperty(QStringLiteral("textBaseline"), QQuickJSContext2D::method_get_textBaseline, QQuickJSContext2D::method_set_textBaseline); +#if QT_CONFIG(quick_path) proto->defineAccessorProperty(QStringLiteral("path"), QQuickJSContext2D::method_get_path, QQuickJSContext2D::method_set_path); +#endif proto->defineAccessorProperty(QStringLiteral("lineJoin"), QQuickJSContext2D::method_get_lineJoin, QQuickJSContext2D::method_set_lineJoin); proto->defineAccessorProperty(QStringLiteral("lineWidth"), QQuickJSContext2D::method_get_lineWidth, QQuickJSContext2D::method_set_lineWidth); proto->defineAccessorProperty(QStringLiteral("textAlign"), QQuickJSContext2D::method_get_textAlign, QQuickJSContext2D::method_set_textAlign); diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index a8824de9c8..5f6d44b54d 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -273,7 +273,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType(); qmlRegisterType(uri, major, minor,"AnchorAnimation"); qmlRegisterType(uri, major, minor,"ParentAnimation"); -#if QT_CONFIG(quick_canvas) +#if QT_CONFIG(quick_path) qmlRegisterType("QtQuick",2,0,"PathAnimation"); qmlRegisterType("QtQuick",2,0,"PathInterpolator"); #endif -- cgit v1.2.3 From 9180241819a9ea5e517977efc5bb031521a56cc6 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Thu, 9 Mar 2017 14:50:19 +0100 Subject: Add features.quick-particles Change-Id: I78b30d254ed64acadcb2acc278ad1dfde55216ac Reviewed-by: Lars Knoll --- src/imports/imports.pro | 2 +- src/quick/configure.json | 8 ++++++++ src/src.pro | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/imports/imports.pro b/src/imports/imports.pro index 0ba949f070..d16ac05669 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -20,7 +20,7 @@ qtHaveModule(quick) { sharedimage \ testlib - qtConfig(quick-shadereffect):qtConfig(quick-sprite):qtConfig(opengl(es1|es2)?): \ + qtConfig(quick-particles): \ SUBDIRS += particles } diff --git a/src/quick/configure.json b/src/quick/configure.json index 4ed11e8318..eabc8c4824 100644 --- a/src/quick/configure.json +++ b/src/quick/configure.json @@ -97,6 +97,14 @@ "privateFeature" ] }, + "quick-particles": { + "label": "Particle support", + "purpose": "Provides a particle system for Qt Quick", + "condition": "features.quick-shadereffect && features.quick-sprite && features.opengl", + "output": [ + "privateFeature" + ] + }, "quick-path": { "label": "Path support", "purpose": "Provides Path elements in Qt Quick", diff --git a/src/src.pro b/src/src.pro index 24e139415b..3bb399acd4 100644 --- a/src/src.pro +++ b/src/src.pro @@ -10,7 +10,7 @@ qtHaveModule(gui):qtConfig(animation) { quick \ qmltest - qtConfig(quick-shadereffect):qtConfig(quick-sprite):qtConfig(opengl(es1|es2)?): \ + qtConfig(quick-particles): \ SUBDIRS += particles qtHaveModule(widgets): SUBDIRS += quickwidgets } -- cgit v1.2.3 From 5adfb4063a64aa3ae27269330c1fb8960dda4082 Mon Sep 17 00:00:00 2001 From: Josh Faust Date: Tue, 23 Apr 2013 21:36:30 -0700 Subject: Fix QQmlTypeLoader::Blob::qmldirDataAvailable memory overwrite An invalid iterator was being dereferenced. Task-number: QTBUG-59268 Change-Id: I58635667ab4591c06f1d7644243b83fd0172e74f Reviewed-by: Simon Hausmann --- src/qml/qml/qqmltypeloader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 3004fd2196..6465cd0b19 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1527,7 +1527,8 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QList Date: Thu, 9 Mar 2017 18:53:23 +0100 Subject: QV4DebugService: Reduce unnecessary recursion and redundancy Large parts of the protocol are unnecessary. There is no reason to send a separate chunk of "handles" with almost every reply. The refs are given as part of the regular data and if the client wants to find out more, it can do further lookups. Also, it makes no sense to encode the function and script names as objects, as they are in fact not JavaScript objects. Unfortunately these cleanups require some cooperation from the client. Older clients will misbehave if we just drop the redundancy. Therefore, we introduce parameters which the client can explicitly set with the "connect" message. redundantRefs tells the service if redundant references are required, namesAsObjects tells it if script and function names have to be sent as objects/ Once we can require clients that support these options, we can drop the code that generates redundant data. Also, fix tst_qv4debugger::evaluateExpression() to actually check all the expressions evaluated, not only the first and second one. Task-number: QTBUG-42435 Change-Id: If93d2a2b9d0b8035f85dbef871bc1b03f199171d Reviewed-by: hjk Reviewed-by: Simon Hausmann --- .../qmldbg_debugger/qv4datacollector.cpp | 72 +++++++++++++++------- .../qmltooling/qmldbg_debugger/qv4datacollector.h | 26 +++++--- .../qmltooling/qmldbg_debugger/qv4debugjob.cpp | 17 ++--- .../qmltooling/qmldbg_debugger/qv4debugjob.h | 21 +++++-- .../qmltooling/qmldbg_debugger/qv4debugservice.cpp | 45 ++++++++++---- .../qmltooling/qmldbg_debugger/qv4debugservice.h | 6 ++ 6 files changed, 134 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index aed2759383..5d2e754057 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -118,15 +118,18 @@ int QV4DataCollector::encodeScopeType(QV4::Heap::ExecutionContext::ContextType s } } -QV4DataCollector::QV4DataCollector(QV4::ExecutionEngine *engine) : m_engine(engine) +QV4DataCollector::QV4DataCollector(QV4::ExecutionEngine *engine) + : m_engine(engine), m_namesAsObjects(true), m_redundantRefs(true) { m_values.set(engine, engine->newArrayObject()); } +// TODO: Directly call addRef() once we don't need to support redundantRefs anymore QV4DataCollector::Ref QV4DataCollector::collect(const QV4::ScopedValue &value) { Ref ref = addRef(value); - m_collectedRefs.append(ref); + if (m_redundantRefs) + m_collectedRefs.append(ref); return ref; } @@ -190,24 +193,33 @@ const QV4::Object *collectProperty(const QV4::ScopedValue &value, QV4::Execution } } -QJsonObject QV4DataCollector::lookupRef(Ref ref) +QJsonObject QV4DataCollector::lookupRef(Ref ref, bool deep) { QJsonObject dict; - if (lookupSpecialRef(ref, &dict)) - return dict; + + if (m_namesAsObjects) { + if (lookupSpecialRef(ref, &dict)) + return dict; + } + + if (m_redundantRefs) + deep = true; dict.insert(QStringLiteral("handle"), qint64(ref)); QV4::Scope scope(engine()); QV4::ScopedValue value(scope, getValue(ref)); - if (const QV4::Object *o = collectProperty(value, engine(), dict)) - dict.insert(QStringLiteral("properties"), collectProperties(o)); + const QV4::Object *object = collectProperty(value, engine(), dict); + if (deep && object) + dict.insert(QStringLiteral("properties"), collectProperties(object)); return dict; } +// TODO: Drop this method once we don't need to support namesAsObjects anymore QV4DataCollector::Ref QV4DataCollector::addFunctionRef(const QString &functionName) { + Q_ASSERT(m_namesAsObjects); Ref ref = addRef(QV4::Primitive::emptyValue(), false); QJsonObject dict; @@ -220,8 +232,10 @@ QV4DataCollector::Ref QV4DataCollector::addFunctionRef(const QString &functionNa return ref; } +// TODO: Drop this method once we don't need to support namesAsObjects anymore QV4DataCollector::Ref QV4DataCollector::addScriptRef(const QString &scriptName) { + Q_ASSERT(m_namesAsObjects); Ref ref = addRef(QV4::Primitive::emptyValue(), false); QJsonObject dict; @@ -250,6 +264,7 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr) if (!ctxt) return false; + Refs collectedRefs; QV4::ScopedValue v(scope); int nFormals = ctxt->formalCount(); for (unsigned i = 0, ei = nFormals; i != ei; ++i) { @@ -258,7 +273,7 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr) qName = name->string; names.append(qName); v = ctxt->argument(i); - collect(v); + collectedRefs.append(collect(v)); } for (unsigned i = 0, ei = ctxt->variableCount(); i != ei; ++i) { @@ -267,19 +282,24 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr) qName = name->string; names.append(qName); v = ctxt->d()->locals[i]; - collect(v); + collectedRefs.append(collect(v)); } QV4::ScopedObject scopeObject(scope, engine()->newObject()); - Q_ASSERT(names.size() == m_collectedRefs.size()); - for (int i = 0, ei = m_collectedRefs.size(); i != ei; ++i) + Q_ASSERT(names.size() == collectedRefs.size()); + for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) scopeObject->put(engine(), names.at(i), - QV4::Value::fromReturnedValue(getValue(m_collectedRefs.at(i)))); + QV4::Value::fromReturnedValue(getValue(collectedRefs.at(i)))); Ref scopeObjectRef = addRef(scopeObject); - dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef)); - m_collectedRefs.append(scopeObjectRef); + if (m_redundantRefs) { + dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef)); + m_collectedRefs.append(scopeObjectRef); + } else { + *dict = lookupRef(scopeObjectRef, true); + } + return true; } @@ -291,15 +311,16 @@ QJsonObject toRef(QV4DataCollector::Ref ref) { QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int frameNr) { - QV4DataCollector::Ref ref; - QJsonObject frame; frame[QLatin1String("index")] = frameNr; frame[QLatin1String("debuggerFrame")] = false; - ref = addFunctionRef(stackFrame.function); - frame[QLatin1String("func")] = toRef(ref); - ref = addScriptRef(stackFrame.source); - frame[QLatin1String("script")] = toRef(ref); + if (m_namesAsObjects) { + frame[QLatin1String("func")] = toRef(addFunctionRef(stackFrame.function)); + frame[QLatin1String("script")] = toRef(addScriptRef(stackFrame.source)); + } else { + frame[QLatin1String("func")] = stackFrame.function; + frame[QLatin1String("script")] = stackFrame.source; + } frame[QLatin1String("line")] = stackFrame.line - 1; if (stackFrame.column >= 0) frame[QLatin1String("column")] = stackFrame.column; @@ -338,15 +359,17 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int return frame; } +// TODO: Drop this method once we don't need to support redundantRefs anymore QJsonArray QV4DataCollector::flushCollectedRefs() { + Q_ASSERT(m_redundantRefs); QJsonArray refs; std::sort(m_collectedRefs.begin(), m_collectedRefs.end()); for (int i = 0, ei = m_collectedRefs.size(); i != ei; ++i) { QV4DataCollector::Ref ref = m_collectedRefs.at(i); if (i > 0 && ref == m_collectedRefs.at(i - 1)) continue; - refs.append(lookupRef(ref)); + refs.append(lookupRef(ref, true)); } m_collectedRefs.clear(); @@ -358,6 +381,8 @@ void QV4DataCollector::clear() m_values.set(engine(), engine()->newArrayObject()); m_collectedRefs.clear(); m_specialRefs.clear(); + m_namesAsObjects = true; + m_redundantRefs = true; } QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicate) @@ -401,8 +426,10 @@ QV4::ReturnedValue QV4DataCollector::getValue(Ref ref) return array->getIndexed(ref, Q_NULLPTR); } +// TODO: Drop this method once we don't need to support namesAsObjects anymore bool QV4DataCollector::lookupSpecialRef(Ref ref, QJsonObject *dict) { + Q_ASSERT(m_namesAsObjects); SpecialRefs::const_iterator it = m_specialRefs.constFind(ref); if (it == m_specialRefs.cend()) return false; @@ -440,7 +467,8 @@ QJsonObject QV4DataCollector::collectAsJson(const QString &name, const QV4::Scop if (value->isManaged() && !value->isString()) { Ref ref = addRef(value); dict.insert(QStringLiteral("ref"), qint64(ref)); - m_collectedRefs.append(ref); + if (m_redundantRefs) + m_collectedRefs.append(ref); } collectProperty(value, engine(), dict); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h index fd6356f22e..2c2514a1b3 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h @@ -66,34 +66,42 @@ public: QV4DataCollector(QV4::ExecutionEngine *engine); - Ref collect(const QV4::ScopedValue &value); - Ref addFunctionRef(const QString &functionName); - Ref addScriptRef(const QString &scriptName); + Ref collect(const QV4::ScopedValue &value); // only for redundantRefs + Ref addFunctionRef(const QString &functionName); // only for namesAsObjects + Ref addScriptRef(const QString &scriptName); // only for namesAsObjects + + void setNamesAsObjects(bool namesAsObjects) { m_namesAsObjects = namesAsObjects; } + bool namesAsObjects() const { return m_namesAsObjects; } + + void setRedundantRefs(bool redundantRefs) { m_redundantRefs = redundantRefs; } + bool redundantRefs() const { return m_redundantRefs; } bool isValidRef(Ref ref) const; - QJsonObject lookupRef(Ref ref); + QJsonObject lookupRef(Ref ref, bool deep); bool collectScope(QJsonObject *dict, int frameNr, int scopeNr); QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr); QV4::ExecutionEngine *engine() const { return m_engine; } - QJsonArray flushCollectedRefs(); + QJsonArray flushCollectedRefs(); // only for redundantRefs void clear(); private: Ref addRef(QV4::Value value, bool deduplicate = true); QV4::ReturnedValue getValue(Ref ref); - bool lookupSpecialRef(Ref ref, QJsonObject *dict); + bool lookupSpecialRef(Ref ref, QJsonObject *dict); // only for namesAsObjects QJsonArray collectProperties(const QV4::Object *object); QJsonObject collectAsJson(const QString &name, const QV4::ScopedValue &value); void collectArgumentsInContext(); QV4::ExecutionEngine *m_engine; - Refs m_collectedRefs; + Refs m_collectedRefs; // only for redundantRefs QV4::PersistentValue m_values; - typedef QHash SpecialRefs; - SpecialRefs m_specialRefs; + typedef QHash SpecialRefs; // only for namesAsObjects + SpecialRefs m_specialRefs; // only for namesAsObjects + bool m_namesAsObjects; + bool m_redundantRefs; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp index df316c1ae6..a624cf22a4 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp @@ -148,7 +148,7 @@ void BacktraceJob::run() result.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size()); result.insert(QStringLiteral("frames"), frameArray); } - collectedRefs = collector->flushCollectedRefs(); + flushRedundantRefs(); } FrameJob::FrameJob(QV4DataCollector *collector, int frameNr) : @@ -163,7 +163,7 @@ void FrameJob::run() success = false; } else { result = collector->buildFrame(frames[frameNr], frameNr); - collectedRefs = collector->flushCollectedRefs(); + flushRedundantRefs(); success = true; } } @@ -193,7 +193,7 @@ void ScopeJob::run() result[QLatin1String("index")] = scopeNr; result[QLatin1String("frameIndex")] = frameNr; result[QLatin1String("object")] = object; - collectedRefs = collector->flushCollectedRefs(); + flushRedundantRefs(); } bool ScopeJob::wasSuccessful() const @@ -223,9 +223,9 @@ void ValueLookupJob::run() exception = QString::fromLatin1("Invalid Ref: %1").arg(ref); break; } - result[QString::number(ref)] = collector->lookupRef(ref); + result[QString::number(ref)] = collector->lookupRef(ref, true); } - collectedRefs = collector->flushCollectedRefs(); + flushRedundantRefs(); if (scopeObject) engine->popContext(); } @@ -246,8 +246,9 @@ void ExpressionEvalJob::handleResult(QV4::ScopedValue &value) { if (hasExeption()) exception = value->toQStringNoThrow(); - result = collector->lookupRef(collector->collect(value)); - collectedRefs = collector->flushCollectedRefs(); + result = collector->lookupRef(collector->collect(value), true); + if (collector->redundantRefs()) + collectedRefs = collector->flushCollectedRefs(); } const QString &ExpressionEvalJob::exceptionMessage() const @@ -260,8 +261,10 @@ const QJsonObject &ExpressionEvalJob::returnValue() const return result; } +// TODO: Drop this method once we don't need to support redundantRefs anymore const QJsonArray &ExpressionEvalJob::refs() const { + Q_ASSERT(collector->redundantRefs()); return collectedRefs; } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h index 00d3e6206a..eca8710e15 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h @@ -78,11 +78,24 @@ class CollectJob : public QV4DebugJob protected: QV4DataCollector *collector; QJsonObject result; - QJsonArray collectedRefs; + QJsonArray collectedRefs; // only for redundantRefs + + void flushRedundantRefs() + { + if (collector->redundantRefs()) + collectedRefs = collector->flushCollectedRefs(); + } + public: CollectJob(QV4DataCollector *collector) : collector(collector) {} const QJsonObject &returnValue() const { return result; } - const QJsonArray &refs() const { return collectedRefs; } + + // TODO: Drop this method once we don't need to support redundantRefs anymore + const QJsonArray &refs() const + { + Q_ASSERT(collector->redundantRefs()); + return collectedRefs; + } }; class BacktraceJob: public CollectJob @@ -133,7 +146,7 @@ class ExpressionEvalJob: public JavaScriptJob QV4DataCollector *collector; QString exception; QJsonObject result; - QJsonArray collectedRefs; + QJsonArray collectedRefs; // only for redundantRefs public: ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, int context, @@ -141,7 +154,7 @@ public: void handleResult(QV4::ScopedValue &value) override; const QString &exceptionMessage() const; const QJsonObject &returnValue() const; - const QJsonArray &refs() const; + const QJsonArray &refs() const; // only for redundantRefs }; class GatherSourcesJob: public QV4DebugJob diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp index 1d2cc092dc..fbf6397a18 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp @@ -121,8 +121,18 @@ protected: response.insert(QStringLiteral("running"), debugService->debuggerAgent.isRunning()); } + QV4DataCollector *saneCollector(QV4Debugger *debugger) + { + QV4DataCollector *collector = debugger->collector(); + collector->setNamesAsObjects(debugService->clientRequiresNamesAsObjects()); + collector->setRedundantRefs(debugService->clientRequiresRedundantRefs()); + return collector; + } + + // TODO: drop this method once we don't need to support redundantRefs anymore. void addRefs(const QJsonArray &refs) { + Q_ASSERT(debugService->clientRequiresRedundantRefs()); response.insert(QStringLiteral("refs"), refs); } @@ -286,7 +296,7 @@ public: return; } - BacktraceJob job(debugger->collector(), fromFrame, toFrame); + BacktraceJob job(saneCollector(debugger), fromFrame, toFrame); debugger->runInEngine(&job); // response: @@ -295,7 +305,8 @@ public: addSuccess(true); addRunning(); addBody(job.returnValue()); - addRefs(job.refs()); + if (debugService->clientRequiresRedundantRefs()) + addRefs(job.refs()); } }; @@ -322,7 +333,7 @@ public: return; } - FrameJob job(debugger->collector(), frameNr); + FrameJob job(saneCollector(debugger), frameNr); debugger->runInEngine(&job); if (!job.wasSuccessful()) { createErrorResponse(QStringLiteral("frame retrieval failed")); @@ -337,7 +348,8 @@ public: addSuccess(true); addRunning(); addBody(job.returnValue()); - addRefs(job.refs()); + if (debugService->clientRequiresRedundantRefs()) + addRefs(job.refs()); } }; @@ -369,7 +381,7 @@ public: return; } - ScopeJob job(debugger->collector(), frameNr, scopeNr); + ScopeJob job(saneCollector(debugger), frameNr, scopeNr); debugger->runInEngine(&job); if (!job.wasSuccessful()) { createErrorResponse(QStringLiteral("scope retrieval failed")); @@ -382,7 +394,8 @@ public: addSuccess(true); addRunning(); addBody(job.returnValue()); - addRefs(job.refs()); + if (debugService->clientRequiresRedundantRefs()) + addRefs(job.refs()); } }; @@ -410,7 +423,7 @@ public: debugger = debuggers.first(); } - ValueLookupJob job(handles, debugger->collector()); + ValueLookupJob job(handles, saneCollector(debugger)); debugger->runInEngine(&job); if (!job.exceptionMessage().isEmpty()) { createErrorResponse(job.exceptionMessage()); @@ -421,7 +434,8 @@ public: addSuccess(true); addRunning(); addBody(job.returnValue()); - addRefs(job.refs()); + if (debugService->clientRequiresRedundantRefs()) + addRefs(job.refs()); } } }; @@ -630,7 +644,7 @@ public: } ExpressionEvalJob job(debugger->engine(), frame, context, expression, - debugger->collector()); + saneCollector(debugger)); debugger->runInEngine(&job); if (job.hasExeption()) { createErrorResponse(job.exceptionMessage()); @@ -640,7 +654,8 @@ public: addSuccess(true); addRunning(); addBody(job.returnValue()); - addRefs(job.refs()); + if (debugService->clientRequiresRedundantRefs()) + addRefs(job.refs()); } } }; @@ -662,7 +677,7 @@ V8CommandHandler *QV4DebugServiceImpl::v8CommandHandler(const QString &command) QV4DebugServiceImpl::QV4DebugServiceImpl(QObject *parent) : QQmlConfigurableDebugService(1, parent), - debuggerAgent(this), theSelectedFrame(0), + debuggerAgent(this), theSelectedFrame(0), redundantRefs(true), namesAsObjects(true), unknownV8CommandHandler(new UnknownV8CommandHandler) { addHandler(new V8VersionRequest); @@ -766,6 +781,14 @@ void QV4DebugServiceImpl::messageReceived(const QByteArray &message) TRACE_PROTOCOL(qDebug() << "... type:" << type); if (type == V4_CONNECT) { + QJsonObject parameters = QJsonDocument::fromJson(payload).object(); + namesAsObjects = true; + redundantRefs = true; + if (parameters.contains("namesAsObjects")) + namesAsObjects = parameters.value("namesAsObjects").toBool(); + if (parameters.contains("redundantRefs")) + namesAsObjects = parameters.value("redundantRefs").toBool(); + emit messageToClient(name(), packMessage(type)); stopWaiting(); } else if (type == V4_PAUSE) { diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h index 69e32189b8..bb13890ae4 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h @@ -86,6 +86,9 @@ public: int selectedFrame() const; void selectFrame(int frameNr); + bool clientRequiresRedundantRefs() const { return redundantRefs; } + bool clientRequiresNamesAsObjects() const { return namesAsObjects; } + QV4DebuggerAgent debuggerAgent; protected: @@ -105,6 +108,9 @@ private: static int sequence; int theSelectedFrame; + bool redundantRefs; + bool namesAsObjects; + void addHandler(V8CommandHandler* handler); QHash handlers; QScopedPointer unknownV8CommandHandler; -- cgit v1.2.3 From 8469f0501d9c581a6b2fd2e380187a00b47c6f8d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 14 Mar 2017 17:32:08 +0100 Subject: V4 Debugger: Fix typo We want to set redundantRefs if the client states "redundantRefs". Change-Id: I277120e3feedec14492679ad827845732dc36495 Reviewed-by: Simon Hausmann --- src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp index fbf6397a18..68cdb57a44 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp @@ -787,7 +787,7 @@ void QV4DebugServiceImpl::messageReceived(const QByteArray &message) if (parameters.contains("namesAsObjects")) namesAsObjects = parameters.value("namesAsObjects").toBool(); if (parameters.contains("redundantRefs")) - namesAsObjects = parameters.value("redundantRefs").toBool(); + redundantRefs = parameters.value("redundantRefs").toBool(); emit messageToClient(name(), packMessage(type)); stopWaiting(); -- cgit v1.2.3 From 8675bb6b5a4721aa4d94dcb3cb98dbed061c164f Mon Sep 17 00:00:00 2001 From: Christoph Sterz Date: Fri, 18 Dec 2015 13:18:46 +0100 Subject: Doc: Removed non-working reimplementation suggestions QSGSimpleMaterialShader::uniformMatrixName() and QSGSimpleMaterialShader::uniformOpacityName() cannot be reimplemented since they are non-virtual. Removed the suggestion, so nobody is tempted to do so. Added a Remark in the header to fix towards intended behavior in Qt6. Change-Id: Id23c8d54728095f143f1d0e0520590303cff91a0 Reviewed-by: Giuseppe D'Angelo Reviewed-by: Leena Miettinen Reviewed-by: Jan Arne Petersen Reviewed-by: Gunnar Sletta --- src/quick/scenegraph/util/qsgsimplematerial.cpp | 12 ++++-------- src/quick/scenegraph/util/qsgsimplematerial.h | 1 + 2 files changed, 5 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/quick/scenegraph/util/qsgsimplematerial.cpp b/src/quick/scenegraph/util/qsgsimplematerial.cpp index 7214a255df..f29c58ad9e 100644 --- a/src/quick/scenegraph/util/qsgsimplematerial.cpp +++ b/src/quick/scenegraph/util/qsgsimplematerial.cpp @@ -194,19 +194,15 @@ /*! \fn const char *QSGSimpleMaterialShader::uniformMatrixName() const - Reimplement this function to give a different name to the uniform for - item transformation. The default value is \c qt_Matrix. - + Returns the name for the transform matrix uniform of this item. + The default value is \c qt_Matrix. */ /*! \fn const char *QSGSimpleMaterialShader::uniformOpacityName() const - Reimplement this function to give a different name to the uniform for - item opacity. The default value is \c qt_Opacity. - - If the shader program does not implement the item opacity, the - implemented function should return a null pointer. + Returns the name for the opacity uniform of this item. + The default value is \c qt_Opacity. */ /*! diff --git a/src/quick/scenegraph/util/qsgsimplematerial.h b/src/quick/scenegraph/util/qsgsimplematerial.h index 8f42599832..80593c755b 100644 --- a/src/quick/scenegraph/util/qsgsimplematerial.h +++ b/src/quick/scenegraph/util/qsgsimplematerial.h @@ -71,6 +71,7 @@ public: resolveUniforms(); } + // ### Qt 6: make both virtual and fix docs const char *uniformMatrixName() const { return "qt_Matrix"; } const char *uniformOpacityName() const { return "qt_Opacity"; } -- cgit v1.2.3 From 212ccd59627deb8c06227dbf0f3f3329006c326e Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Mon, 13 Mar 2017 16:33:18 +0100 Subject: QSGDistanceFieldGlyphNode: Remove per-node QLinkedList of nodes to delete We avoided deleting these nodes directly due to preprocess, but this is a bit of a hack. QSGRenderer::preprocess already contains some work to allow for modification of nodes at preprocess time, but it didn't allow for detecting dead nodes. By marking a pointer as not to be touched if it is removed during preprocess, we can remove the per-node QLinkedList and delete directly, while at the same time, still not touching deleted nodes later on in preprocess. Change-Id: I99a1ea65d3fe0b73db73e4a1d10d999d56edcdc4 Reviewed-by: Gunnar Sletta --- src/quick/scenegraph/coreapi/qsgrenderer.cpp | 20 +++++++++++++++++++- src/quick/scenegraph/coreapi/qsgrenderer_p.h | 2 ++ src/quick/scenegraph/qsgdistancefieldglyphnode.cpp | 15 ++++----------- src/quick/scenegraph/qsgdistancefieldglyphnode_p.h | 1 - 4 files changed, 25 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp index 9207fdbc55..bb2671f6c3 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp @@ -134,6 +134,7 @@ QSGRenderer::QSGRenderer(QSGRenderContext *context) , m_bindable(0) , m_changed_emitted(false) , m_is_rendering(false) + , m_is_preprocessing(false) { } @@ -287,6 +288,8 @@ void QSGRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state) void QSGRenderer::preprocess() { + m_is_preprocessing = true; + QSGRootNode *root = rootNode(); Q_ASSERT(root); @@ -298,6 +301,11 @@ void QSGRenderer::preprocess() for (QSet::const_iterator it = items.constBegin(); it != items.constEnd(); ++it) { QSGNode *n = *it; + + // If we are currently preprocessing, check this node hasn't been + // deleted or something. we don't want a use-after-free! + if (m_nodes_dont_preprocess.contains(n)) // skip + continue; if (!nodeUpdater()->isNodeBlocked(n, root)) { n->preprocess(); } @@ -315,8 +323,13 @@ void QSGRenderer::preprocess() updatePassTime = frameTimer.nsecsElapsed(); Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame, QQuickProfiler::SceneGraphRendererUpdate); + + m_is_preprocessing = false; + m_nodes_dont_preprocess.clear(); } + + void QSGRenderer::addNodesToPreprocess(QSGNode *node) { for (QSGNode *c = node->firstChild(); c; c = c->nextSibling()) @@ -329,8 +342,13 @@ void QSGRenderer::removeNodesToPreprocess(QSGNode *node) { for (QSGNode *c = node->firstChild(); c; c = c->nextSibling()) removeNodesToPreprocess(c); - if (node->flags() & QSGNode::UsePreprocess) + if (node->flags() & QSGNode::UsePreprocess) { m_nodes_to_preprocess.remove(node); + + // If preprocessing *now*, mark the node as gone. + if (m_is_preprocessing) + m_nodes_dont_preprocess.insert(node); + } } diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h index 4589685765..1ea2775e6f 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h @@ -118,11 +118,13 @@ private: QSGNodeUpdater *m_node_updater; QSet m_nodes_to_preprocess; + QSet m_nodes_dont_preprocess; const QSGBindable *m_bindable; uint m_changed_emitted : 1; uint m_is_rendering : 1; + uint m_is_preprocessing : 1; }; class Q_QUICK_PRIVATE_EXPORT QSGBindable diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp index 456a197ba1..11c5444cd2 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp @@ -76,9 +76,6 @@ QSGDistanceFieldGlyphNode::~QSGDistanceFieldGlyphNode() m_glyph_cache->unregisterGlyphNode(this); m_glyph_cache->unregisterOwnerElement(ownerElement()); } - - while (m_nodesToDelete.count()) - delete m_nodesToDelete.takeLast(); } void QSGDistanceFieldGlyphNode::setColor(const QColor &color) @@ -158,9 +155,6 @@ void QSGDistanceFieldGlyphNode::preprocess() { Q_ASSERT(m_glyph_cache); - while (m_nodesToDelete.count()) - delete m_nodesToDelete.takeLast(); - m_glyph_cache->processPendingGlyphs(); m_glyph_cache->update(); @@ -188,13 +182,12 @@ void QSGDistanceFieldGlyphNode::updateGeometry() // Remove previously created sub glyph nodes // We assume all the children are sub glyph nodes QSGNode *subnode = firstChild(); + QSGNode *nextNode = 0; while (subnode) { - // We can't delete the node now as it might be in the preprocess list - // It will be deleted in the next preprocess - m_nodesToDelete.append(subnode); - subnode = subnode->nextSibling(); + nextNode = subnode->nextSibling(); + delete subnode; + subnode = nextNode; } - removeAllChildNodes(); QSGGeometry *g = geometry(); diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h index c0c6bda718..04446c7b2c 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h @@ -107,7 +107,6 @@ private: AntialiasingMode m_antialiasingMode; QRectF m_boundingRect; const QSGDistanceFieldGlyphCache::Texture *m_texture; - QLinkedList m_nodesToDelete; struct GlyphInfo { QVector indexes; -- cgit v1.2.3 From af9536deeaf1123aaae5ce78cee7b4014a01d595 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 15 Mar 2017 13:29:24 +0100 Subject: Fix QQmlMetaType::prettyTypeName to deal with malformed type names We can have QML type names that are empty or end in '/'. In those cases use the QMetaObject to retrieve a more meaningful type name. Change-Id: I4dd0841de13d4e7524a104f0bbc08cb854484cfe Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlmetatype.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index bd6b9a1599..bb9b69c479 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -1971,7 +1971,9 @@ QString QQmlMetaType::prettyTypeName(const QObject *object) const int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); if (lastSlash != -1) typeName = typeName.mid(lastSlash + 1); - } else { + } + + if (typeName.isEmpty()) { typeName = QString::fromUtf8(object->metaObject()->className()); int marker = typeName.indexOf(QLatin1String("_QMLTYPE_")); if (marker != -1) @@ -1982,10 +1984,12 @@ QString QQmlMetaType::prettyTypeName(const QObject *object) typeName = typeName.leftRef(marker) + QLatin1Char('*'); type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1())); if (type) { - typeName = type->qmlTypeName(); - const int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); + QString qmlTypeName = type->qmlTypeName(); + const int lastSlash = qmlTypeName.lastIndexOf(QLatin1Char('/')); if (lastSlash != -1) - typeName = typeName.mid(lastSlash + 1); + qmlTypeName = qmlTypeName.mid(lastSlash + 1); + if (!qmlTypeName.isEmpty()) + typeName = qmlTypeName; } } } -- cgit v1.2.3 From 34ff6c40c1a03f51bc259e57cffb02ad69c7663b Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Wed, 18 Jan 2017 16:26:43 +0100 Subject: qml: Override the new Object::instanceOf hook to allow QML type checking [ChangeLog][QtQml] The instanceof keyword in JavaScript has been extended to work on QML types and instances. This means that you are now able to use it to verify that a var is indeed the type you expect (e.g. someVar instanceof Rectangle). Note that one of the added tests revealed a slight shortcoming in the QML type system (QTBUG-58477). For now, we should keep consistency and work to address the problem universally in the future. Change-Id: I7d9bf9b64cfd037908de1ae51b01065eacb95abe Task-number: QTBUG-24799 Reviewed-by: Simon Hausmann --- src/qml/doc/src/javascript/hostenvironment.qdoc | 13 ++++++++ src/qml/qml/qqmltypewrapper.cpp | 40 +++++++++++++++++++++++++ src/qml/qml/qqmltypewrapper_p.h | 2 +- 3 files changed, 54 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc index 1e33f2f641..7e9a22f5d3 100644 --- a/src/qml/doc/src/javascript/hostenvironment.qdoc +++ b/src/qml/doc/src/javascript/hostenvironment.qdoc @@ -74,6 +74,19 @@ Note that QML makes the following modifications to native objects: \li Locale-aware conversion functions are added to the \l Date and \l Number prototypes. \endlist +In addition, QML also extends the behavior of the instanceof function to +allow for type checking against QML types. This means that you may use it to +verify that a variable is indeed the type you expect, for example: + +\qml + var v = something(); + if (!v instanceof Item) { + throw new TypeError("I need an Item type!"); + } + + ... +\endqml + \section1 JavaScript Environment Restrictions diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 49103ed653..7b98096a7f 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -342,4 +342,44 @@ bool QmlTypeWrapper::isEqualTo(Managed *a, Managed *b) return false; } +ReturnedValue QmlTypeWrapper::instanceOf(const Object *typeObject, const Value &var) +{ + Q_ASSERT(typeObject->as()); + const QV4::QmlTypeWrapper *typeWrapper = static_cast(typeObject); + QV4::ExecutionEngine *engine = typeObject->internalClass()->engine; + QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(engine->qmlEngine()); + + // can only compare a QObject* against a QML type + const QObjectWrapper *wrapper = var.as(); + if (!wrapper) + return engine->throwTypeError(); + + // in case the wrapper outlived the QObject* + const QObject *wrapperObject = wrapper->object(); + if (!wrapperObject) + return engine->throwTypeError(); + + const int myTypeId = typeWrapper->d()->type->typeId(); + QQmlMetaObject myQmlType; + if (myTypeId == 0) { + // we're a composite type; a composite type cannot be equal to a + // non-composite object instance (Rectangle{} is never an instance of + // CustomRectangle) + QQmlData *theirDData = QQmlData::get(wrapperObject, /*create=*/false); + Q_ASSERT(theirDData); // must exist, otherwise how do we have a QObjectWrapper for it?! + if (!theirDData->compilationUnit) + return Encode(false); + + QQmlTypeData *td = qenginepriv->typeLoader.getType(typeWrapper->d()->type->sourceUrl()); + CompiledData::CompilationUnit *cu = td->compilationUnit(); + myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId); + } else { + myQmlType = qenginepriv->metaObjectForType(myTypeId); + } + + const QMetaObject *theirType = wrapperObject->metaObject(); + + return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType)); +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index cfb6cb0ec9..c584458ed4 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -103,7 +103,7 @@ struct Q_QML_EXPORT QmlTypeWrapper : Object static bool put(Managed *m, String *name, const Value &value); static PropertyAttributes query(const Managed *, String *name); static bool isEqualTo(Managed *that, Managed *o); - + static ReturnedValue instanceOf(const Object *typeObject, const Value &var); }; } -- cgit v1.2.3 From e7a6544225a5ab3749230fc6783a5145e02dbe32 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 23 Feb 2017 16:26:53 +0100 Subject: Use qRadiansToDegrees() more widely It documents the meaning of the computation more clearly. Task-number: QTBUG-58083 Change-Id: Ie2d486d1e1919569de5a1565e783703b9b3bc813 Reviewed-by: Robin Burchell --- src/quick/items/context2d/qquickcontext2d.cpp | 12 +++++------- src/quick/items/qquickitemanimation.cpp | 2 +- src/quick/items/qquickstateoperations.cpp | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index cf34523693..66afd3828b 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -128,8 +128,6 @@ QT_BEGIN_NAMESPACE Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok); -#define DEGREES(t) ((t) * 180.0 / M_PI) - #define CHECK_CONTEXT(r) if (!r || !r->d()->context || !r->d()->context->bufferValid()) \ THROW_GENERIC_ERROR("Not a Context2D object"); @@ -1641,7 +1639,7 @@ void QQuickJSContext2DPrototype::method_createConicalGradient(const QV4::Builtin if (callData->argc >= 3) { qreal x = callData->args[0].toNumber(); qreal y = callData->args[1].toNumber(); - qreal angle = DEGREES(callData->args[2].toNumber()); + qreal angle = qRadiansToDegrees(callData->args[2].toNumber()); if (!qt_is_finite(x) || !qt_is_finite(y)) { THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments"); } @@ -3366,7 +3364,7 @@ void QQuickContext2D::rotate(qreal angle) return; QTransform newTransform =state.matrix; - newTransform.rotate(DEGREES(angle)); + newTransform.rotate(qRadiansToDegrees(angle)); if (!newTransform.isInvertible()) { state.invertibleCTM = false; @@ -3375,7 +3373,7 @@ void QQuickContext2D::rotate(qreal angle) state.matrix = newTransform; buffer()->updateMatrix(state.matrix); - m_path = QTransform().rotate(-DEGREES(angle)).map(m_path); + m_path = QTransform().rotate(-qRadiansToDegrees(angle)).map(m_path); } void QQuickContext2D::shear(qreal h, qreal v) @@ -3772,8 +3770,8 @@ void QQuickContext2D::arc(qreal xc, qreal yc, qreal radius, qreal sar, qreal ear antiClockWise = !antiClockWise; //end hack - float sa = DEGREES(sar); - float ea = DEGREES(ear); + float sa = qRadiansToDegrees(sar); + float ea = qRadiansToDegrees(ear); double span = 0; diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp index 9873622f41..874130b137 100644 --- a/src/quick/items/qquickitemanimation.cpp +++ b/src/quick/items/qquickitemanimation.cpp @@ -327,7 +327,7 @@ QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &act } if (scale != 0) - rotation = qAtan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI; + rotation = qRadiansToDegrees(qAtan2(transform.m12() / scale, transform.m11() / scale)); else { qmlWarning(this) << QQuickParentAnimation::tr("Unable to preserve appearance under scale of 0"); ok = false; diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp index b40a9e2843..a4ce13a199 100644 --- a/src/quick/items/qquickstateoperations.cpp +++ b/src/quick/items/qquickstateoperations.cpp @@ -101,7 +101,7 @@ void QQuickParentChangePrivate::doChange(QQuickItem *targetParent, QQuickItem *s } if (scale != 0) - rotation = qAtan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI; + rotation = qRadiansToDegrees(qAtan2(transform.m12() / scale, transform.m11() / scale)); else { qmlWarning(q) << QQuickParentChange::tr("Unable to preserve appearance under scale of 0"); ok = false; -- cgit v1.2.3 From aa570a7720dc508f83c32aee81ac1d6ea21d6757 Mon Sep 17 00:00:00 2001 From: Nikita Krupenko Date: Sat, 11 Jun 2016 20:03:45 +0300 Subject: Flickable: fix doc statement about content anchoring Task-number: QTBUG-54101 Change-Id: I3b0a0225efb77003c1c80c1d5b94ab572f3cc785 Reviewed-by: Shawn Rutledge --- src/quick/items/qquickflickable.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index d97c731157..6a2946bdcc 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -642,8 +642,10 @@ is finished. \section1 Limitations - \note Due to an implementation detail, items placed inside a Flickable cannot anchor to it by - \c id. Use \c parent instead. + \note Due to an implementation detail, items placed inside a Flickable + cannot anchor to the Flickable. Instead, use \l {Item::}{parent}, which + refers to the Flickable's \l contentItem. The size of the content item is + determined by \l contentWidth and \l contentHeight. */ /*! -- cgit v1.2.3 From 7efa1e60d24fee9b1745c30965949af78f3fb0f3 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 13 Mar 2017 14:26:07 +0100 Subject: Fix running of 32-bit JIT code generated on 64-bit hosts The offsets of members encoded in JIT generated code differ between 32-bit and 64-bit architectures. This patch moves some of the ExecutionEngine members into a separate standard-layout EngineBase class (in line with the same class in commit 2a554434a571dcefd26cf10ef8c5ae8b3b7d66db and subject to merging). By ensuring that the members are stored at pointer intervals, we can translate from host pointer size to target when generating the code. Task-number: QTBUG-58666 Change-Id: I1c38a7da059826848b80fd9972ed073214501386 Reviewed-by: Qt CI Bot Reviewed-by: Lars Knoll --- src/qml/jit/qv4assembler.cpp | 10 +++++----- src/qml/jit/qv4assembler_p.h | 14 ++++++++++---- src/qml/jit/qv4isel_masm.cpp | 4 ++-- src/qml/jsruntime/qv4engine.cpp | 4 +--- src/qml/jsruntime/qv4engine_p.h | 6 +----- src/qml/memory/qv4mmdefs_p.h | 20 ++++++++++++++++++++ 6 files changed, 39 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index ad8a5823e2..263f332f33 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -269,7 +269,7 @@ typename Assembler::Pointer Assembler: { int32_t offset = 0; int scope = al->scope; - loadPtr(Address(EngineRegister, qOffsetOf(ExecutionEngine, current)), baseReg); + loadPtr(Address(EngineRegister, targetStructureOffset(offsetof(EngineBase, current))), baseReg); if (scope) { loadPtr(Address(baseReg, qOffsetOf(ExecutionContext::Data, outer)), baseReg); --scope; @@ -298,7 +298,7 @@ typename Assembler::Pointer Assembler: template typename Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &string) { - loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister); + loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), Assembler::ScratchRegister); loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, compilationUnit)), Assembler::ScratchRegister); loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg); const int id = _jsGenerator->registerString(string); @@ -314,7 +314,7 @@ typename Assembler::Address Assembler: template typename Assembler::Address Assembler::loadConstant(const Primitive &v, RegisterID baseReg) { - loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), baseReg); + loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), baseReg); loadPtr(Address(baseReg, qOffsetOf(QV4::Heap::ExecutionContext, constantTable)), baseReg); const int index = _jsGenerator->registerConstant(v.asReturnedValue()); return Address(baseReg, index * sizeof(QV4::Value)); @@ -518,9 +518,9 @@ void Assembler::returnFromFunction(IR::Ret *s, RegisterInfo const int locals = stackLayout().calculateJSStackFrameSize(); subPtr(TrustedImm32(sizeof(QV4::Value)*locals), JITTargetPlatform::LocalsRegister); - loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister); + loadPtr(Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister); loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, engine)), JITTargetPlatform::ScratchRegister); - storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop))); + storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::ScratchRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop)))); leaveStandardStackFrame(regularRegistersToSave, fpRegistersToSave); ret(); diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 720c522e1d..0a27ab02cf 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -713,6 +713,12 @@ public: using JITTargetPlatform::platformFinishEnteringStandardStackFrame; using JITTargetPlatform::platformLeaveStandardStackFrame; + static qint32 targetStructureOffset(qint32 hostOffset) + { + Q_ASSERT(hostOffset % QT_POINTER_SIZE == 0); + return (hostOffset * RegisterSize) / QT_POINTER_SIZE; + } + using RegisterSizeDependentOps = RegisterSizeDependentAssembler, MacroAssembler, JITTargetPlatform, RegisterSize>; struct LookupCall { @@ -1249,7 +1255,7 @@ public: const RegisterInformation &fpRegistersToSave); void checkException() { - load32(Address(EngineRegister, qOffsetOf(QV4::ExecutionEngine, hasException)), ScratchRegister); + load32(Address(EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, hasException))), ScratchRegister); Jump exceptionThrown = branch32(RelationalCondition::NotEqual, ScratchRegister, TrustedImm32(0)); if (catchBlock) addPatch(catchBlock, exceptionThrown); @@ -1317,7 +1323,7 @@ public: // IMPORTANT! See generateLookupCall in qv4isel_masm_p.h for details! // load the table from the context - loadPtr(Address(EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), ScratchRegister); + loadPtr(Address(EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), ScratchRegister); loadPtr(Address(ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, lookups)), lookupCall.addr.base); // pre-calculate the indirect address for the lookupCall table: @@ -1616,9 +1622,9 @@ public: const int locals = _stackLayout->calculateJSStackFrameSize(); if (locals <= 0) return; - loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)), JITTargetPlatform::LocalsRegister); + loadPtr(Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop))), JITTargetPlatform::LocalsRegister); RegisterSizeDependentOps::initializeLocalVariables(this, locals); - storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop))); + storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop)))); } Label exceptionReturnLabel; diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 69d6951bb9..3cbed3ce56 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -132,7 +132,7 @@ void InstructionSelection::run(int functionIndex) for (IR::Stmt *s : _block->statements()) { if (s->location.isValid()) { if (int(s->location.startLine) != lastLine) { - _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister); + _as->loadPtr(Address(JITTargetPlatform::EngineRegister, JITAssembler::targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister); Address lineAddr(JITTargetPlatform::ScratchRegister, qOffsetOf(QV4::ExecutionContext::Data, lineNumber)); _as->store32(TrustedImm32(s->location.startLine), lineAddr); lastLine = s->location.startLine; @@ -447,7 +447,7 @@ void InstructionSelection::callValue(IR::Expr *value, IR::ExprList template void InstructionSelection::loadThisObject(IR::Expr *temp) { - _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister); + _as->loadPtr(Address(JITTargetPlatform::EngineRegister, JITAssembler::targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister); _as->loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), JITTargetPlatform::ScratchRegister); _as->copyValue(temp, Address(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject))); } diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index f925c9184c..3f11e51799 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -130,9 +130,7 @@ QQmlEngine *ExecutionEngine::qmlEngine() const qint32 ExecutionEngine::maxCallDepth = -1; ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) - : current(0) - , hasException(false) - , callDepth(0) + : callDepth(0) , memoryManager(new QV4::MemoryManager(this)) , executableAllocator(new QV4::ExecutableAllocator) , regExpAllocator(new QV4::ExecutableAllocator) diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 69aa389c44..6de087a4e2 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -88,7 +88,7 @@ struct CompilationUnit; struct InternalClass; struct InternalClassPool; -struct Q_QML_EXPORT ExecutionEngine +struct Q_QML_EXPORT ExecutionEngine : public EngineBase { private: static qint32 maxCallDepth; @@ -97,10 +97,6 @@ private: friend struct ExecutionContext; friend struct Heap::ExecutionContext; public: - Heap::ExecutionContext *current; - - Value *jsStackTop; - quint32 hasException; qint32 callDepth; MemoryManager *memoryManager; diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index 588ae21ee0..edae7293ce 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -255,6 +255,26 @@ Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize); Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits); Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits); +// Base class for the execution engine + +#if defined(Q_CC_MSVC) || defined(Q_CC_GNU) +#pragma pack(push, 1) +#endif +struct EngineBase { + Heap::ExecutionContext *current = 0; + + Value *jsStackTop = 0; + quint32 hasException = false; +}; +#if defined(Q_CC_MSVC) || defined(Q_CC_GNU) +#pragma pack(pop) +#endif + +Q_STATIC_ASSERT(std::is_standard_layout::value); +Q_STATIC_ASSERT(offsetof(EngineBase, current) == 0); +Q_STATIC_ASSERT(offsetof(EngineBase, jsStackTop) == offsetof(EngineBase, current) + QT_POINTER_SIZE); +Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsStackTop) + QT_POINTER_SIZE); + } QT_END_NAMESPACE -- cgit v1.2.3 From 8e64fdf246a9076d4044e6c78af29e499f48905c Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 9 Feb 2017 15:53:13 +0100 Subject: Prepare run-time method calling mechanism for cross-compilation The current way of encoding the offsetof() of the method_ members in QV4::Runtime is not portable when cross-compiling from a 64-bit host (where the offsetof would be calculated on) to a 32-bit target (where the offset would be different), or vice versa. In preparation for making this work, this patch first replaces the direct use of the run-time members with use through a void * and an enum for indexing. This gives us some type-safety in some places and will also allow for a translation of the pointer offset from host pointer indexing to target pointer indexes. As a bonus we can avoid going through the engine->runtime indirection in the interpreter altogether and call the static methods right away. Task-number: QTBUG-58666 Change-Id: I3cd6459523923a9719408317fa729bca19c2bf3c Reviewed-by: Lars Knoll --- src/qml/compiler/qv4compileddata_p.h | 2 +- src/qml/compiler/qv4instr_moth_p.h | 2 +- src/qml/compiler/qv4isel_moth.cpp | 75 +++---- src/qml/jit/qv4assembler_p.h | 9 +- src/qml/jit/qv4binop.cpp | 10 +- src/qml/jit/qv4binop_p.h | 4 +- src/qml/jit/qv4isel_masm.cpp | 4 +- src/qml/jit/qv4unop.cpp | 2 +- src/qml/jsruntime/qv4arraydata.cpp | 2 +- src/qml/jsruntime/qv4engine_p.h | 6 +- src/qml/jsruntime/qv4runtimeapi_p.h | 392 ++++++++++++++--------------------- src/qml/jsruntime/qv4vme_moth.cpp | 132 ++++++------ 12 files changed, 282 insertions(+), 358 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 23139d6c8e..110baafabe 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -71,7 +71,7 @@ QT_BEGIN_NAMESPACE // Bump this whenever the compiler data structures change in an incompatible way. -#define QV4_DATA_STRUCTURE_VERSION 0x09 +#define QV4_DATA_STRUCTURE_VERSION 0x10 class QIODevice; class QQmlPropertyCache; diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 53d9956315..fbd6ac8f99 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -690,7 +690,7 @@ union Instr }; struct instr_binop { MOTH_INSTR_HEADER - uint alu; // offset inside the runtime methods + int alu; // QV4::Runtime::RuntimeMethods enum value Param lhs; Param rhs; Param result; diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index 04844302d9..aefb084971 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -55,70 +55,70 @@ using namespace QV4::Moth; namespace { -inline uint aluOpFunction(IR::AluOp op) +inline QV4::Runtime::RuntimeMethods aluOpFunction(IR::AluOp op) { switch (op) { case IR::OpInvalid: - return 0; + return QV4::Runtime::InvalidRuntimeMethod; case IR::OpIfTrue: - return 0; + return QV4::Runtime::InvalidRuntimeMethod; case IR::OpNot: - return 0; + return QV4::Runtime::InvalidRuntimeMethod; case IR::OpUMinus: - return 0; + return QV4::Runtime::InvalidRuntimeMethod; case IR::OpUPlus: - return 0; + return QV4::Runtime::InvalidRuntimeMethod; case IR::OpCompl: - return 0; + return QV4::Runtime::InvalidRuntimeMethod; case IR::OpBitAnd: - return offsetof(QV4::Runtime, bitAnd); + return QV4::Runtime::bitAnd; case IR::OpBitOr: - return offsetof(QV4::Runtime, bitOr); + return QV4::Runtime::bitOr; case IR::OpBitXor: - return offsetof(QV4::Runtime, bitXor); + return QV4::Runtime::bitXor; case IR::OpAdd: - return 0; + return QV4::Runtime::InvalidRuntimeMethod; case IR::OpSub: - return offsetof(QV4::Runtime, sub); + return QV4::Runtime::sub; case IR::OpMul: - return offsetof(QV4::Runtime, mul); + return QV4::Runtime::mul; case IR::OpDiv: - return offsetof(QV4::Runtime, div); + return QV4::Runtime::div; case IR::OpMod: - return offsetof(QV4::Runtime, mod); + return QV4::Runtime::mod; case IR::OpLShift: - return offsetof(QV4::Runtime, shl); + return QV4::Runtime::shl; case IR::OpRShift: - return offsetof(QV4::Runtime, shr); + return QV4::Runtime::shr; case IR::OpURShift: - return offsetof(QV4::Runtime, ushr); + return QV4::Runtime::ushr; case IR::OpGt: - return offsetof(QV4::Runtime, greaterThan); + return QV4::Runtime::greaterThan; case IR::OpLt: - return offsetof(QV4::Runtime, lessThan); + return QV4::Runtime::lessThan; case IR::OpGe: - return offsetof(QV4::Runtime, greaterEqual); + return QV4::Runtime::greaterEqual; case IR::OpLe: - return offsetof(QV4::Runtime, lessEqual); + return QV4::Runtime::lessEqual; case IR::OpEqual: - return offsetof(QV4::Runtime, equal); + return QV4::Runtime::equal; case IR::OpNotEqual: - return offsetof(QV4::Runtime, notEqual); + return QV4::Runtime::notEqual; case IR::OpStrictEqual: - return offsetof(QV4::Runtime, strictEqual); + return QV4::Runtime::strictEqual; case IR::OpStrictNotEqual: - return offsetof(QV4::Runtime, strictNotEqual); + return QV4::Runtime::strictNotEqual; case IR::OpInstanceof: - return 0; + return QV4::Runtime::InvalidRuntimeMethod; case IR::OpIn: - return 0; + return QV4::Runtime::InvalidRuntimeMethod; case IR::OpAnd: - return 0; + return QV4::Runtime::InvalidRuntimeMethod; case IR::OpOr: - return 0; + return QV4::Runtime::InvalidRuntimeMethod; default: Q_ASSERT(!"Unknown AluOp"); - return 0; + return QV4::Runtime::InvalidRuntimeMethod; } }; @@ -889,24 +889,25 @@ Param InstructionSelection::binopHelper(IR::AluOp oper, IR::Expr *leftSource, IR if (oper == IR::OpInstanceof || oper == IR::OpIn || oper == IR::OpAdd) { Instruction::BinopContext binop; if (oper == IR::OpInstanceof) - binop.alu = offsetof(QV4::Runtime, instanceof); + binop.alu = QV4::Runtime::instanceof; else if (oper == IR::OpIn) - binop.alu = offsetof(QV4::Runtime, in); + binop.alu = QV4::Runtime::in; else - binop.alu = offsetof(QV4::Runtime, add); + binop.alu = QV4::Runtime::add; binop.lhs = getParam(leftSource); binop.rhs = getParam(rightSource); binop.result = getResultParam(target); - Q_ASSERT(binop.alu); + Q_ASSERT(binop.alu != QV4::Runtime::InvalidRuntimeMethod); addInstruction(binop); return binop.result; } else { + auto binopFunc = aluOpFunction(oper); + Q_ASSERT(binopFunc != QV4::Runtime::InvalidRuntimeMethod); Instruction::Binop binop; - binop.alu = aluOpFunction(oper); + binop.alu = binopFunc; binop.lhs = getParam(leftSource); binop.rhs = getParam(rightSource); binop.result = getResultParam(target); - Q_ASSERT(binop.alu); addInstruction(binop); return binop.result; } diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 0a27ab02cf..3cd33e91e7 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -131,7 +131,7 @@ typedef AssemblerTargetConfigurationgenerateFunctionCallImp(Runtime::Method_##function##_NeedsExceptionCheck, t, "Runtime::" isel_stringIfy(function), typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, function)), __VA_ARGS__) + as->generateFunctionCallImp(Runtime::Method_##function##_NeedsExceptionCheck, t, "Runtime::" isel_stringIfy(function), typename JITAssembler::RuntimeCall(QV4::Runtime::function), __VA_ARGS__) template @@ -734,7 +734,7 @@ public: struct RuntimeCall { Address addr; - inline RuntimeCall(uint offset = uint(INT_MIN)); + inline RuntimeCall(Runtime::RuntimeMethods method = Runtime::InvalidRuntimeMethod); bool isValid() const { return addr.offset >= 0; } }; @@ -1685,8 +1685,9 @@ void Assembler::copyValue(Result result, IR::Expr* source) } template -inline Assembler::RuntimeCall::RuntimeCall(uint offset) - : addr(Assembler::EngineRegister, offset + qOffsetOf(QV4::ExecutionEngine, runtime)) +inline Assembler::RuntimeCall::RuntimeCall(Runtime::RuntimeMethods method) + : addr(Assembler::EngineRegister, + method == Runtime::InvalidRuntimeMethod ? -1 : (Assembler::targetStructureOffset(qOffsetOf(QV4::ExecutionEngine, runtime) + Runtime::runtimeMethodOffset(method)))) { } diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp index 22067bbb13..feb30ee298 100644 --- a/src/qml/jit/qv4binop.cpp +++ b/src/qml/jit/qv4binop.cpp @@ -165,17 +165,17 @@ struct ArchitectureSpecificBinaryOperation const typename Binop::OpInfo Binop::operations[IR::LastAluOp + 1] = { diff --git a/src/qml/jit/qv4binop_p.h b/src/qml/jit/qv4binop_p.h index d2d9ba7753..1b1ab7f24d 100644 --- a/src/qml/jit/qv4binop_p.h +++ b/src/qml/jit/qv4binop_p.h @@ -88,8 +88,8 @@ struct Binop { struct OpInfo { const char *name; - int fallbackImplementation; // offsetOf(Runtime,...) - int contextImplementation; // offsetOf(Runtime,...) + Runtime::RuntimeMethods fallbackImplementation; + Runtime::RuntimeMethods contextImplementation; MemRegOp inlineMemRegOp; ImmRegOp inlineImmRegOp; bool needsExceptionCheck; diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 3cbed3ce56..3803a5e119 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -791,12 +791,12 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr * #define setOp(op, opName, operation) \ do { \ - op = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \ + op = typename JITAssembler::RuntimeCall(QV4::Runtime::operation); opName = "Runtime::" isel_stringIfy(operation); \ needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \ } while (0) #define setOpContext(op, opName, operation) \ do { \ - opContext = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \ + opContext = typename JITAssembler::RuntimeCall(QV4::Runtime::operation); opName = "Runtime::" isel_stringIfy(operation); \ needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \ } while (0) diff --git a/src/qml/jit/qv4unop.cpp b/src/qml/jit/qv4unop.cpp index 76c6457d67..896be07ed5 100644 --- a/src/qml/jit/qv4unop.cpp +++ b/src/qml/jit/qv4unop.cpp @@ -48,7 +48,7 @@ using namespace JIT; #define stringIfy(s) stringIfyx(s) #define setOp(operation) \ do { \ - call = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); name = "Runtime::" stringIfy(operation); \ + call = typename JITAssembler::RuntimeCall(QV4::Runtime::operation); name = "Runtime::" stringIfy(operation); \ needsExceptionCheck = Runtime::Method_##operation##_NeedsExceptionCheck; \ } while (0) diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index d8a7de5466..c29cedaa9b 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -697,7 +697,7 @@ bool ArrayElementLessThan::operator()(Value v1, Value v2) const callData->thisObject = Primitive::undefinedValue(); callData->args[0] = v1; callData->args[1] = v2; - result = scope.engine->runtime.callValue(scope.engine, m_comparefn, callData); + result = QV4::Runtime::method_callValue(scope.engine, m_comparefn, callData); return result->toNumber() < 0; } diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 6de087a4e2..0492191747 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -97,6 +97,10 @@ private: friend struct ExecutionContext; friend struct Heap::ExecutionContext; public: + // This must be the first member, so that its offset is a multiple of QT_POINTER_SIZE + // as the base class's size is. + Runtime runtime; + qint32 callDepth; MemoryManager *memoryManager; @@ -108,8 +112,6 @@ public: Value *jsStackLimit; - Runtime runtime; - WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine. enum { JSStackLimit = 4*1024*1024 }; diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index 355b7890b6..2c898a1880 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -90,256 +90,176 @@ struct ExceptionCheck { }; } // anonymous namespace -#define RUNTIME_METHOD(returnvalue, name, args) \ - typedef returnvalue (*Method_##name)args; \ - enum { Method_##name##_NeedsExceptionCheck = ExceptionCheck::NeedsCheck }; \ - static returnvalue method_##name args; \ - const Method_##name name - -#define INIT_RUNTIME_METHOD(name) \ - name(method_##name) +#define FOR_EACH_RUNTIME_METHOD(F) \ + /* call */ \ + F(ReturnedValue, callGlobalLookup, (ExecutionEngine *engine, uint index, CallData *callData)) \ + F(ReturnedValue, callActivationProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)) \ + F(ReturnedValue, callQmlScopeObjectProperty, (ExecutionEngine *engine, int propertyIndex, CallData *callData)) \ + F(ReturnedValue, callQmlContextObjectProperty, (ExecutionEngine *engine, int propertyIndex, CallData *callData)) \ + F(ReturnedValue, callProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)) \ + F(ReturnedValue, callPropertyLookup, (ExecutionEngine *engine, uint index, CallData *callData)) \ + F(ReturnedValue, callElement, (ExecutionEngine *engine, const Value &index, CallData *callData)) \ + F(ReturnedValue, callValue, (ExecutionEngine *engine, const Value &func, CallData *callData)) \ + \ + /* construct */ \ + F(ReturnedValue, constructGlobalLookup, (ExecutionEngine *engine, uint index, CallData *callData)) \ + F(ReturnedValue, constructActivationProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)) \ + F(ReturnedValue, constructProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)) \ + F(ReturnedValue, constructPropertyLookup, (ExecutionEngine *engine, uint index, CallData *callData)) \ + F(ReturnedValue, constructValue, (ExecutionEngine *engine, const Value &func, CallData *callData)) \ + \ + /* set & get */ \ + F(void, setActivationProperty, (ExecutionEngine *engine, int nameIndex, const Value &value)) \ + F(void, setProperty, (ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)) \ + F(void, setElement, (ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)) \ + F(ReturnedValue, getProperty, (ExecutionEngine *engine, const Value &object, int nameIndex)) \ + F(ReturnedValue, getActivationProperty, (ExecutionEngine *engine, int nameIndex)) \ + F(ReturnedValue, getElement, (ExecutionEngine *engine, const Value &object, const Value &index)) \ + \ + /* typeof */ \ + F(ReturnedValue, typeofValue, (ExecutionEngine *engine, const Value &val)) \ + F(ReturnedValue, typeofName, (ExecutionEngine *engine, int nameIndex)) \ + F(ReturnedValue, typeofScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex)) \ + F(ReturnedValue, typeofContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex)) \ + F(ReturnedValue, typeofMember, (ExecutionEngine *engine, const Value &base, int nameIndex)) \ + F(ReturnedValue, typeofElement, (ExecutionEngine *engine, const Value &base, const Value &index)) \ + \ + /* delete */ \ + F(ReturnedValue, deleteElement, (ExecutionEngine *engine, const Value &base, const Value &index)) \ + F(ReturnedValue, deleteMember, (ExecutionEngine *engine, const Value &base, int nameIndex)) \ + F(ReturnedValue, deleteMemberString, (ExecutionEngine *engine, const Value &base, String *name)) \ + F(ReturnedValue, deleteName, (ExecutionEngine *engine, int nameIndex)) \ + \ + /* exceptions & scopes */ \ + F(void, throwException, (ExecutionEngine *engine, const Value &value)) \ + F(ReturnedValue, unwindException, (ExecutionEngine *engine)) \ + F(void, pushWithScope, (const Value &o, NoThrowEngine *engine)) \ + F(void, pushCatchScope, (NoThrowEngine *engine, int exceptionVarNameIndex)) \ + F(void, popScope, (NoThrowEngine *engine)) \ + \ + /* closures */ \ + F(ReturnedValue, closure, (ExecutionEngine *engine, int functionId)) \ + \ + /* function header */ \ + F(void, declareVar, (ExecutionEngine *engine, bool deletable, int nameIndex)) \ + F(ReturnedValue, setupArgumentsObject, (ExecutionEngine *engine)) \ + F(void, convertThisToObject, (ExecutionEngine *engine)) \ + \ + /* literals */ \ + F(ReturnedValue, arrayLiteral, (ExecutionEngine *engine, Value *values, uint length)) \ + F(ReturnedValue, objectLiteral, (ExecutionEngine *engine, const Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags)) \ + F(ReturnedValue, regexpLiteral, (ExecutionEngine *engine, int id)) \ + \ + /* foreach */ \ + F(ReturnedValue, foreachIterator, (ExecutionEngine *engine, const Value &in)) \ + F(ReturnedValue, foreachNextPropertyName, (const Value &foreach_iterator)) \ + \ + /* unary operators */ \ + F(ReturnedValue, uPlus, (const Value &value)) \ + F(ReturnedValue, uMinus, (const Value &value)) \ + F(ReturnedValue, uNot, (const Value &value)) \ + F(ReturnedValue, complement, (const Value &value)) \ + F(ReturnedValue, increment, (const Value &value)) \ + F(ReturnedValue, decrement, (const Value &value)) \ + \ + /* binary operators */ \ + F(ReturnedValue, instanceof, (ExecutionEngine *engine, const Value &left, const Value &right)) \ + F(ReturnedValue, in, (ExecutionEngine *engine, const Value &left, const Value &right)) \ + F(ReturnedValue, add, (ExecutionEngine *engine, const Value &left, const Value &right)) \ + F(ReturnedValue, addString, (ExecutionEngine *engine, const Value &left, const Value &right)) \ + F(ReturnedValue, bitOr, (const Value &left, const Value &right)) \ + F(ReturnedValue, bitXor, (const Value &left, const Value &right)) \ + F(ReturnedValue, bitAnd, (const Value &left, const Value &right)) \ + F(ReturnedValue, sub, (const Value &left, const Value &right)) \ + F(ReturnedValue, mul, (const Value &left, const Value &right)) \ + F(ReturnedValue, div, (const Value &left, const Value &right)) \ + F(ReturnedValue, mod, (const Value &left, const Value &right)) \ + F(ReturnedValue, shl, (const Value &left, const Value &right)) \ + F(ReturnedValue, shr, (const Value &left, const Value &right)) \ + F(ReturnedValue, ushr, (const Value &left, const Value &right)) \ + F(ReturnedValue, greaterThan, (const Value &left, const Value &right)) \ + F(ReturnedValue, lessThan, (const Value &left, const Value &right)) \ + F(ReturnedValue, greaterEqual, (const Value &left, const Value &right)) \ + F(ReturnedValue, lessEqual, (const Value &left, const Value &right)) \ + F(ReturnedValue, equal, (const Value &left, const Value &right)) \ + F(ReturnedValue, notEqual, (const Value &left, const Value &right)) \ + F(ReturnedValue, strictEqual, (const Value &left, const Value &right)) \ + F(ReturnedValue, strictNotEqual, (const Value &left, const Value &right)) \ + \ + /* comparisons */ \ + F(Bool, compareGreaterThan, (const Value &l, const Value &r)) \ + F(Bool, compareLessThan, (const Value &l, const Value &r)) \ + F(Bool, compareGreaterEqual, (const Value &l, const Value &r)) \ + F(Bool, compareLessEqual, (const Value &l, const Value &r)) \ + F(Bool, compareEqual, (const Value &left, const Value &right)) \ + F(Bool, compareNotEqual, (const Value &left, const Value &right)) \ + F(Bool, compareStrictEqual, (const Value &left, const Value &right)) \ + F(Bool, compareStrictNotEqual, (const Value &left, const Value &right)) \ + \ + F(Bool, compareInstanceof, (ExecutionEngine *engine, const Value &left, const Value &right)) \ + F(Bool, compareIn, (ExecutionEngine *engine, const Value &left, const Value &right)) \ + \ + /* conversions */ \ + F(Bool, toBoolean, (const Value &value)) \ + F(ReturnedValue, toDouble, (const Value &value)) \ + F(int, toInt, (const Value &value)) \ + F(int, doubleToInt, (const double &d)) \ + F(unsigned, toUInt, (const Value &value)) \ + F(unsigned, doubleToUInt, (const double &d)) \ + \ + /* qml */ \ + F(ReturnedValue, getQmlContext, (NoThrowEngine *engine)) \ + F(ReturnedValue, getQmlImportedScripts, (NoThrowEngine *engine)) \ + F(ReturnedValue, getQmlSingleton, (NoThrowEngine *engine, int nameIndex)) \ + F(ReturnedValue, getQmlAttachedProperty, (ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex)) \ + F(ReturnedValue, getQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \ + F(ReturnedValue, getQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \ + F(ReturnedValue, getQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)) \ + F(ReturnedValue, getQmlSingletonQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)) \ + F(ReturnedValue, getQmlIdObject, (ExecutionEngine *engine, const Value &context, uint index)) \ + \ + F(void, setQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)) \ + F(void, setQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)) \ + F(void, setQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value)) struct Q_QML_PRIVATE_EXPORT Runtime { Runtime() - : INIT_RUNTIME_METHOD(callGlobalLookup) - , INIT_RUNTIME_METHOD(callActivationProperty) - , INIT_RUNTIME_METHOD(callQmlScopeObjectProperty) - , INIT_RUNTIME_METHOD(callQmlContextObjectProperty) - , INIT_RUNTIME_METHOD(callProperty) - , INIT_RUNTIME_METHOD(callPropertyLookup) - , INIT_RUNTIME_METHOD(callElement) - , INIT_RUNTIME_METHOD(callValue) - , INIT_RUNTIME_METHOD(constructGlobalLookup) - , INIT_RUNTIME_METHOD(constructActivationProperty) - , INIT_RUNTIME_METHOD(constructProperty) - , INIT_RUNTIME_METHOD(constructPropertyLookup) - , INIT_RUNTIME_METHOD(constructValue) - , INIT_RUNTIME_METHOD(setActivationProperty) - , INIT_RUNTIME_METHOD(setProperty) - , INIT_RUNTIME_METHOD(setElement) - , INIT_RUNTIME_METHOD(getProperty) - , INIT_RUNTIME_METHOD(getActivationProperty) - , INIT_RUNTIME_METHOD(getElement) - , INIT_RUNTIME_METHOD(typeofValue) - , INIT_RUNTIME_METHOD(typeofName) - , INIT_RUNTIME_METHOD(typeofScopeObjectProperty) - , INIT_RUNTIME_METHOD(typeofContextObjectProperty) - , INIT_RUNTIME_METHOD(typeofMember) - , INIT_RUNTIME_METHOD(typeofElement) - , INIT_RUNTIME_METHOD(deleteElement) - , INIT_RUNTIME_METHOD(deleteMember) - , INIT_RUNTIME_METHOD(deleteMemberString) - , INIT_RUNTIME_METHOD(deleteName) - , INIT_RUNTIME_METHOD(throwException) - , INIT_RUNTIME_METHOD(unwindException) - , INIT_RUNTIME_METHOD(pushWithScope) - , INIT_RUNTIME_METHOD(pushCatchScope) - , INIT_RUNTIME_METHOD(popScope) - , INIT_RUNTIME_METHOD(closure) - , INIT_RUNTIME_METHOD(declareVar) - , INIT_RUNTIME_METHOD(setupArgumentsObject) - , INIT_RUNTIME_METHOD(convertThisToObject) - , INIT_RUNTIME_METHOD(arrayLiteral) - , INIT_RUNTIME_METHOD(objectLiteral) - , INIT_RUNTIME_METHOD(regexpLiteral) - , INIT_RUNTIME_METHOD(foreachIterator) - , INIT_RUNTIME_METHOD(foreachNextPropertyName) - , INIT_RUNTIME_METHOD(uPlus) - , INIT_RUNTIME_METHOD(uMinus) - , INIT_RUNTIME_METHOD(uNot) - , INIT_RUNTIME_METHOD(complement) - , INIT_RUNTIME_METHOD(increment) - , INIT_RUNTIME_METHOD(decrement) - , INIT_RUNTIME_METHOD(instanceof) - , INIT_RUNTIME_METHOD(in) - , INIT_RUNTIME_METHOD(add) - , INIT_RUNTIME_METHOD(addString) - , INIT_RUNTIME_METHOD(bitOr) - , INIT_RUNTIME_METHOD(bitXor) - , INIT_RUNTIME_METHOD(bitAnd) - , INIT_RUNTIME_METHOD(sub) - , INIT_RUNTIME_METHOD(mul) - , INIT_RUNTIME_METHOD(div) - , INIT_RUNTIME_METHOD(mod) - , INIT_RUNTIME_METHOD(shl) - , INIT_RUNTIME_METHOD(shr) - , INIT_RUNTIME_METHOD(ushr) - , INIT_RUNTIME_METHOD(greaterThan) - , INIT_RUNTIME_METHOD(lessThan) - , INIT_RUNTIME_METHOD(greaterEqual) - , INIT_RUNTIME_METHOD(lessEqual) - , INIT_RUNTIME_METHOD(equal) - , INIT_RUNTIME_METHOD(notEqual) - , INIT_RUNTIME_METHOD(strictEqual) - , INIT_RUNTIME_METHOD(strictNotEqual) - , INIT_RUNTIME_METHOD(compareGreaterThan) - , INIT_RUNTIME_METHOD(compareLessThan) - , INIT_RUNTIME_METHOD(compareGreaterEqual) - , INIT_RUNTIME_METHOD(compareLessEqual) - , INIT_RUNTIME_METHOD(compareEqual) - , INIT_RUNTIME_METHOD(compareNotEqual) - , INIT_RUNTIME_METHOD(compareStrictEqual) - , INIT_RUNTIME_METHOD(compareStrictNotEqual) - , INIT_RUNTIME_METHOD(compareInstanceof) - , INIT_RUNTIME_METHOD(compareIn) - , INIT_RUNTIME_METHOD(toBoolean) - , INIT_RUNTIME_METHOD(toDouble) - , INIT_RUNTIME_METHOD(toInt) - , INIT_RUNTIME_METHOD(doubleToInt) - , INIT_RUNTIME_METHOD(toUInt) - , INIT_RUNTIME_METHOD(doubleToUInt) - , INIT_RUNTIME_METHOD(getQmlContext) - , INIT_RUNTIME_METHOD(getQmlImportedScripts) - , INIT_RUNTIME_METHOD(getQmlSingleton) - , INIT_RUNTIME_METHOD(getQmlAttachedProperty) - , INIT_RUNTIME_METHOD(getQmlScopeObjectProperty) - , INIT_RUNTIME_METHOD(getQmlContextObjectProperty) - , INIT_RUNTIME_METHOD(getQmlQObjectProperty) - , INIT_RUNTIME_METHOD(getQmlSingletonQObjectProperty) - , INIT_RUNTIME_METHOD(getQmlIdObject) - , INIT_RUNTIME_METHOD(setQmlScopeObjectProperty) - , INIT_RUNTIME_METHOD(setQmlContextObjectProperty) - , INIT_RUNTIME_METHOD(setQmlQObjectProperty) - { } - - // call - RUNTIME_METHOD(ReturnedValue, callGlobalLookup, (ExecutionEngine *engine, uint index, CallData *callData)); - RUNTIME_METHOD(ReturnedValue, callActivationProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)); - RUNTIME_METHOD(ReturnedValue, callQmlScopeObjectProperty, (ExecutionEngine *engine, int propertyIndex, CallData *callData)); - RUNTIME_METHOD(ReturnedValue, callQmlContextObjectProperty, (ExecutionEngine *engine, int propertyIndex, CallData *callData)); - RUNTIME_METHOD(ReturnedValue, callProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)); - RUNTIME_METHOD(ReturnedValue, callPropertyLookup, (ExecutionEngine *engine, uint index, CallData *callData)); - RUNTIME_METHOD(ReturnedValue, callElement, (ExecutionEngine *engine, const Value &index, CallData *callData)); - RUNTIME_METHOD(ReturnedValue, callValue, (ExecutionEngine *engine, const Value &func, CallData *callData)); - - // construct - RUNTIME_METHOD(ReturnedValue, constructGlobalLookup, (ExecutionEngine *engine, uint index, CallData *callData)); - RUNTIME_METHOD(ReturnedValue, constructActivationProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)); - RUNTIME_METHOD(ReturnedValue, constructProperty, (ExecutionEngine *engine, int nameIndex, CallData *callData)); - RUNTIME_METHOD(ReturnedValue, constructPropertyLookup, (ExecutionEngine *engine, uint index, CallData *callData)); - RUNTIME_METHOD(ReturnedValue, constructValue, (ExecutionEngine *engine, const Value &func, CallData *callData)); - - // set & get - RUNTIME_METHOD(void, setActivationProperty, (ExecutionEngine *engine, int nameIndex, const Value &value)); - RUNTIME_METHOD(void, setProperty, (ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)); - RUNTIME_METHOD(void, setElement, (ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)); - RUNTIME_METHOD(ReturnedValue, getProperty, (ExecutionEngine *engine, const Value &object, int nameIndex)); - RUNTIME_METHOD(ReturnedValue, getActivationProperty, (ExecutionEngine *engine, int nameIndex)); - RUNTIME_METHOD(ReturnedValue, getElement, (ExecutionEngine *engine, const Value &object, const Value &index)); - - // typeof - RUNTIME_METHOD(ReturnedValue, typeofValue, (ExecutionEngine *engine, const Value &val)); - RUNTIME_METHOD(ReturnedValue, typeofName, (ExecutionEngine *engine, int nameIndex)); - RUNTIME_METHOD(ReturnedValue, typeofScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex)); - RUNTIME_METHOD(ReturnedValue, typeofContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex)); - RUNTIME_METHOD(ReturnedValue, typeofMember, (ExecutionEngine *engine, const Value &base, int nameIndex)); - RUNTIME_METHOD(ReturnedValue, typeofElement, (ExecutionEngine *engine, const Value &base, const Value &index)); - - // delete - RUNTIME_METHOD(ReturnedValue, deleteElement, (ExecutionEngine *engine, const Value &base, const Value &index)); - RUNTIME_METHOD(ReturnedValue, deleteMember, (ExecutionEngine *engine, const Value &base, int nameIndex)); - RUNTIME_METHOD(ReturnedValue, deleteMemberString, (ExecutionEngine *engine, const Value &base, String *name)); - RUNTIME_METHOD(ReturnedValue, deleteName, (ExecutionEngine *engine, int nameIndex)); - - // exceptions & scopes - RUNTIME_METHOD(void, throwException, (ExecutionEngine *engine, const Value &value)); - RUNTIME_METHOD(ReturnedValue, unwindException, (ExecutionEngine *engine)); - RUNTIME_METHOD(void, pushWithScope, (const Value &o, NoThrowEngine *engine)); - RUNTIME_METHOD(void, pushCatchScope, (NoThrowEngine *engine, int exceptionVarNameIndex)); - RUNTIME_METHOD(void, popScope, (NoThrowEngine *engine)); - - // closures - RUNTIME_METHOD(ReturnedValue, closure, (ExecutionEngine *engine, int functionId)); + { +#define INIT_METHOD(returnvalue, name, args) runtimeMethods[name] = reinterpret_cast(&method_##name); +FOR_EACH_RUNTIME_METHOD(INIT_METHOD) +#undef INIT_METHOD + } - // function header - RUNTIME_METHOD(void, declareVar, (ExecutionEngine *engine, bool deletable, int nameIndex)); - RUNTIME_METHOD(ReturnedValue, setupArgumentsObject, (ExecutionEngine *engine)); - RUNTIME_METHOD(void, convertThisToObject, (ExecutionEngine *engine)); - - // literals - RUNTIME_METHOD(ReturnedValue, arrayLiteral, (ExecutionEngine *engine, Value *values, uint length)); - RUNTIME_METHOD(ReturnedValue, objectLiteral, (ExecutionEngine *engine, const Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags)); - RUNTIME_METHOD(ReturnedValue, regexpLiteral, (ExecutionEngine *engine, int id)); - - // foreach - RUNTIME_METHOD(ReturnedValue, foreachIterator, (ExecutionEngine *engine, const Value &in)); - RUNTIME_METHOD(ReturnedValue, foreachNextPropertyName, (const Value &foreach_iterator)); - - // unary operators typedef ReturnedValue (*UnaryOperation)(const Value &value); - RUNTIME_METHOD(ReturnedValue, uPlus, (const Value &value)); - RUNTIME_METHOD(ReturnedValue, uMinus, (const Value &value)); - RUNTIME_METHOD(ReturnedValue, uNot, (const Value &value)); - RUNTIME_METHOD(ReturnedValue, complement, (const Value &value)); - RUNTIME_METHOD(ReturnedValue, increment, (const Value &value)); - RUNTIME_METHOD(ReturnedValue, decrement, (const Value &value)); - - // binary operators typedef ReturnedValue (*BinaryOperation)(const Value &left, const Value &right); typedef ReturnedValue (*BinaryOperationContext)(ExecutionEngine *engine, const Value &left, const Value &right); - RUNTIME_METHOD(ReturnedValue, instanceof, (ExecutionEngine *engine, const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, in, (ExecutionEngine *engine, const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, add, (ExecutionEngine *engine, const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, addString, (ExecutionEngine *engine, const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, bitOr, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, bitXor, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, bitAnd, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, sub, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, mul, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, div, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, mod, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, shl, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, shr, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, ushr, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, greaterThan, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, lessThan, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, greaterEqual, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, lessEqual, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, equal, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, notEqual, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, strictEqual, (const Value &left, const Value &right)); - RUNTIME_METHOD(ReturnedValue, strictNotEqual, (const Value &left, const Value &right)); - - // comparisons - RUNTIME_METHOD(Bool, compareGreaterThan, (const Value &l, const Value &r)); - RUNTIME_METHOD(Bool, compareLessThan, (const Value &l, const Value &r)); - RUNTIME_METHOD(Bool, compareGreaterEqual, (const Value &l, const Value &r)); - RUNTIME_METHOD(Bool, compareLessEqual, (const Value &l, const Value &r)); - RUNTIME_METHOD(Bool, compareEqual, (const Value &left, const Value &right)); - RUNTIME_METHOD(Bool, compareNotEqual, (const Value &left, const Value &right)); - RUNTIME_METHOD(Bool, compareStrictEqual, (const Value &left, const Value &right)); - RUNTIME_METHOD(Bool, compareStrictNotEqual, (const Value &left, const Value &right)); +#define DEFINE_RUNTIME_METHOD_ENUM(returnvalue, name, args) name, + enum RuntimeMethods { + FOR_EACH_RUNTIME_METHOD(DEFINE_RUNTIME_METHOD_ENUM) + RuntimeMethodCount, + InvalidRuntimeMethod = RuntimeMethodCount + }; +#undef DEFINE_RUNTIME_METHOD_ENUM - RUNTIME_METHOD(Bool, compareInstanceof, (ExecutionEngine *engine, const Value &left, const Value &right)); - RUNTIME_METHOD(Bool, compareIn, (ExecutionEngine *engine, const Value &left, const Value &right)); + void *runtimeMethods[RuntimeMethodCount]; - // conversions - RUNTIME_METHOD(Bool, toBoolean, (const Value &value)); - RUNTIME_METHOD(ReturnedValue, toDouble, (const Value &value)); - RUNTIME_METHOD(int, toInt, (const Value &value)); - RUNTIME_METHOD(int, doubleToInt, (const double &d)); - RUNTIME_METHOD(unsigned, toUInt, (const Value &value)); - RUNTIME_METHOD(unsigned, doubleToUInt, (const double &d)); + static uint runtimeMethodOffset(RuntimeMethods method) { return method*QT_POINTER_SIZE; } - // qml - RUNTIME_METHOD(ReturnedValue, getQmlContext, (NoThrowEngine *engine)); - RUNTIME_METHOD(ReturnedValue, getQmlImportedScripts, (NoThrowEngine *engine)); - RUNTIME_METHOD(ReturnedValue, getQmlSingleton, (NoThrowEngine *engine, int nameIndex)); - RUNTIME_METHOD(ReturnedValue, getQmlAttachedProperty, (ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex)); - RUNTIME_METHOD(ReturnedValue, getQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)); - RUNTIME_METHOD(ReturnedValue, getQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)); - RUNTIME_METHOD(ReturnedValue, getQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)); - RUNTIME_METHOD(ReturnedValue, getQmlSingletonQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)); - RUNTIME_METHOD(ReturnedValue, getQmlIdObject, (ExecutionEngine *engine, const Value &context, uint index)); +#define RUNTIME_METHOD(returnvalue, name, args) \ + typedef returnvalue (*Method_##name)args; \ + enum { Method_##name##_NeedsExceptionCheck = ExceptionCheck::NeedsCheck }; \ + static returnvalue method_##name args; + FOR_EACH_RUNTIME_METHOD(RUNTIME_METHOD) +#undef RUNTIME_METHOD - RUNTIME_METHOD(void, setQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)); - RUNTIME_METHOD(void, setQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)); - RUNTIME_METHOD(void, setQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value)); }; -#undef RUNTIME_METHOD -#undef INIT_RUNTIME_METHOD +static_assert(std::is_standard_layout::value, "Runtime needs to be standard layout in order for us to be able to use offsetof"); +static_assert(offsetof(Runtime, runtimeMethods) == 0, "JIT expects this to be the first member"); +static_assert(sizeof(Runtime::BinaryOperation) == sizeof(void*), "JIT expects a function pointer to fit into a regular pointer, for cross-compilation offset translation"); + +#undef FOR_EACH_RUNTIME_METHOD } // namespace QV4 diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index be2772c23f..988b0a03b2 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -455,12 +455,12 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(LoadRegExp) MOTH_BEGIN_INSTR(LoadClosure) - STOREVALUE(instr.result, engine->runtime.closure(engine, instr.value)); + STOREVALUE(instr.result, Runtime::method_closure(engine, instr.value)); MOTH_END_INSTR(LoadClosure) MOTH_BEGIN_INSTR(LoadName) TRACE(inline, "property name = %s", runtimeStrings[instr.name]->toQString().toUtf8().constData()); - STOREVALUE(instr.result, engine->runtime.getActivationProperty(engine, instr.name)); + STOREVALUE(instr.result, Runtime::method_getActivationProperty(engine, instr.name)); MOTH_END_INSTR(LoadName) MOTH_BEGIN_INSTR(GetGlobalLookup) @@ -470,12 +470,12 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(StoreName) TRACE(inline, "property name = %s", runtimeStrings[instr.name]->toQString().toUtf8().constData()); - engine->runtime.setActivationProperty(engine, instr.name, VALUE(instr.source)); + Runtime::method_setActivationProperty(engine, instr.name, VALUE(instr.source)); CHECK_EXCEPTION; MOTH_END_INSTR(StoreName) MOTH_BEGIN_INSTR(LoadElement) - STOREVALUE(instr.result, engine->runtime.getElement(engine, VALUE(instr.base), VALUE(instr.index))); + STOREVALUE(instr.result, Runtime::method_getElement(engine, VALUE(instr.base), VALUE(instr.index))); MOTH_END_INSTR(LoadElement) MOTH_BEGIN_INSTR(LoadElementLookup) @@ -484,7 +484,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(LoadElementLookup) MOTH_BEGIN_INSTR(StoreElement) - engine->runtime.setElement(engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source)); + Runtime::method_setElement(engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source)); CHECK_EXCEPTION; MOTH_END_INSTR(StoreElement) @@ -495,7 +495,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(StoreElementLookup) MOTH_BEGIN_INSTR(LoadProperty) - STOREVALUE(instr.result, engine->runtime.getProperty(engine, VALUE(instr.base), instr.name)); + STOREVALUE(instr.result, Runtime::method_getProperty(engine, VALUE(instr.base), instr.name)); MOTH_END_INSTR(LoadProperty) MOTH_BEGIN_INSTR(GetLookup) @@ -504,7 +504,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(GetLookup) MOTH_BEGIN_INSTR(StoreProperty) - engine->runtime.setProperty(engine, VALUE(instr.base), instr.name, VALUE(instr.source)); + Runtime::method_setProperty(engine, VALUE(instr.base), instr.name, VALUE(instr.source)); CHECK_EXCEPTION; MOTH_END_INSTR(StoreProperty) @@ -515,42 +515,42 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(SetLookup) MOTH_BEGIN_INSTR(StoreQObjectProperty) - engine->runtime.setQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source)); + Runtime::method_setQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source)); CHECK_EXCEPTION; MOTH_END_INSTR(StoreQObjectProperty) MOTH_BEGIN_INSTR(LoadQObjectProperty) - STOREVALUE(instr.result, engine->runtime.getQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired)); + STOREVALUE(instr.result, Runtime::method_getQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired)); MOTH_END_INSTR(LoadQObjectProperty) MOTH_BEGIN_INSTR(StoreScopeObjectProperty) - engine->runtime.setQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source)); + Runtime::method_setQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source)); CHECK_EXCEPTION; MOTH_END_INSTR(StoreScopeObjectProperty) MOTH_BEGIN_INSTR(LoadScopeObjectProperty) - STOREVALUE(instr.result, engine->runtime.getQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired)); + STOREVALUE(instr.result, Runtime::method_getQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired)); MOTH_END_INSTR(LoadScopeObjectProperty) MOTH_BEGIN_INSTR(StoreContextObjectProperty) - engine->runtime.setQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source)); + Runtime::method_setQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source)); CHECK_EXCEPTION; MOTH_END_INSTR(StoreContextObjectProperty) MOTH_BEGIN_INSTR(LoadContextObjectProperty) - STOREVALUE(instr.result, engine->runtime.getQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired)); + STOREVALUE(instr.result, Runtime::method_getQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired)); MOTH_END_INSTR(LoadContextObjectProperty) MOTH_BEGIN_INSTR(LoadIdObject) - STOREVALUE(instr.result, engine->runtime.getQmlIdObject(engine, VALUE(instr.base), instr.index)); + STOREVALUE(instr.result, Runtime::method_getQmlIdObject(engine, VALUE(instr.base), instr.index)); MOTH_END_INSTR(LoadIdObject) MOTH_BEGIN_INSTR(LoadAttachedQObjectProperty) - STOREVALUE(instr.result, engine->runtime.getQmlAttachedProperty(engine, instr.attachedPropertiesId, instr.propertyIndex)); + STOREVALUE(instr.result, Runtime::method_getQmlAttachedProperty(engine, instr.attachedPropertiesId, instr.propertyIndex)); MOTH_END_INSTR(LoadAttachedQObjectProperty) MOTH_BEGIN_INSTR(LoadSingletonQObjectProperty) - STOREVALUE(instr.result, engine->runtime.getQmlSingletonQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired)); + STOREVALUE(instr.result, Runtime::method_getQmlSingletonQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired)); MOTH_END_INSTR(LoadSingletonQObjectProperty) MOTH_BEGIN_INSTR(Push) @@ -576,7 +576,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); - STOREVALUE(instr.result, engine->runtime.callValue(engine, VALUE(instr.dest), callData)); + STOREVALUE(instr.result, Runtime::method_callValue(engine, VALUE(instr.dest), callData)); MOTH_END_INSTR(CallValue) MOTH_BEGIN_INSTR(CallProperty) @@ -586,7 +586,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); - STOREVALUE(instr.result, engine->runtime.callProperty(engine, instr.name, callData)); + STOREVALUE(instr.result, Runtime::method_callProperty(engine, instr.name, callData)); MOTH_END_INSTR(CallProperty) MOTH_BEGIN_INSTR(CallPropertyLookup) @@ -595,7 +595,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); - STOREVALUE(instr.result, engine->runtime.callPropertyLookup(engine, instr.lookupIndex, callData)); + STOREVALUE(instr.result, Runtime::method_callPropertyLookup(engine, instr.lookupIndex, callData)); MOTH_END_INSTR(CallPropertyLookup) MOTH_BEGIN_INSTR(CallScopeObjectProperty) @@ -605,7 +605,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); - STOREVALUE(instr.result, engine->runtime.callQmlScopeObjectProperty(engine, instr.index, callData)); + STOREVALUE(instr.result, Runtime::method_callQmlScopeObjectProperty(engine, instr.index, callData)); MOTH_END_INSTR(CallScopeObjectProperty) MOTH_BEGIN_INSTR(CallContextObjectProperty) @@ -615,7 +615,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); - STOREVALUE(instr.result, engine->runtime.callQmlContextObjectProperty(engine, instr.index, callData)); + STOREVALUE(instr.result, Runtime::method_callQmlContextObjectProperty(engine, instr.index, callData)); MOTH_END_INSTR(CallContextObjectProperty) MOTH_BEGIN_INSTR(CallElement) @@ -624,7 +624,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); - STOREVALUE(instr.result, engine->runtime.callElement(engine, VALUE(instr.index), callData)); + STOREVALUE(instr.result, Runtime::method_callElement(engine, VALUE(instr.index), callData)); MOTH_END_INSTR(CallElement) MOTH_BEGIN_INSTR(CallActivationProperty) @@ -633,7 +633,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); - STOREVALUE(instr.result, engine->runtime.callActivationProperty(engine, instr.name, callData)); + STOREVALUE(instr.result, Runtime::method_callActivationProperty(engine, instr.name, callData)); MOTH_END_INSTR(CallActivationProperty) MOTH_BEGIN_INSTR(CallGlobalLookup) @@ -650,95 +650,95 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(SetExceptionHandler) MOTH_BEGIN_INSTR(CallBuiltinThrow) - engine->runtime.throwException(engine, VALUE(instr.arg)); + Runtime::method_throwException(engine, VALUE(instr.arg)); CHECK_EXCEPTION; MOTH_END_INSTR(CallBuiltinThrow) MOTH_BEGIN_INSTR(CallBuiltinUnwindException) - STOREVALUE(instr.result, engine->runtime.unwindException(engine)); + STOREVALUE(instr.result, Runtime::method_unwindException(engine)); MOTH_END_INSTR(CallBuiltinUnwindException) MOTH_BEGIN_INSTR(CallBuiltinPushCatchScope) - engine->runtime.pushCatchScope(static_cast(engine), instr.name); + Runtime::method_pushCatchScope(static_cast(engine), instr.name); context = engine->currentContext; MOTH_END_INSTR(CallBuiltinPushCatchScope) MOTH_BEGIN_INSTR(CallBuiltinPushScope) - engine->runtime.pushWithScope(VALUE(instr.arg), static_cast(engine)); + Runtime::method_pushWithScope(VALUE(instr.arg), static_cast(engine)); context = engine->currentContext; CHECK_EXCEPTION; MOTH_END_INSTR(CallBuiltinPushScope) MOTH_BEGIN_INSTR(CallBuiltinPopScope) - engine->runtime.popScope(static_cast(engine)); + Runtime::method_popScope(static_cast(engine)); context = engine->currentContext; MOTH_END_INSTR(CallBuiltinPopScope) MOTH_BEGIN_INSTR(CallBuiltinForeachIteratorObject) - STOREVALUE(instr.result, engine->runtime.foreachIterator(engine, VALUE(instr.arg))); + STOREVALUE(instr.result, Runtime::method_foreachIterator(engine, VALUE(instr.arg))); MOTH_END_INSTR(CallBuiltinForeachIteratorObject) MOTH_BEGIN_INSTR(CallBuiltinForeachNextPropertyName) - STOREVALUE(instr.result, engine->runtime.foreachNextPropertyName(VALUE(instr.arg))); + STOREVALUE(instr.result, Runtime::method_foreachNextPropertyName(VALUE(instr.arg))); MOTH_END_INSTR(CallBuiltinForeachNextPropertyName) MOTH_BEGIN_INSTR(CallBuiltinDeleteMember) - STOREVALUE(instr.result, engine->runtime.deleteMember(engine, VALUE(instr.base), instr.member)); + STOREVALUE(instr.result, Runtime::method_deleteMember(engine, VALUE(instr.base), instr.member)); MOTH_END_INSTR(CallBuiltinDeleteMember) MOTH_BEGIN_INSTR(CallBuiltinDeleteSubscript) - STOREVALUE(instr.result, engine->runtime.deleteElement(engine, VALUE(instr.base), VALUE(instr.index))); + STOREVALUE(instr.result, Runtime::method_deleteElement(engine, VALUE(instr.base), VALUE(instr.index))); MOTH_END_INSTR(CallBuiltinDeleteSubscript) MOTH_BEGIN_INSTR(CallBuiltinDeleteName) - STOREVALUE(instr.result, engine->runtime.deleteName(engine, instr.name)); + STOREVALUE(instr.result, Runtime::method_deleteName(engine, instr.name)); MOTH_END_INSTR(CallBuiltinDeleteName) MOTH_BEGIN_INSTR(CallBuiltinTypeofScopeObjectProperty) - STOREVALUE(instr.result, engine->runtime.typeofScopeObjectProperty(engine, VALUE(instr.base), instr.index)); + STOREVALUE(instr.result, Runtime::method_typeofScopeObjectProperty(engine, VALUE(instr.base), instr.index)); MOTH_END_INSTR(CallBuiltinTypeofMember) MOTH_BEGIN_INSTR(CallBuiltinTypeofContextObjectProperty) - STOREVALUE(instr.result, engine->runtime.typeofContextObjectProperty(engine, VALUE(instr.base), instr.index)); + STOREVALUE(instr.result, Runtime::method_typeofContextObjectProperty(engine, VALUE(instr.base), instr.index)); MOTH_END_INSTR(CallBuiltinTypeofMember) MOTH_BEGIN_INSTR(CallBuiltinTypeofMember) - STOREVALUE(instr.result, engine->runtime.typeofMember(engine, VALUE(instr.base), instr.member)); + STOREVALUE(instr.result, Runtime::method_typeofMember(engine, VALUE(instr.base), instr.member)); MOTH_END_INSTR(CallBuiltinTypeofMember) MOTH_BEGIN_INSTR(CallBuiltinTypeofSubscript) - STOREVALUE(instr.result, engine->runtime.typeofElement(engine, VALUE(instr.base), VALUE(instr.index))); + STOREVALUE(instr.result, Runtime::method_typeofElement(engine, VALUE(instr.base), VALUE(instr.index))); MOTH_END_INSTR(CallBuiltinTypeofSubscript) MOTH_BEGIN_INSTR(CallBuiltinTypeofName) - STOREVALUE(instr.result, engine->runtime.typeofName(engine, instr.name)); + STOREVALUE(instr.result, Runtime::method_typeofName(engine, instr.name)); MOTH_END_INSTR(CallBuiltinTypeofName) MOTH_BEGIN_INSTR(CallBuiltinTypeofValue) - STOREVALUE(instr.result, engine->runtime.typeofValue(engine, VALUE(instr.value))); + STOREVALUE(instr.result, Runtime::method_typeofValue(engine, VALUE(instr.value))); MOTH_END_INSTR(CallBuiltinTypeofValue) MOTH_BEGIN_INSTR(CallBuiltinDeclareVar) - engine->runtime.declareVar(engine, instr.isDeletable, instr.varName); + Runtime::method_declareVar(engine, instr.isDeletable, instr.varName); MOTH_END_INSTR(CallBuiltinDeclareVar) MOTH_BEGIN_INSTR(CallBuiltinDefineArray) Q_ASSERT(instr.args + instr.argc <= stackSize); QV4::Value *args = stack + instr.args; - STOREVALUE(instr.result, engine->runtime.arrayLiteral(engine, args, instr.argc)); + STOREVALUE(instr.result, Runtime::method_arrayLiteral(engine, args, instr.argc)); MOTH_END_INSTR(CallBuiltinDefineArray) MOTH_BEGIN_INSTR(CallBuiltinDefineObjectLiteral) QV4::Value *args = stack + instr.args; - STOREVALUE(instr.result, engine->runtime.objectLiteral(engine, args, instr.internalClassId, instr.arrayValueCount, instr.arrayGetterSetterCountAndFlags)); + STOREVALUE(instr.result, Runtime::method_objectLiteral(engine, args, instr.internalClassId, instr.arrayValueCount, instr.arrayGetterSetterCountAndFlags)); MOTH_END_INSTR(CallBuiltinDefineObjectLiteral) MOTH_BEGIN_INSTR(CallBuiltinSetupArgumentsObject) - STOREVALUE(instr.result, engine->runtime.setupArgumentsObject(engine)); + STOREVALUE(instr.result, Runtime::method_setupArgumentsObject(engine)); MOTH_END_INSTR(CallBuiltinSetupArgumentsObject) MOTH_BEGIN_INSTR(CallBuiltinConvertThisToObject) - engine->runtime.convertThisToObject(engine); + Runtime::method_convertThisToObject(engine); CHECK_EXCEPTION; MOTH_END_INSTR(CallBuiltinConvertThisToObject) @@ -748,7 +748,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); - STOREVALUE(instr.result, engine->runtime.constructValue(engine, VALUE(instr.func), callData)); + STOREVALUE(instr.result, Runtime::method_constructValue(engine, VALUE(instr.func), callData)); MOTH_END_INSTR(CreateValue) MOTH_BEGIN_INSTR(CreateProperty) @@ -757,7 +757,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); - STOREVALUE(instr.result, engine->runtime.constructProperty(engine, instr.name, callData)); + STOREVALUE(instr.result, Runtime::method_constructProperty(engine, instr.name, callData)); MOTH_END_INSTR(CreateProperty) MOTH_BEGIN_INSTR(ConstructPropertyLookup) @@ -766,7 +766,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); - STOREVALUE(instr.result, engine->runtime.constructPropertyLookup(engine, instr.index, callData)); + STOREVALUE(instr.result, Runtime::method_constructPropertyLookup(engine, instr.index, callData)); MOTH_END_INSTR(ConstructPropertyLookup) MOTH_BEGIN_INSTR(CreateActivationProperty) @@ -775,7 +775,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); - STOREVALUE(instr.result, engine->runtime.constructActivationProperty(engine, instr.name, callData)); + STOREVALUE(instr.result, Runtime::method_constructActivationProperty(engine, instr.name, callData)); MOTH_END_INSTR(CreateActivationProperty) MOTH_BEGIN_INSTR(ConstructGlobalLookup) @@ -784,7 +784,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); - STOREVALUE(instr.result, engine->runtime.constructGlobalLookup(engine, instr.index, callData)); + STOREVALUE(instr.result, Runtime::method_constructGlobalLookup(engine, instr.index, callData)); MOTH_END_INSTR(ConstructGlobalLookup) MOTH_BEGIN_INSTR(Jump) @@ -806,7 +806,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(JumpNe) MOTH_BEGIN_INSTR(UNot) - STOREVALUE(instr.result, engine->runtime.uNot(VALUE(instr.source))); + STOREVALUE(instr.result, Runtime::method_uNot(VALUE(instr.source))); MOTH_END_INSTR(UNot) MOTH_BEGIN_INSTR(UNotBool) @@ -815,15 +815,15 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(UNotBool) MOTH_BEGIN_INSTR(UPlus) - STOREVALUE(instr.result, engine->runtime.uPlus(VALUE(instr.source))); + STOREVALUE(instr.result, Runtime::method_uPlus(VALUE(instr.source))); MOTH_END_INSTR(UPlus) MOTH_BEGIN_INSTR(UMinus) - STOREVALUE(instr.result, engine->runtime.uMinus(VALUE(instr.source))); + STOREVALUE(instr.result, Runtime::method_uMinus(VALUE(instr.source))); MOTH_END_INSTR(UMinus) MOTH_BEGIN_INSTR(UCompl) - STOREVALUE(instr.result, engine->runtime.complement(VALUE(instr.source))); + STOREVALUE(instr.result, Runtime::method_complement(VALUE(instr.source))); MOTH_END_INSTR(UCompl) MOTH_BEGIN_INSTR(UComplInt) @@ -831,32 +831,32 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(UComplInt) MOTH_BEGIN_INSTR(Increment) - STOREVALUE(instr.result, engine->runtime.increment(VALUE(instr.source))); + STOREVALUE(instr.result, Runtime::method_increment(VALUE(instr.source))); MOTH_END_INSTR(Increment) MOTH_BEGIN_INSTR(Decrement) - STOREVALUE(instr.result, engine->runtime.decrement(VALUE(instr.source))); + STOREVALUE(instr.result, Runtime::method_decrement(VALUE(instr.source))); MOTH_END_INSTR(Decrement) MOTH_BEGIN_INSTR(Binop) - QV4::Runtime::BinaryOperation op = *reinterpret_cast(reinterpret_cast(&engine->runtime) + instr.alu); + QV4::Runtime::BinaryOperation op = *reinterpret_cast(reinterpret_cast(&engine->runtime.runtimeMethods[instr.alu])); STOREVALUE(instr.result, op(VALUE(instr.lhs), VALUE(instr.rhs))); MOTH_END_INSTR(Binop) MOTH_BEGIN_INSTR(Add) - STOREVALUE(instr.result, engine->runtime.add(engine, VALUE(instr.lhs), VALUE(instr.rhs))); + STOREVALUE(instr.result, Runtime::method_add(engine, VALUE(instr.lhs), VALUE(instr.rhs))); MOTH_END_INSTR(Add) MOTH_BEGIN_INSTR(BitAnd) - STOREVALUE(instr.result, engine->runtime.bitAnd(VALUE(instr.lhs), VALUE(instr.rhs))); + STOREVALUE(instr.result, Runtime::method_bitAnd(VALUE(instr.lhs), VALUE(instr.rhs))); MOTH_END_INSTR(BitAnd) MOTH_BEGIN_INSTR(BitOr) - STOREVALUE(instr.result, engine->runtime.bitOr(VALUE(instr.lhs), VALUE(instr.rhs))); + STOREVALUE(instr.result, Runtime::method_bitOr(VALUE(instr.lhs), VALUE(instr.rhs))); MOTH_END_INSTR(BitOr) MOTH_BEGIN_INSTR(BitXor) - STOREVALUE(instr.result, engine->runtime.bitXor(VALUE(instr.lhs), VALUE(instr.rhs))); + STOREVALUE(instr.result, Runtime::method_bitXor(VALUE(instr.lhs), VALUE(instr.rhs))); MOTH_END_INSTR(BitXor) MOTH_BEGIN_INSTR(Shr) @@ -891,15 +891,15 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(ShlConst) MOTH_BEGIN_INSTR(Mul) - STOREVALUE(instr.result, engine->runtime.mul(VALUE(instr.lhs), VALUE(instr.rhs))); + STOREVALUE(instr.result, Runtime::method_mul(VALUE(instr.lhs), VALUE(instr.rhs))); MOTH_END_INSTR(Mul) MOTH_BEGIN_INSTR(Sub) - STOREVALUE(instr.result, engine->runtime.sub(VALUE(instr.lhs), VALUE(instr.rhs))); + STOREVALUE(instr.result, Runtime::method_sub(VALUE(instr.lhs), VALUE(instr.rhs))); MOTH_END_INSTR(Sub) MOTH_BEGIN_INSTR(BinopContext) - QV4::Runtime::BinaryOperationContext op = *reinterpret_cast(reinterpret_cast(&engine->runtime) + instr.alu); + QV4::Runtime::BinaryOperationContext op = *reinterpret_cast(reinterpret_cast(&engine->runtime.runtimeMethods[instr.alu])); STOREVALUE(instr.result, op(engine, VALUE(instr.lhs), VALUE(instr.rhs))); MOTH_END_INSTR(BinopContext) @@ -930,15 +930,15 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(LoadThis) MOTH_BEGIN_INSTR(LoadQmlContext) - VALUE(instr.result) = engine->runtime.getQmlContext(static_cast(engine)); + VALUE(instr.result) = Runtime::method_getQmlContext(static_cast(engine)); MOTH_END_INSTR(LoadQmlContext) MOTH_BEGIN_INSTR(LoadQmlImportedScripts) - VALUE(instr.result) = engine->runtime.getQmlImportedScripts(static_cast(engine)); + VALUE(instr.result) = Runtime::method_getQmlImportedScripts(static_cast(engine)); MOTH_END_INSTR(LoadQmlImportedScripts) MOTH_BEGIN_INSTR(LoadQmlSingleton) - VALUE(instr.result) = engine->runtime.getQmlSingleton(static_cast(engine), instr.name); + VALUE(instr.result) = Runtime::method_getQmlSingleton(static_cast(engine), instr.name); MOTH_END_INSTR(LoadQmlSingleton) #ifdef MOTH_THREADED_INTERPRETER -- cgit v1.2.3 From 25e40b18d5348064e1b31d491a22c50a2ffb89c3 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 14 Mar 2017 13:32:42 +0100 Subject: Protect CallData usage against cross-compilation word size differences Ensure via static asserts that the members always have the same offsets. Since the class has standard layout, we can also use the C++11 offsetof macro instead of qOffsetOf. Task-number: QTBUG-58666 Change-Id: I7dcecf517c771c7081334cd9d0b7ae133b23b23a Reviewed-by: Lars Knoll --- src/qml/compiler/qv4isel_moth_p.h | 2 +- src/qml/jit/qv4isel_masm.cpp | 8 ++++---- src/qml/jsruntime/qv4context_p.h | 6 ++++++ src/qml/jsruntime/qv4scopedvalue_p.h | 2 +- src/qml/jsruntime/qv4vme_moth.cpp | 26 +++++++++++++------------- 5 files changed, 25 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h index 41469f1985..4b84bd2831 100644 --- a/src/qml/compiler/qv4isel_moth_p.h +++ b/src/qml/compiler/qv4isel_moth_p.h @@ -179,7 +179,7 @@ private: int scratchTempIndex() const { return _function->tempCount; } int callDataStart() const { return scratchTempIndex() + 1; } - int outgoingArgumentTempStart() const { return callDataStart() + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value); } + int outgoingArgumentTempStart() const { return callDataStart() + offsetof(QV4::CallData, args)/sizeof(QV4::Value); } int frameSize() const { return outgoingArgumentTempStart() + _function->maxNumberOfArguments; } template diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 3803a5e119..cf7205661d 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -449,7 +449,7 @@ void InstructionSelection::loadThisObject(IR::Expr *temp) { _as->loadPtr(Address(JITTargetPlatform::EngineRegister, JITAssembler::targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister); _as->loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), JITTargetPlatform::ScratchRegister); - _as->copyValue(temp, Address(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject))); + _as->copyValue(temp, Address(JITTargetPlatform::ScratchRegister, offsetof(CallData, thisObject))); } template @@ -1313,11 +1313,11 @@ int InstructionSelection::prepareCallData(IR::ExprList* args, IR:: ++argc; } - Pointer p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, tag)); + Pointer p = _as->stackLayout().callDataAddress(offsetof(CallData, tag)); _as->store32(TrustedImm32(QV4::Value::Integer_Type_Internal), p); - p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, argc)); + p = _as->stackLayout().callDataAddress(offsetof(CallData, argc)); _as->store32(TrustedImm32(argc), p); - p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, thisObject)); + p = _as->stackLayout().callDataAddress(offsetof(CallData, thisObject)); if (!thisObject) _as->storeValue(QV4::Primitive::undefinedValue(), p); else diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index bcfee2e1f8..3c779e52a3 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -73,6 +73,8 @@ struct WithContext; struct QmlContext; struct QmlContextWrapper; +// Attention: Make sure that this structure is the same size on 32-bit and 64-bit +// architecture or you'll have to change the JIT code. struct CallData { // below is to be compatible with Value. Initialize tag to 0 @@ -91,6 +93,10 @@ struct CallData Value args[1]; }; +Q_STATIC_ASSERT(std::is_standard_layout::value); +Q_STATIC_ASSERT(offsetof(CallData, thisObject) == 8); +Q_STATIC_ASSERT(offsetof(CallData, args) == 16); + namespace Heap { struct QmlContext; diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 6775028272..894434be16 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -366,7 +366,7 @@ struct Scoped struct ScopedCallData { ScopedCallData(const Scope &scope, int argc = 0) { - int size = qMax(argc, (int)QV4::Global::ReservedArgumentCount) + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value); + int size = qMax(argc, QV4::Global::ReservedArgumentCount + int(offsetof(QV4::CallData, args)/sizeof(QV4::Value))); ptr = reinterpret_cast(scope.alloc(size)); ptr->tag = QV4::Value::Integer_Type_Internal; ptr->argc = argc; diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 988b0a03b2..17091819ee 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -571,7 +571,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code } } #endif // DO_TRACE_INSTR - Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; @@ -581,7 +581,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallProperty) TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); - Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; @@ -590,7 +590,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(CallProperty) MOTH_BEGIN_INSTR(CallPropertyLookup) - Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; @@ -600,7 +600,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallScopeObjectProperty) TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); - Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; @@ -610,7 +610,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallContextObjectProperty) TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); - Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; @@ -619,7 +619,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(CallContextObjectProperty) MOTH_BEGIN_INSTR(CallElement) - Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; @@ -628,7 +628,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(CallElement) MOTH_BEGIN_INSTR(CallActivationProperty) - Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; @@ -637,7 +637,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(CallActivationProperty) MOTH_BEGIN_INSTR(CallGlobalLookup) - Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; @@ -743,7 +743,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(CallBuiltinConvertThisToObject) MOTH_BEGIN_INSTR(CreateValue) - Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; @@ -752,7 +752,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(CreateValue) MOTH_BEGIN_INSTR(CreateProperty) - Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; @@ -761,7 +761,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(CreateProperty) MOTH_BEGIN_INSTR(ConstructPropertyLookup) - Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; @@ -770,7 +770,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(ConstructPropertyLookup) MOTH_BEGIN_INSTR(CreateActivationProperty) - Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; @@ -779,7 +779,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_END_INSTR(CreateActivationProperty) MOTH_BEGIN_INSTR(ConstructGlobalLookup) - Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); + Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = QV4::Value::Integer_Type_Internal; callData->argc = instr.argc; -- cgit v1.2.3 From 720dab7ad0f77b739a12f0e3e7e7178ea16c2e64 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 14 Mar 2017 13:51:27 +0100 Subject: Protect Lookup usage against cross-compilation word size differences The offsets we're taking from Lookup in the code generator are always zero, but with static assertions we can ensure that they stay that way. Task-number: QTBUG-58666 Change-Id: I91e047d2101ba33e36aaada4a5adc75e20fea7d8 Reviewed-by: Lars Knoll --- src/qml/jit/qv4isel_masm.cpp | 10 +++++----- src/qml/jsruntime/qv4lookup_p.h | 7 +++++++ 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index cf7205661d..d23380ed87 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -519,7 +519,7 @@ void InstructionSelection::getActivationProperty(const IR::Name *n { if (useFastLookups && name->global) { uint index = registerGlobalGetterLookup(*name->id); - generateLookupCall(target, index, qOffsetOf(QV4::Lookup, globalGetter), JITTargetPlatform::EngineRegister, JITAssembler::Void); + generateLookupCall(target, index, offsetof(QV4::Lookup, globalGetter), JITTargetPlatform::EngineRegister, JITAssembler::Void); return; } generateRuntimeCall(_as, target, getActivationProperty, JITTargetPlatform::EngineRegister, StringToIndex(*name->id)); @@ -545,7 +545,7 @@ void InstructionSelection::getProperty(IR::Expr *base, const QStri { if (useFastLookups) { uint index = registerGetterLookup(name); - generateLookupCall(target, index, qOffsetOf(QV4::Lookup, getter), JITTargetPlatform::EngineRegister, PointerToValue(base), JITAssembler::Void); + generateLookupCall(target, index, offsetof(QV4::Lookup, getter), JITTargetPlatform::EngineRegister, PointerToValue(base), JITAssembler::Void); } else { generateRuntimeCall(_as, target, getProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), StringToIndex(name)); @@ -584,7 +584,7 @@ void InstructionSelection::setProperty(IR::Expr *source, IR::Expr { if (useFastLookups) { uint index = registerSetterLookup(targetName); - generateLookupCall(JITAssembler::Void, index, qOffsetOf(QV4::Lookup, setter), + generateLookupCall(JITAssembler::Void, index, offsetof(QV4::Lookup, setter), JITTargetPlatform::EngineRegister, PointerToValue(targetBase), PointerToValue(source)); @@ -620,7 +620,7 @@ void InstructionSelection::getElement(IR::Expr *base, IR::Expr *in { if (useFastLookups) { uint lookup = registerIndexedGetterLookup(); - generateLookupCall(target, lookup, qOffsetOf(QV4::Lookup, indexedGetter), + generateLookupCall(target, lookup, offsetof(QV4::Lookup, indexedGetter), PointerToValue(base), PointerToValue(index)); return; @@ -635,7 +635,7 @@ void InstructionSelection::setElement(IR::Expr *source, IR::Expr * { if (useFastLookups) { uint lookup = registerIndexedSetterLookup(); - generateLookupCall(JITAssembler::Void, lookup, qOffsetOf(QV4::Lookup, indexedSetter), + generateLookupCall(JITAssembler::Void, lookup, offsetof(QV4::Lookup, indexedSetter), PointerToValue(targetBase), PointerToValue(targetIndex), PointerToValue(source)); return; diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index c5ee92fedd..2ffb43cce9 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -141,6 +141,13 @@ struct Lookup { }; +Q_STATIC_ASSERT(std::is_standard_layout::value); +// Ensure that these offsets are always at this point to keep generated code compatible +// across 32-bit and 64-bit (matters when cross-compiling). +Q_STATIC_ASSERT(offsetof(Lookup, indexedGetter) == 0); +Q_STATIC_ASSERT(offsetof(Lookup, getter) == 0); +Q_STATIC_ASSERT(offsetof(Lookup, engine) == offsetof(Lookup, getter) + QT_POINTER_SIZE); + } QT_END_NAMESPACE -- cgit v1.2.3 From 94b52fd93b8ec31981b097af0b29f39b6b294ce7 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 14 Mar 2017 15:31:06 +0100 Subject: Protect CompilationUnit member usage against word size differences Currently we only use the runtimeStrings offset in JIT generated code, so move that into a standard layout base class and use that instead. Task-number: QTBUG-58666 Change-Id: Id933ba5df3a6990e89886c2b328e9e814ec5e413 Reviewed-by: Lars Knoll --- src/qml/compiler/qv4compileddata.cpp | 1 - src/qml/compiler/qv4compileddata_p.h | 16 +++++++++------- src/qml/jit/qv4assembler.cpp | 2 +- src/qml/jsruntime/qv4context.cpp | 4 ++-- src/qml/jsruntime/qv4context_p.h | 4 ++-- src/qml/jsruntime/qv4runtime.cpp | 6 +++--- src/qml/jsruntime/qv4script_p.h | 2 +- src/qml/jsruntime/qv4vme_moth.cpp | 4 ++-- src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 2 +- 9 files changed, 21 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 668f20e4f2..cddc0dd8aa 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -95,7 +95,6 @@ static QString cacheFilePath(const QUrl &url) #ifndef V4_BOOTSTRAP CompilationUnit::CompilationUnit() : data(0) - , runtimeStrings(0) , engine(0) , runtimeLookups(0) , runtimeRegularExpressions(0) diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 110baafabe..6d219b85aa 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -71,7 +71,7 @@ QT_BEGIN_NAMESPACE // Bump this whenever the compiler data structures change in an incompatible way. -#define QV4_DATA_STRUCTURE_VERSION 0x10 +#define QV4_DATA_STRUCTURE_VERSION 0x11 class QIODevice; class QQmlPropertyCache; @@ -795,11 +795,15 @@ typedef QVector BindingPropertyData; // This is how this hooks into the existing structures: -//VM::Function -// CompilationUnit * (for functions that need to clean up) -// CompiledData::Function *compiledFunction +struct Q_QML_PRIVATE_EXPORT CompilationUnitBase +{ + QV4::Heap::String **runtimeStrings = 0; // Array +}; -struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount +Q_STATIC_ASSERT(std::is_standard_layout::value); +Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeStrings) == 0); + +struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase, public QQmlRefCount { #ifdef V4_BOOTSTRAP CompilationUnit() @@ -816,8 +820,6 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount // Called only when building QML, when we build the header for JS first and append QML data virtual QV4::CompiledData::Unit *createUnitData(QmlIR::Document *irDocument); - QV4::Heap::String **runtimeStrings; // Array - #ifndef V4_BOOTSTRAP ExecutionEngine *engine; diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 263f332f33..e941bd25cd 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -300,7 +300,7 @@ typename Assembler::Pointer Assembler: { loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), Assembler::ScratchRegister); loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, compilationUnit)), Assembler::ScratchRegister); - loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg); + loadPtr(Address(Assembler::ScratchRegister, offsetof(CompiledData::CompilationUnitBase, runtimeStrings)), reg); const int id = _jsGenerator->registerString(string); return Pointer(reg, id * sizeof(QV4::String*)); } diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 60b90e4bf0..c4a0539750 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -78,8 +78,8 @@ Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData c->activation = 0; c->compilationUnit = function->compilationUnit; - c->lookups = c->compilationUnit->runtimeLookups; - c->constantTable = c->compilationUnit->constants; + c->lookups = function->compilationUnit->runtimeLookups; + c->constantTable = function->compilationUnit->constants; c->locals = (Value *)((quintptr(c + 1) + 7) & ~7); const CompiledData::Function *compiledFunction = function->compiledFunction; diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 3c779e52a3..d0496d319e 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -61,7 +61,7 @@ class QQmlContextData; namespace QV4 { namespace CompiledData { -struct CompilationUnit; +struct CompilationUnitBase; struct Function; } @@ -126,7 +126,7 @@ struct ExecutionContext : Base { Pointer outer; Lookup *lookups; const QV4::Value *constantTable; - CompiledData::CompilationUnit *compilationUnit; + CompiledData::CompilationUnitBase *compilationUnit; ContextType type : 8; bool strictMode : 8; diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 6590054bf3..25748720aa 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -300,7 +300,7 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix) ReturnedValue Runtime::method_closure(ExecutionEngine *engine, int functionId) { - QV4::Function *clos = engine->current->compilationUnit->runtimeFunctions[functionId]; + QV4::Function *clos = static_cast(engine->current->compilationUnit)->runtimeFunctions[functionId]; Q_ASSERT(clos); return FunctionObject::createScriptFunction(engine->currentContext, clos)->asReturnedValue(); } @@ -1301,7 +1301,7 @@ ReturnedValue Runtime::method_arrayLiteral(ExecutionEngine *engine, Value *value ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags) { Scope scope(engine); - QV4::InternalClass *klass = engine->current->compilationUnit->runtimeClasses[classId]; + QV4::InternalClass *klass = static_cast(engine->current->compilationUnit)->runtimeClasses[classId]; ScopedObject o(scope, engine->newObject(klass, engine->objectPrototype())); { @@ -1413,7 +1413,7 @@ ReturnedValue Runtime::method_getQmlContext(NoThrowEngine *engine) ReturnedValue Runtime::method_regexpLiteral(ExecutionEngine *engine, int id) { - return engine->current->compilationUnit->runtimeRegularExpressions[id].asReturnedValue(); + return static_cast(engine->current->compilationUnit)->runtimeRegularExpressions[id].asReturnedValue(); } ReturnedValue Runtime::method_getQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired) diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index f96f0254a5..4ebe2dd609 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -72,7 +72,7 @@ struct ContextStateSaver { bool strictMode; Lookup *lookups; const QV4::Value *constantTable; - CompiledData::CompilationUnit *compilationUnit; + CompiledData::CompilationUnitBase *compilationUnit; int lineNumber; ContextStateSaver(const Scope &scope, ExecutionContext *context) diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 17091819ee..075a9a4a5d 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -404,7 +404,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code Q_ALLOCA_VAR(QV4::Value*, scopes, sizeof(QV4::Value *)*(2 + 2*scopeDepth)); { - scopes[0] = const_cast(context->d()->compilationUnit->constants); + scopes[0] = const_cast(static_cast(context->d()->compilationUnit)->constants); // stack gets setup in push instruction scopes[1] = 0; QV4::Heap::ExecutionContext *scope = context->d(); @@ -451,7 +451,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(LoadRegExp) // TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData()); - VALUE(instr.result) = context->d()->compilationUnit->runtimeRegularExpressions[instr.regExpId]; + VALUE(instr.result) = static_cast(context->d()->compilationUnit)->runtimeRegularExpressions[instr.regExpId]; MOTH_END_INSTR(LoadRegExp) MOTH_BEGIN_INSTR(LoadClosure) diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index d359a0f62f..8cc0b32168 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -1885,7 +1885,7 @@ void GlobalExtensions::method_qsTr(const BuiltinFunction *, Scope &scope, CallDa ExecutionContext *parentCtx = scope.engine->currentContext; // The first non-empty source URL in the call stack determines the translation context. while (!!parentCtx && context.isEmpty()) { - if (QV4::CompiledData::CompilationUnit *unit = parentCtx->d()->compilationUnit) { + if (CompiledData::CompilationUnit *unit = static_cast(parentCtx->d()->compilationUnit)) { QString fileName = unit->fileName(); QUrl url(unit->fileName()); if (url.isValid() && url.isRelative()) { -- cgit v1.2.3 From 53547ee6b3a828969a3e2283a6ea5b3141f065d5 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 14 Mar 2017 15:44:16 +0100 Subject: Clean up qOffsetOf usage For offsets from CompiledData::Unit we can use C++11's offsetof macro as the class has standard layout. Change-Id: I7377294679a9cd79c35486fa34355933271f9251 Reviewed-by: Lars Knoll --- src/qml/compiler/qv4compileddata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index cddc0dd8aa..4688f936cc 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -776,7 +776,7 @@ void Unit::generateChecksum() #ifndef V4_BOOTSTRAP QCryptographicHash hash(QCryptographicHash::Md5); - const int checksummableDataOffset = qOffsetOf(QV4::CompiledData::Unit, md5Checksum) + sizeof(md5Checksum); + const int checksummableDataOffset = offsetof(QV4::CompiledData::Unit, md5Checksum) + sizeof(md5Checksum); const char *dataPtr = reinterpret_cast(this) + checksummableDataOffset; hash.addData(dataPtr, unitSize - checksummableDataOffset); -- cgit v1.2.3 From cbdf28b078bbe0ce4136013ecdba1511fc926601 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 14 Mar 2017 17:02:59 +0100 Subject: Protect ExecutionContext member usage against word size differences Ensure the offsets we're taking from ExecutionContext members in the JIT code generator can be translated from host architecture sizes to target architecture, using assertions and a memory layout that we already have in the dev branch with commit 4de7e48ab160dacc7a09360e80264eac4945a8f4. Task-number: QTBUG-58666 Change-Id: I26cdbd1ddb995b116624fab16f7caba5d21c13b5 Reviewed-by: Lars Knoll --- src/qml/jit/qv4assembler.cpp | 16 ++++++++++------ src/qml/jit/qv4assembler_p.h | 2 +- src/qml/jit/qv4isel_masm.cpp | 4 ++-- src/qml/jsruntime/qv4context_p.h | 41 ++++++++++++++++++++++++++++++---------- src/qml/memory/qv4heap_p.h | 6 ++++++ 5 files changed, 50 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index e941bd25cd..66cf502bde 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -270,18 +270,22 @@ typename Assembler::Pointer Assembler: int32_t offset = 0; int scope = al->scope; loadPtr(Address(EngineRegister, targetStructureOffset(offsetof(EngineBase, current))), baseReg); + + const qint32 outerOffset = targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, outer)); + if (scope) { - loadPtr(Address(baseReg, qOffsetOf(ExecutionContext::Data, outer)), baseReg); + loadPtr(Address(baseReg, outerOffset), baseReg); --scope; while (scope) { - loadPtr(Address(baseReg, qOffsetOf(ExecutionContext::Data, outer)), baseReg); + loadPtr(Address(baseReg, outerOffset), baseReg); --scope; } } switch (al->kind) { case IR::ArgLocal::Formal: case IR::ArgLocal::ScopedFormal: { - loadPtr(Address(baseReg, qOffsetOf(ExecutionContext::Data, callData)), baseReg); + const qint32 callDataOffset = targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, callData)); + loadPtr(Address(baseReg, callDataOffset), baseReg); offset = sizeof(CallData) + (al->index - 1) * sizeof(Value); } break; case IR::ArgLocal::Local: @@ -299,7 +303,7 @@ template typename Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &string) { loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), Assembler::ScratchRegister); - loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, compilationUnit)), Assembler::ScratchRegister); + loadPtr(Address(Assembler::ScratchRegister, targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, compilationUnit))), Assembler::ScratchRegister); loadPtr(Address(Assembler::ScratchRegister, offsetof(CompiledData::CompilationUnitBase, runtimeStrings)), reg); const int id = _jsGenerator->registerString(string); return Pointer(reg, id * sizeof(QV4::String*)); @@ -315,7 +319,7 @@ template typename Assembler::Address Assembler::loadConstant(const Primitive &v, RegisterID baseReg) { loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), baseReg); - loadPtr(Address(baseReg, qOffsetOf(QV4::Heap::ExecutionContext, constantTable)), baseReg); + loadPtr(Address(baseReg, targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, constantTable))), baseReg); const int index = _jsGenerator->registerConstant(v.asReturnedValue()); return Address(baseReg, index * sizeof(QV4::Value)); } @@ -519,7 +523,7 @@ void Assembler::returnFromFunction(IR::Ret *s, RegisterInfo const int locals = stackLayout().calculateJSStackFrameSize(); subPtr(TrustedImm32(sizeof(QV4::Value)*locals), JITTargetPlatform::LocalsRegister); loadPtr(Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister); - loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, engine)), JITTargetPlatform::ScratchRegister); + loadPtr(Address(JITTargetPlatform::ScratchRegister, targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, engine))), JITTargetPlatform::ScratchRegister); storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::ScratchRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop)))); leaveStandardStackFrame(regularRegistersToSave, fpRegistersToSave); diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 3cd33e91e7..1a9aefb4bc 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -1324,7 +1324,7 @@ public: // load the table from the context loadPtr(Address(EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), ScratchRegister); - loadPtr(Address(ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, lookups)), + loadPtr(Address(ScratchRegister, targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, lookups))), lookupCall.addr.base); // pre-calculate the indirect address for the lookupCall table: if (lookupCall.addr.offset) diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index d23380ed87..4a222e20f4 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -133,7 +133,7 @@ void InstructionSelection::run(int functionIndex) if (s->location.isValid()) { if (int(s->location.startLine) != lastLine) { _as->loadPtr(Address(JITTargetPlatform::EngineRegister, JITAssembler::targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister); - Address lineAddr(JITTargetPlatform::ScratchRegister, qOffsetOf(QV4::ExecutionContext::Data, lineNumber)); + Address lineAddr(JITTargetPlatform::ScratchRegister, JITAssembler::targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, lineNumber))); _as->store32(TrustedImm32(s->location.startLine), lineAddr); lastLine = s->location.startLine; } @@ -448,7 +448,7 @@ template void InstructionSelection::loadThisObject(IR::Expr *temp) { _as->loadPtr(Address(JITTargetPlatform::EngineRegister, JITAssembler::targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister); - _as->loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), JITTargetPlatform::ScratchRegister); + _as->loadPtr(Address(JITTargetPlatform::ScratchRegister, JITAssembler::targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, callData))), JITTargetPlatform::ScratchRegister); _as->copyValue(temp, Address(JITTargetPlatform::ScratchRegister, offsetof(CallData, thisObject))); } diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index d0496d319e..968f625e5c 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -101,7 +101,37 @@ namespace Heap { struct QmlContext; -struct ExecutionContext : Base { +// ### Temporary arrangment until this code hits the dev branch and +// can use the Members macro +struct ExecutionContextData { + CallData *callData; + ExecutionEngine *engine; + ExecutionContext *outer; + Lookup *lookups; + const QV4::Value *constantTable; + CompiledData::CompilationUnitBase *compilationUnit; + // as member of non-pointer size this has to come last to preserve the ability to + // translate offsetof of it between 64-bit and 32-bit. + int lineNumber; +#if QT_POINTER_SIZE == 8 + uint padding_; +#endif +}; + +Q_STATIC_ASSERT(std::is_standard_layout::value); +Q_STATIC_ASSERT(offsetof(ExecutionContextData, callData) == 0); +Q_STATIC_ASSERT(offsetof(ExecutionContextData, engine) == offsetof(ExecutionContextData, callData) + QT_POINTER_SIZE); +Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == offsetof(ExecutionContextData, engine) + QT_POINTER_SIZE); +Q_STATIC_ASSERT(offsetof(ExecutionContextData, lookups) == offsetof(ExecutionContextData, outer) + QT_POINTER_SIZE); +Q_STATIC_ASSERT(offsetof(ExecutionContextData, constantTable) == offsetof(ExecutionContextData, lookups) + QT_POINTER_SIZE); +Q_STATIC_ASSERT(offsetof(ExecutionContextData, compilationUnit) == offsetof(ExecutionContextData, constantTable) + QT_POINTER_SIZE); +Q_STATIC_ASSERT(offsetof(ExecutionContextData, lineNumber) == offsetof(ExecutionContextData, compilationUnit) + QT_POINTER_SIZE); + +struct ExecutionContextSizeStruct : public Base, public ExecutionContextData {}; + +struct ExecutionContext : Base, public ExecutionContextData { + static Q_CONSTEXPR size_t baseOffset = sizeof(ExecutionContextSizeStruct) - sizeof(ExecutionContextData); + enum ContextType { Type_GlobalContext = 0x1, Type_CatchContext = 0x2, @@ -120,17 +150,8 @@ struct ExecutionContext : Base { lineNumber = -1; } - CallData *callData; - - ExecutionEngine *engine; - Pointer outer; - Lookup *lookups; - const QV4::Value *constantTable; - CompiledData::CompilationUnitBase *compilationUnit; - ContextType type : 8; bool strictMode : 8; - int lineNumber; }; V4_ASSERT_IS_TRIVIAL(ExecutionContext) diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index 8285ef4de7..bdb5bef92b 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -160,6 +160,12 @@ struct Q_QML_EXPORT Base { #endif }; V4_ASSERT_IS_TRIVIAL(Base) +// This class needs to consist only of pointer sized members to allow +// for a size/offset translation when cross-compiling between 32- and +// 64-bit. +Q_STATIC_ASSERT(std::is_standard_layout::value); +Q_STATIC_ASSERT(offsetof(Base, vt) == 0); +Q_STATIC_ASSERT(sizeof(Base) == QT_POINTER_SIZE); template struct Pointer { -- cgit v1.2.3 From cb4f4028ac9fcc4d8f758899ad1eb2099ffad559 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 15 Mar 2017 08:04:18 +0100 Subject: Remove unused macro This duplicate of qOffsetOf is not used in this file. Change-Id: I8a5ddfe18202501605a06f65c952b58e557dbfac Reviewed-by: Lars Knoll --- src/qml/qml/qqmltypeloader.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 68eb989c70..372b05eeef 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -80,10 +80,6 @@ # define NAME_MAX _POSIX_SYMLINK_MAX #endif -// LSB has a broken version of qOffsetOf that can't be used at compile time -// https://lsbbugs.linuxfoundation.org/show_bug.cgi?id=3462 -#undef qOffsetOf -#define qOffsetOf(TYPE, MEMBER) __builtin_qOffsetOf (TYPE, MEMBER) #endif // #define DATABLOB_DEBUG -- cgit v1.2.3 From 7a125135e1ef592aa20a29f7aac1a6117a6b1770 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 15 Mar 2017 08:25:56 +0100 Subject: Protect CallContext member usage against word size differences Ensure the offsets we're taking from ExecutionContext members in the JIT code generator can be translated from host architecture sizes to target architecture, using assertions and a memory layout that we already have in the dev branch with commit 4de7e48ab160dacc7a09360e80264eac4945a8f4. Change-Id: I1b26ef265234b05a6e5c8688a8aad2f33cd28783 Task-number: QTBUG-58666 Reviewed-by: Lars Knoll --- .../qmltooling/qmldbg_debugger/qv4datacollector.cpp | 2 +- src/qml/jit/qv4assembler.cpp | 3 ++- src/qml/jsruntime/qv4context_p.h | 21 ++++++++++++++++++--- 3 files changed, 21 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index 5d2e754057..8075b7c067 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -95,7 +95,7 @@ QVector QV4DataCollector::getScopeType QV4::ScopedContext it(scope, sctxt); for (; it; it = it->d()->outer) - types.append(it->d()->type); + types.append(QV4::Heap::ExecutionContext::ContextType(it->d()->type)); return types; } diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 66cf502bde..5c90aba464 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -290,7 +290,8 @@ typename Assembler::Pointer Assembler: } break; case IR::ArgLocal::Local: case IR::ArgLocal::ScopedLocal: { - loadPtr(Address(baseReg, qOffsetOf(CallContext::Data, locals)), baseReg); + const qint32 localsOffset = targetStructureOffset(Heap::CallContext::baseOffset + offsetof(Heap::CallContextData, locals)); + loadPtr(Address(baseReg, localsOffset), baseReg); offset = al->index * sizeof(Value); } break; default: diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 968f625e5c..c769dcd142 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -150,12 +150,28 @@ struct ExecutionContext : Base, public ExecutionContextData { lineNumber = -1; } - ContextType type : 8; + quint8 type; bool strictMode : 8; +#if QT_POINTER_SIZE == 8 + quint8 padding_[6]; +#else + quint8 padding_[2]; +#endif }; V4_ASSERT_IS_TRIVIAL(ExecutionContext) +Q_STATIC_ASSERT(sizeof(ExecutionContext) == sizeof(Base) + sizeof(ExecutionContextData) + QT_POINTER_SIZE); + +struct CallContextData { + Value *locals; +}; + +Q_STATIC_ASSERT(std::is_standard_layout::value); +Q_STATIC_ASSERT(offsetof(CallContextData, locals) == 0); -struct CallContext : ExecutionContext { +struct CallContextSizeStruct : public ExecutionContext, public CallContextData {}; + +struct CallContext : ExecutionContext, public CallContextData { + static Q_CONSTEXPR size_t baseOffset = sizeof(CallContextSizeStruct) - sizeof(CallContextData); static CallContext *createSimpleContext(ExecutionEngine *v4); void freeSimpleCallContext(); @@ -168,7 +184,6 @@ struct CallContext : ExecutionContext { Pointer function; QV4::Function *v4Function; - Value *locals; Pointer activation; }; V4_ASSERT_IS_TRIVIAL(CallContext) -- cgit v1.2.3 From 13fc05fde8cde6a81d3cf3161fa34cf9d3652eb2 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 7 Mar 2017 19:52:34 +0100 Subject: Document and demo that fboId can be 0 ...in QQuickWindow::setRenderTarget(). The rendercontrol example is extended with a --onscreen command line argument that can be used to request rendering to the default framebuffer of the window. Change-Id: I7a500d1585dee8334b902fb1dddcb1cb21a2e038 Task-number: QTBUG-59340 Reviewed-by: Gunnar Sletta --- src/quick/items/qquickwindow.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index e6245f90f3..80abf82e58 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -3399,6 +3399,11 @@ void QQuickWindow::setRenderTarget(QOpenGLFramebufferObject *fbo) The specified FBO must be created in the context of the window or one that shares with it. + \note \a fboId can also be set to 0. In this case rendering will target the + default framebuffer of whichever surface is current when the scenegraph + renders. \a size must still be valid, specifying the dimensions of the + surface. + \note This function only has an effect when using the default OpenGL scene graph adaptation. -- cgit v1.2.3 From 09479fac4c08c9e2c159df4f87fa61dbc3836816 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Fri, 17 Mar 2017 15:39:53 +0100 Subject: QQuickImageProvider: Improve documentation about cancel() and finished() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes it a little more obvious how best to use this. We could do with including some snippets showing how to ideally implement cancel() I think, but this is a good start. Change-Id: I88d63a451239f91aa3619ccb74e306a2052a6e70 Task-number: QTBUG-59485 Reviewed-by: Albert Astals Cid Reviewed-by: Pasi Petäjäjärvi --- src/quick/util/qquickimageprovider.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp index a026abe762..0ceed7f681 100644 --- a/src/quick/util/qquickimageprovider.cpp +++ b/src/quick/util/qquickimageprovider.cpp @@ -183,7 +183,12 @@ QString QQuickImageResponse::errorString() const It may be reimplemented to cancel a request in the provider side, however, it is not mandatory. - A cancelled QQuickImageResponse still needs to emit finished(). + A cancelled QQuickImageResponse still needs to emit finished() so that the + engine may clean up the QQuickImageResponse. + + \note finished() should not be emitted until the response is complete, + regardless of whether or not cancel() was called. If it is called prematurely, + the engine may destroy the response while it is still active, leading to a crash. */ void QQuickImageResponse::cancel() { @@ -192,7 +197,12 @@ void QQuickImageResponse::cancel() /*! \fn void QQuickImageResponse::finished() - Signals that the job execution has finished (be it successfully, because an error happened or because it was cancelled). + Signals that the job execution has finished (be it successfully, because an + error happened or because it was cancelled). + + \note Emission of this signal must be the final action the response performs: + once the signal is received, the response will subsequently be destroyed by + the engine. */ /*! -- cgit v1.2.3 From 6825b37a48de6a69def38897b03ff7f9974226dd Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Fri, 17 Mar 2017 13:19:50 +0100 Subject: Expose QQuickItem::size() and document QQuickItem::setSize() [ChangeLog][QtQuick][QQuickItem] Add QQuickItem::size() and document QQuickItem::setSize(). Change-Id: I6f4d531e046758eb062111d656cc2e0be1624da3 Reviewed-by: Shawn Rutledge --- src/quick/items/qquickitem.cpp | 23 +++++++++++++++++++++-- src/quick/items/qquickitem.h | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index aa2662489d..539a374dd9 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -6746,8 +6746,27 @@ bool QQuickItem::heightValid() const } /*! - \internal - */ + \since 5.10 + + Returns the size of the item. + + \sa setSize, width, height + */ + +QSizeF QQuickItem::size() const +{ + Q_D(const QQuickItem); + return QSizeF(d->width, d->height); +} + + +/*! + \since 5.10 + + Sets the size of the item to \a size. + + \sa size, setWidth, setHeight + */ void QQuickItem::setSize(const QSizeF &size) { Q_D(QQuickItem); diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index c9494d91bd..f58946d01d 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -237,6 +237,7 @@ public: void setImplicitHeight(qreal); qreal implicitHeight() const; + QSizeF size() const; void setSize(const QSizeF &size); TransformOrigin transformOrigin() const; -- cgit v1.2.3 From ddb1b8f226693730e3bdb85a0fe78c7ed3c43a79 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Sun, 19 Mar 2017 18:47:31 +0100 Subject: QQuickEvents: Fix documentation of types for MouseEvent and WheelEvent x/y These types are qreal, not int. Change-Id: I26569c40825ce098ea095b3d9dc9b84eb3870c02 Reviewed-by: Mitch Curtis Reviewed-by: Shawn Rutledge --- src/quick/items/qquickevents.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index b6c45c40a8..f1f82f9e0e 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -193,8 +193,8 @@ Item { */ /*! - \qmlproperty int QtQuick::MouseEvent::x - \qmlproperty int QtQuick::MouseEvent::y + \qmlproperty real QtQuick::MouseEvent::x + \qmlproperty real QtQuick::MouseEvent::y These properties hold the coordinates of the position supplied by the mouse event. */ @@ -340,8 +340,8 @@ Item { */ /*! - \qmlproperty int QtQuick::WheelEvent::x - \qmlproperty int QtQuick::WheelEvent::y + \qmlproperty real QtQuick::WheelEvent::x + \qmlproperty real QtQuick::WheelEvent::y These properties hold the coordinates of the position supplied by the wheel event. */ -- cgit v1.2.3 From 4db21fe60e9a852298e12d7fce7b5d2bbde7443e Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 15 Mar 2017 09:25:52 +0100 Subject: Complete transition to standard layout classes for JIT access Move the Runtime function pointer array into EngineBase so that we can eliminate the last use of qOffsetOf. For improved cache locality the memory manager point is now also located in the EngineBase. Change-Id: I0b3cf44c726aa4fb8db1206cc414a56c2f522a84 Task-number: QTBUG-58666 Reviewed-by: Lars Knoll --- src/qml/jit/qv4assembler_p.h | 2 +- src/qml/jsruntime/qv4engine.cpp | 3 ++- src/qml/jsruntime/qv4engine_p.h | 6 ------ src/qml/jsruntime/qv4global_p.h | 2 -- src/qml/jsruntime/qv4runtime.cpp | 8 ++++++++ src/qml/jsruntime/qv4runtimeapi_p.h | 10 ++-------- src/qml/jsruntime/qv4value_p.h | 2 -- src/qml/memory/qv4mmdefs_p.h | 8 ++++++++ 8 files changed, 21 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 1a9aefb4bc..e507a14f12 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -1687,7 +1687,7 @@ void Assembler::copyValue(Result result, IR::Expr* source) template inline Assembler::RuntimeCall::RuntimeCall(Runtime::RuntimeMethods method) : addr(Assembler::EngineRegister, - method == Runtime::InvalidRuntimeMethod ? -1 : (Assembler::targetStructureOffset(qOffsetOf(QV4::ExecutionEngine, runtime) + Runtime::runtimeMethodOffset(method)))) + method == Runtime::InvalidRuntimeMethod ? -1 : (Assembler::targetStructureOffset(offsetof(EngineBase, runtime) + Runtime::runtimeMethodOffset(method)))) { } diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 3f11e51799..83b00f0356 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -131,7 +131,6 @@ qint32 ExecutionEngine::maxCallDepth = -1; ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) : callDepth(0) - , memoryManager(new QV4::MemoryManager(this)) , executableAllocator(new QV4::ExecutableAllocator) , regExpAllocator(new QV4::ExecutableAllocator) , currentContext(0) @@ -149,6 +148,8 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) , m_profiler(0) #endif { + memoryManager = new QV4::MemoryManager(this); + if (maxCallDepth == -1) { bool ok = false; maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 0492191747..5182f24235 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -54,7 +54,6 @@ #include "private/qv4isel_p.h" #include "qv4managed_p.h" #include "qv4context_p.h" -#include "qv4runtimeapi_p.h" #include #ifndef V4_BOOTSTRAP @@ -97,13 +96,8 @@ private: friend struct ExecutionContext; friend struct Heap::ExecutionContext; public: - // This must be the first member, so that its offset is a multiple of QT_POINTER_SIZE - // as the base class's size is. - Runtime runtime; - qint32 callDepth; - MemoryManager *memoryManager; ExecutableAllocator *executableAllocator; ExecutableAllocator *regExpAllocator; QScopedPointer iselFactory; diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 66861bf697..c2a5e75a1f 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -89,8 +89,6 @@ inline bool signbit(double d) { return _copysign(1.0, d) < 0; } inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); } #endif -#define qOffsetOf(s, m) ((size_t)((((char *)&(((s *)64)->m)) - 64))) - // Decide whether to enable or disable the JIT // White list architectures diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 25748720aa..97fd533af2 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -219,6 +219,14 @@ void RuntimeCounters::count(const char *func, uint tag1, uint tag2) #endif // QV4_COUNT_RUNTIME_FUNCTIONS #ifndef V4_BOOTSTRAP + +Runtime::Runtime() +{ +#define INIT_METHOD(returnvalue, name, args) runtimeMethods[name] = reinterpret_cast(&method_##name); +FOR_EACH_RUNTIME_METHOD(INIT_METHOD) +#undef INIT_METHOD +} + void RuntimeHelpers::numberToString(QString *result, double num, int radix) { Q_ASSERT(result); diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index 2c898a1880..302facba06 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE namespace QV4 { +typedef uint Bool; struct NoThrowEngine; namespace { @@ -223,12 +224,7 @@ struct ExceptionCheck { F(void, setQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value)) struct Q_QML_PRIVATE_EXPORT Runtime { - Runtime() - { -#define INIT_METHOD(returnvalue, name, args) runtimeMethods[name] = reinterpret_cast(&method_##name); -FOR_EACH_RUNTIME_METHOD(INIT_METHOD) -#undef INIT_METHOD - } + Runtime(); typedef ReturnedValue (*UnaryOperation)(const Value &value); typedef ReturnedValue (*BinaryOperation)(const Value &left, const Value &right); @@ -259,8 +255,6 @@ static_assert(std::is_standard_layout::value, "Runtime needs to be stan static_assert(offsetof(Runtime, runtimeMethods) == 0, "JIT expects this to be the first member"); static_assert(sizeof(Runtime::BinaryOperation) == sizeof(void*), "JIT expects a function pointer to fit into a regular pointer, for cross-compilation offset translation"); -#undef FOR_EACH_RUNTIME_METHOD - } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 4ff0565f9b..5662432f0d 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -68,8 +68,6 @@ namespace Heap { struct Base; } -typedef uint Bool; - struct Q_QML_PRIVATE_EXPORT Value { private: diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index edae7293ce..db0ffe11a2 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -51,6 +51,7 @@ // #include +#include #include #include @@ -265,6 +266,11 @@ struct EngineBase { Value *jsStackTop = 0; quint32 hasException = false; +#if QT_POINTER_SIZE == 8 + quint8 padding[4]; +#endif + MemoryManager *memoryManager = 0; + Runtime runtime; }; #if defined(Q_CC_MSVC) || defined(Q_CC_GNU) #pragma pack(pop) @@ -274,6 +280,8 @@ Q_STATIC_ASSERT(std::is_standard_layout::value); Q_STATIC_ASSERT(offsetof(EngineBase, current) == 0); Q_STATIC_ASSERT(offsetof(EngineBase, jsStackTop) == offsetof(EngineBase, current) + QT_POINTER_SIZE); Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsStackTop) + QT_POINTER_SIZE); +Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + QT_POINTER_SIZE); +Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE); } -- cgit v1.2.3 From 1bc9e17636f5fd0a4c86cba379f0060fe894b1bb Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 17 Mar 2017 17:49:44 +0100 Subject: V4 Debugger: Encode NaN and +/-Infinity as strings JSON doesn't have numerical values for those. However, as we give the type of each item in a separate field, we can just use strings here and the result will still not clash with actual strings. Task-number: QTBUG-47880 Change-Id: I85ffa008890a8a9e6894dd3151f7dc6b527ed5e1 Reviewed-by: Simon Hausmann --- src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index 8075b7c067..b4b95f6713 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -187,10 +187,19 @@ const QV4::Object *collectProperty(const QV4::ScopedValue &value, QV4::Execution case QV4::Value::Integer_Type: dict.insert(valueKey, value->integerValue()); return 0; - default: // double - dict.insert(valueKey, value->doubleValue()); + default: {// double + const double val = value->doubleValue(); + if (qIsFinite(val)) + dict.insert(valueKey, val); + else if (qIsNaN(val)) + dict.insert(valueKey, QStringLiteral("NaN")); + else if (val < 0) + dict.insert(valueKey, QStringLiteral("-Infinity")); + else + dict.insert(valueKey, QStringLiteral("Infinity")); return 0; } + } } QJsonObject QV4DataCollector::lookupRef(Ref ref, bool deep) -- cgit v1.2.3 From b5903ba46e065b096d7bcc12b11cde32b1c0f0c7 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Mon, 13 Mar 2017 18:19:33 +0100 Subject: QSGDistanceFieldUtil: Remove a layer of indirection These mysterious setters appear to be unused (and always were, as far as I can see). How useful they are is not entirely clear (as opposed to a patch to the source for instance, and as it's private API anyway, you'd be touching internals to use this. Additionally, removing the indirection makes the code a bit cleaner and more self-contained in my opinion. This removal leaves the value of QSGDistanceFieldGlyphCacheManager in some question to me, given that it's basically a glorified wrapper around QHash. Change-Id: I6d18eb40d8cd00ebe389b4ed53448f3401962ae6 Reviewed-by: Gunnar Sletta Reviewed-by: Yoann Lopes --- .../scenegraph/qsgdistancefieldglyphnode_p.cpp | 41 ++++++++++++++++------ src/quick/scenegraph/util/qsgdistancefieldutil.cpp | 26 -------------- src/quick/scenegraph/util/qsgdistancefieldutil_p.h | 12 ------- 3 files changed, 30 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp index fc66f2f2cc..153f0a45c5 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp @@ -58,7 +58,7 @@ public: protected: void initialize() override; - void updateAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc); + void updateAlphaRange(); void updateColor(const QVector4D &c); void updateTextureScale(const QVector2D &ts); @@ -98,7 +98,31 @@ QSGDistanceFieldTextMaterialShader::QSGDistanceFieldTextMaterialShader() setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/distancefieldtext.frag")); } -void QSGDistanceFieldTextMaterialShader::updateAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc) +static float qt_sg_envFloat(const char *name, float defaultValue) +{ + if (Q_LIKELY(!qEnvironmentVariableIsSet(name))) + return defaultValue; + bool ok = false; + const float value = qgetenv(name).toFloat(&ok); + return ok ? value : defaultValue; +} + +static float thresholdFunc(float glyphScale) +{ + static const float base = qt_sg_envFloat("QT_DF_BASE", 0.5f); + static const float baseDev = qt_sg_envFloat("QT_DF_BASEDEVIATION", 0.065f); + static const float devScaleMin = qt_sg_envFloat("QT_DF_SCALEFORMAXDEV", 0.15f); + static const float devScaleMax = qt_sg_envFloat("QT_DF_SCALEFORNODEV", 0.3f); + return base - ((qBound(devScaleMin, glyphScale, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin) * -baseDev + baseDev); +} + +static float spreadFunc(float glyphScale) +{ + static const float range = qt_sg_envFloat("QT_DF_RANGE", 0.06f); + return range / glyphScale; +} + +void QSGDistanceFieldTextMaterialShader::updateAlphaRange() { float combinedScale = m_fontScale * m_matrixScale; float base = thresholdFunc(combinedScale); @@ -169,8 +193,7 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q updateRange = true; } if (updateRange) { - updateAlphaRange(material->glyphCache()->manager()->thresholdFunc(), - material->glyphCache()->manager()->antialiasingSpreadFunc()); + updateAlphaRange(); } Q_ASSERT(material->glyphCache()); @@ -334,7 +357,7 @@ public: protected: void initialize() override; - void updateOutlineAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc, int dfRadius); + void updateOutlineAlphaRange(int dfRadius); int m_outlineAlphaMax0_id; int m_outlineAlphaMax1_id; @@ -355,9 +378,7 @@ void DistanceFieldOutlineTextMaterialShader::initialize() m_outlineAlphaMax1_id = program()->uniformLocation("outlineAlphaMax1"); } -void DistanceFieldOutlineTextMaterialShader::updateOutlineAlphaRange(ThresholdFunc thresholdFunc, - AntialiasingSpreadFunc spreadFunc, - int dfRadius) +void DistanceFieldOutlineTextMaterialShader::updateOutlineAlphaRange(int dfRadius) { float combinedScale = m_fontScale * m_matrixScale; float base = thresholdFunc(combinedScale); @@ -381,9 +402,7 @@ void DistanceFieldOutlineTextMaterialShader::updateState(const RenderState &stat if (oldMaterial == 0 || material->fontScale() != oldMaterial->fontScale() || state.isMatrixDirty()) - updateOutlineAlphaRange(material->glyphCache()->manager()->thresholdFunc(), - material->glyphCache()->manager()->antialiasingSpreadFunc(), - material->glyphCache()->distanceFieldRadius()); + updateOutlineAlphaRange(material->glyphCache()->distanceFieldRadius()); } diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp index 9ca9cdb107..97a5853bd6 100644 --- a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp +++ b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp @@ -47,33 +47,7 @@ QT_BEGIN_NAMESPACE -static float qt_sg_envFloat(const char *name, float defaultValue) -{ - if (Q_LIKELY(!qEnvironmentVariableIsSet(name))) - return defaultValue; - bool ok = false; - const float value = qgetenv(name).toFloat(&ok); - return ok ? value : defaultValue; -} - -static float defaultThresholdFunc(float glyphScale) -{ - static const float base = qt_sg_envFloat("QT_DF_BASE", 0.5f); - static const float baseDev = qt_sg_envFloat("QT_DF_BASEDEVIATION", 0.065f); - static const float devScaleMin = qt_sg_envFloat("QT_DF_SCALEFORMAXDEV", 0.15f); - static const float devScaleMax = qt_sg_envFloat("QT_DF_SCALEFORNODEV", 0.3f); - return base - ((qBound(devScaleMin, glyphScale, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin) * -baseDev + baseDev); -} - -static float defaultAntialiasingSpreadFunc(float glyphScale) -{ - static const float range = qt_sg_envFloat("QT_DF_RANGE", 0.06f); - return range / glyphScale; -} - QSGDistanceFieldGlyphCacheManager::QSGDistanceFieldGlyphCacheManager() - : m_threshold_func(defaultThresholdFunc) - , m_antialiasingSpread_func(defaultAntialiasingSpreadFunc) { } diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h b/src/quick/scenegraph/util/qsgdistancefieldutil_p.h index ad366cb4d4..78e7ce15cd 100644 --- a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h +++ b/src/quick/scenegraph/util/qsgdistancefieldutil_p.h @@ -57,9 +57,6 @@ QT_BEGIN_NAMESPACE -typedef float (*ThresholdFunc)(float glyphScale); -typedef float (*AntialiasingSpreadFunc)(float glyphScale); - class QOpenGLShaderProgram; class QSGDistanceFieldGlyphCache; class QSGContext; @@ -73,17 +70,8 @@ public: QSGDistanceFieldGlyphCache *cache(const QRawFont &font); void insertCache(const QRawFont &font, QSGDistanceFieldGlyphCache *cache); - ThresholdFunc thresholdFunc() const { return m_threshold_func; } - void setThresholdFunc(ThresholdFunc func) { m_threshold_func = func; } - - AntialiasingSpreadFunc antialiasingSpreadFunc() const { return m_antialiasingSpread_func; } - void setAntialiasingSpreadFunc(AntialiasingSpreadFunc func) { m_antialiasingSpread_func = func; } - private: QHash m_caches; - - ThresholdFunc m_threshold_func; - AntialiasingSpreadFunc m_antialiasingSpread_func; }; QT_END_NAMESPACE -- cgit v1.2.3 From 59d8fa914d5d72a7973b91e67235e6fdf9686d7d Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Mon, 13 Mar 2017 18:33:58 +0100 Subject: Remove QSGDistanceFieldGlyphCacheManager After the previous cleanups, it became clear that this didn't serve much of a purpose, so let's remove it and simplify the implementation as a result. Change-Id: Iae2ff9c46762f0c7bdf4225a2c4df93bc8253902 Reviewed-by: Yoann Lopes --- src/quick/scenegraph/qsgadaptationlayer.cpp | 6 +- src/quick/scenegraph/qsgadaptationlayer_p.h | 7 +- src/quick/scenegraph/qsgcontext.cpp | 1 - src/quick/scenegraph/qsgcontext_p.h | 3 +- src/quick/scenegraph/qsgdefaultcontext.cpp | 1 - .../qsgdefaultdistancefieldglyphcache.cpp | 5 +- .../qsgdefaultdistancefieldglyphcache_p.h | 2 +- src/quick/scenegraph/qsgdefaultrendercontext.cpp | 14 ++-- src/quick/scenegraph/qsgdistancefieldglyphnode.cpp | 1 - .../scenegraph/qsgdistancefieldglyphnode_p.cpp | 1 - src/quick/scenegraph/qsgdistancefieldglyphnode_p.h | 1 - src/quick/scenegraph/scenegraph.pri | 2 - src/quick/scenegraph/util/qsgdistancefieldutil.cpp | 69 ------------------- src/quick/scenegraph/util/qsgdistancefieldutil_p.h | 79 ---------------------- 14 files changed, 12 insertions(+), 180 deletions(-) delete mode 100644 src/quick/scenegraph/util/qsgdistancefieldutil.cpp delete mode 100644 src/quick/scenegraph/util/qsgdistancefieldutil_p.h (limited to 'src') diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp index 412023564f..f90706affe 100644 --- a/src/quick/scenegraph/qsgadaptationlayer.cpp +++ b/src/quick/scenegraph/qsgadaptationlayer.cpp @@ -40,7 +40,6 @@ #include "qsgadaptationlayer_p.h" #include -#include #include #include #include @@ -57,9 +56,8 @@ static QElapsedTimer qsg_render_timer; QSGDistanceFieldGlyphCache::Texture QSGDistanceFieldGlyphCache::s_emptyTexture; -QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font) - : m_manager(man) - , m_pendingGlyphs(64) +QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QOpenGLContext *c, const QRawFont &font) + : m_pendingGlyphs(64) { Q_ASSERT(font.isValid()); diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h index a8e35b1ac1..ba146b884f 100644 --- a/src/quick/scenegraph/qsgadaptationlayer_p.h +++ b/src/quick/scenegraph/qsgadaptationlayer_p.h @@ -73,7 +73,6 @@ QT_BEGIN_NAMESPACE class QSGNode; class QImage; class TextureReference; -class QSGDistanceFieldGlyphCacheManager; class QSGDistanceFieldGlyphNode; class QOpenGLContext; class QSGInternalImageNode; @@ -409,7 +408,7 @@ public: class Q_QUICK_PRIVATE_EXPORT QSGDistanceFieldGlyphCache { public: - QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font); + QSGDistanceFieldGlyphCache(QOpenGLContext *c, const QRawFont &font); virtual ~QSGDistanceFieldGlyphCache(); struct Metrics { @@ -443,8 +442,6 @@ public: bool operator == (const Texture &other) const { return textureId == other.textureId; } }; - const QSGDistanceFieldGlyphCacheManager *manager() const { return m_manager; } - const QRawFont &referenceFont() const { return m_referenceFont; } qreal fontScale(qreal pixelSize) const @@ -514,8 +511,6 @@ protected: inline bool isCoreProfile() const { return m_coreProfile; } private: - QSGDistanceFieldGlyphCacheManager *m_manager; - QRawFont m_referenceFont; int m_glyphCount; diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index d52f69c7a3..ff2379ecb5 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -333,7 +333,6 @@ QSGRendererInterface *QSGContext::rendererInterface(QSGRenderContext *renderCont QSGRenderContext::QSGRenderContext(QSGContext *context) : m_sg(context) - , m_distanceFieldCacheManager(0) { } diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index 2f5d5790ee..bd10453131 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -78,7 +78,6 @@ class QSGMaterial; class QSGRenderLoop; class QSGLayer; class QQuickTextureFactory; -class QSGDistanceFieldGlyphCacheManager; class QSGContext; class QQuickPaintedItem; class QSGRendererInterface; @@ -194,7 +193,7 @@ protected: QMutex m_mutex; QHash m_textures; QSet m_texturesToDelete; - QSGDistanceFieldGlyphCacheManager *m_distanceFieldCacheManager; + QHash m_glyphCaches; QSet m_fontEnginesToClean; }; diff --git a/src/quick/scenegraph/qsgdefaultcontext.cpp b/src/quick/scenegraph/qsgdefaultcontext.cpp index d31a7025e5..be5fec9dab 100644 --- a/src/quick/scenegraph/qsgdefaultcontext.cpp +++ b/src/quick/scenegraph/qsgdefaultcontext.cpp @@ -39,7 +39,6 @@ #include "qsgdefaultcontext_p.h" -#include #include #include #include diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp index f0a336e229..ba25172d2f 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -60,8 +59,8 @@ DEFINE_BOOL_CONFIG_OPTION(qsgPreferFullSizeGlyphCacheTextures, QSG_PREFER_FULLSI # define QSG_DEFAULT_DISTANCEFIELD_GLYPH_CACHE_PADDING 2 #endif -QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font) - : QSGDistanceFieldGlyphCache(man, c, font) +QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QOpenGLContext *c, const QRawFont &font) + : QSGDistanceFieldGlyphCache(c, font) , m_maxTextureSize(0) , m_maxTextureCount(3) , m_blitProgram(0) diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h index 57dc4a5d07..fe365495c2 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h @@ -69,7 +69,7 @@ class QOpenGLFunctions_3_2_Core; class Q_QUICK_PRIVATE_EXPORT QSGDefaultDistanceFieldGlyphCache : public QSGDistanceFieldGlyphCache { public: - QSGDefaultDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font); + QSGDefaultDistanceFieldGlyphCache(QOpenGLContext *c, const QRawFont &font); virtual ~QSGDefaultDistanceFieldGlyphCache(); void requestGlyphs(const QSet &glyphs) override; diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp index 2c5b4ff5c8..7542068a53 100644 --- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp +++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp @@ -45,7 +45,6 @@ #include #include #include -#include QT_BEGIN_NAMESPACE @@ -159,8 +158,8 @@ void QSGDefaultRenderContext::invalidate() delete m_depthStencilManager; m_depthStencilManager = 0; - delete m_distanceFieldCacheManager; - m_distanceFieldCacheManager = 0; + qDeleteAll(m_glyphCaches); + m_glyphCaches.clear(); if (m_gl->property(QSG_RENDERCONTEXT_PROPERTY) == QVariant::fromValue(this)) m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant()); @@ -294,13 +293,10 @@ QT_END_NAMESPACE QSGDistanceFieldGlyphCache *QSGDefaultRenderContext::distanceFieldGlyphCache(const QRawFont &font) { - if (!m_distanceFieldCacheManager) - m_distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager; - - QSGDistanceFieldGlyphCache *cache = m_distanceFieldCacheManager->cache(font); + QSGDistanceFieldGlyphCache *cache = m_glyphCaches.value(font, 0); if (!cache) { - cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, openglContext(), font); - m_distanceFieldCacheManager->insertCache(font, cache); + cache = new QSGDefaultDistanceFieldGlyphCache(openglContext(), font); + m_glyphCaches.insert(font, cache); } return cache; diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp index 11c5444cd2..32eda2d142 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp @@ -39,7 +39,6 @@ #include "qsgdistancefieldglyphnode_p.h" #include "qsgdistancefieldglyphnode_p_p.h" -#include #include QT_BEGIN_NAMESPACE diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp index 153f0a45c5..a67c659c99 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp @@ -38,7 +38,6 @@ ****************************************************************************/ #include "qsgdistancefieldglyphnode_p_p.h" -#include #include #include #include diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h index 04446c7b2c..7008f20925 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h @@ -59,7 +59,6 @@ QT_BEGIN_NAMESPACE class QSGRenderContext; -class QSGDistanceFieldGlyphCacheManager; class QSGDistanceFieldTextMaterial; class QSGDistanceFieldGlyphNode: public QSGGlyphNode, public QSGDistanceFieldGlyphConsumer { diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri index 38c3b8dd85..c6db3df158 100644 --- a/src/quick/scenegraph/scenegraph.pri +++ b/src/quick/scenegraph/scenegraph.pri @@ -45,7 +45,6 @@ HEADERS += \ $$PWD/util/qsgtexture.h \ $$PWD/util/qsgtexture_p.h \ $$PWD/util/qsgtextureprovider.h \ - $$PWD/util/qsgdistancefieldutil_p.h \ $$PWD/util/qsgflatcolormaterial.h \ $$PWD/util/qsgsimplematerial.h \ $$PWD/util/qsgtexturematerial.h \ @@ -62,7 +61,6 @@ SOURCES += \ $$PWD/util/qsgsimpletexturenode.cpp \ $$PWD/util/qsgtexture.cpp \ $$PWD/util/qsgtextureprovider.cpp \ - $$PWD/util/qsgdistancefieldutil.cpp \ $$PWD/util/qsgflatcolormaterial.cpp \ $$PWD/util/qsgsimplematerial.cpp \ $$PWD/util/qsgtexturematerial.cpp \ diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp deleted file mode 100644 index 97a5853bd6..0000000000 --- a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQuick 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 "qsgdistancefieldutil_p.h" - -#include -#if QT_CONFIG(opengl) -# include -#endif -#include - -QT_BEGIN_NAMESPACE - -QSGDistanceFieldGlyphCacheManager::QSGDistanceFieldGlyphCacheManager() -{ -} - -QSGDistanceFieldGlyphCacheManager::~QSGDistanceFieldGlyphCacheManager() -{ - qDeleteAll(m_caches); -} - -QSGDistanceFieldGlyphCache *QSGDistanceFieldGlyphCacheManager::cache(const QRawFont &font) -{ - return m_caches.value(font, 0); -} - -void QSGDistanceFieldGlyphCacheManager::insertCache(const QRawFont &font, QSGDistanceFieldGlyphCache *cache) -{ - m_caches.insert(font, cache); -} - -QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h b/src/quick/scenegraph/util/qsgdistancefieldutil_p.h deleted file mode 100644 index 78e7ce15cd..0000000000 --- a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQuick 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 QSGDISTANCEFIELDUTIL_H -#define QSGDISTANCEFIELDUTIL_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QOpenGLShaderProgram; -class QSGDistanceFieldGlyphCache; -class QSGContext; - -class Q_QUICK_PRIVATE_EXPORT QSGDistanceFieldGlyphCacheManager -{ -public: - QSGDistanceFieldGlyphCacheManager(); - ~QSGDistanceFieldGlyphCacheManager(); - - QSGDistanceFieldGlyphCache *cache(const QRawFont &font); - void insertCache(const QRawFont &font, QSGDistanceFieldGlyphCache *cache); - -private: - QHash m_caches; -}; - -QT_END_NAMESPACE - -#endif // QSGDISTANCEFIELDUTIL_H -- cgit v1.2.3 From fc0254a48c775cdfea693402d0472b73c8b940e5 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 15 Mar 2017 16:26:02 +0100 Subject: Simplify internal source access API All call sites of QQmlDataBlob::Data immediately convert the data to UTf-8 - for .qml, .js and qmldir files. We can simplify the code by reflecting that in the API and that also opens up the possibility for future optimizations. This means that the bi-pointer has to go, but at the moment the Data object is stack-allocated anyway. Since the "Data" class always represents source code, it is now called SourceCodeData. Change-Id: Icd262ed1e35f9edd64945ba6c16d80f9917eae72 Reviewed-by: Lars Knoll --- src/qml/qml/qqmltypeloader.cpp | 40 ++++++++++++++++++++-------------------- src/qml/qml/qqmltypeloader_p.h | 27 ++++++++++----------------- 2 files changed, 30 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 372b05eeef..193239e680 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1245,20 +1245,22 @@ void QQmlTypeLoader::initializeEngine(QQmlExtensionInterface *iface, void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data) { QML_MEMORY_SCOPE_URL(blob->url()); - QQmlDataBlob::Data d; - d.d = &data; + QQmlDataBlob::SourceCodeData d; + d.inlineSourceCodeOrFileName = QString::fromUtf8(data); + d.sourceCodeAvailable = true; setData(blob, d); } void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName) { QML_MEMORY_SCOPE_URL(blob->url()); - QQmlDataBlob::Data d; - d.d = &fileName; + QQmlDataBlob::SourceCodeData d; + d.inlineSourceCodeOrFileName = fileName; + d.sourceCodeAvailable = false; setData(blob, d); } -void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d) +void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeData &d) { QML_MEMORY_SCOPE_URL(blob->url()); QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob); @@ -2342,7 +2344,7 @@ bool QQmlTypeData::loadImplicitImport() return true; } -void QQmlTypeData::dataReceived(const Data &data) +void QQmlTypeData::dataReceived(const SourceCodeData &data) { QString error; m_backupSourceCode = data.readAll(&error, &m_sourceTimeStamp); @@ -2376,12 +2378,11 @@ void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *un bool QQmlTypeData::loadFromSource() { - QString code = QString::fromUtf8(m_backupSourceCode); m_document.reset(new QmlIR::Document(isDebugging())); m_document->jsModule.sourceTimeStamp = m_sourceTimeStamp; QQmlEngine *qmlEngine = typeLoader()->engine(); QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames()); - if (!compiler.generateFromQml(code, finalUrlString(), m_document.data())) { + if (!compiler.generateFromQml(m_backupSourceCode, finalUrlString(), m_document.data())) { QList errors; errors.reserve(compiler.errors.count()); for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) { @@ -2872,7 +2873,7 @@ struct EmptyCompilationUnit : public QV4::CompiledData::CompilationUnit void linkBackendToEngine(QV4::ExecutionEngine *) override {} }; -void QQmlScriptBlob::dataReceived(const Data &data) +void QQmlScriptBlob::dataReceived(const SourceCodeData &data) { QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine()); @@ -2891,7 +2892,7 @@ void QQmlScriptBlob::dataReceived(const Data &data) QmlIR::Document irUnit(isDebugging()); QString error; - QString source = QString::fromUtf8(data.readAll(&error, &irUnit.jsModule.sourceTimeStamp)); + QString source = data.readAll(&error, &irUnit.jsModule.sourceTimeStamp); if (!error.isEmpty()) { setError(error); return; @@ -3055,10 +3056,10 @@ void QQmlQmldirData::setPriority(int priority) m_priority = priority; } -void QQmlQmldirData::dataReceived(const Data &data) +void QQmlQmldirData::dataReceived(const SourceCodeData &data) { QString error; - m_content = QString::fromUtf8(data.readAll(&error)); + m_content = data.readAll(&error); if (!error.isEmpty()) { setError(error); return; @@ -3070,19 +3071,18 @@ void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit * Q_UNIMPLEMENTED(); } -QByteArray QQmlDataBlob::Data::readAll(QString *error, qint64 *sourceTimeStamp) const +QString QQmlDataBlob::SourceCodeData::readAll(QString *error, qint64 *sourceTimeStamp) const { - Q_ASSERT(!d.isNull()); error->clear(); - if (d.isT1()) { + if (sourceCodeAvailable) { if (sourceTimeStamp) *sourceTimeStamp = 0; - return *d.asT1(); + return inlineSourceCodeOrFileName; } - QFile f(*d.asT2()); + QFile f(inlineSourceCodeOrFileName); if (!f.open(QIODevice::ReadOnly)) { *error = f.errorString(); - return QByteArray(); + return QString(); } if (sourceTimeStamp) { QDateTime timeStamp = QFileInfo(f).lastModified(); @@ -3095,9 +3095,9 @@ QByteArray QQmlDataBlob::Data::readAll(QString *error, qint64 *sourceTimeStamp) QByteArray data(f.size(), Qt::Uninitialized); if (f.read(data.data(), data.length()) != data.length()) { *error = f.errorString(); - return QByteArray(); + return QString(); } - return data; + return QString::fromUtf8(data); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 915b1bcc4c..c1b3548fa6 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -130,16 +130,14 @@ public: QList errors() const; - class Data { + class SourceCodeData { public: - QByteArray readAll(QString *error, qint64 *sourceTimeStamp = 0) const; + QString readAll(QString *error, qint64 *sourceTimeStamp = 0) const; private: friend class QQmlDataBlob; friend class QQmlTypeLoader; - inline Data(); - Data(const Data &); - Data &operator=(const Data &); - QBiPointer d; + QString inlineSourceCodeOrFileName; + bool sourceCodeAvailable = false; }; protected: @@ -152,7 +150,7 @@ protected: void addDependency(QQmlDataBlob *); // Callbacks made in load thread - virtual void dataReceived(const Data &) = 0; + virtual void dataReceived(const SourceCodeData &) = 0; virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit*) = 0; virtual void done(); #if QT_CONFIG(qml_network) @@ -339,7 +337,7 @@ private: void setData(QQmlDataBlob *, const QByteArray &); void setData(QQmlDataBlob *, const QString &fileName); - void setData(QQmlDataBlob *, const QQmlDataBlob::Data &); + void setData(QQmlDataBlob *, const QQmlDataBlob::SourceCodeData &); void setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit); template @@ -436,7 +434,7 @@ public: protected: void done() override; void completed() override; - void dataReceived(const Data &) override; + void dataReceived(const SourceCodeData &) override; void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) override; void allDependenciesDone() override; void downloadProgressChanged(qreal) override; @@ -463,7 +461,7 @@ private: qint64 m_sourceTimeStamp = 0; - QByteArray m_backupSourceCode; // used when cache verification fails. + QString m_backupSourceCode; // used when cache verification fails. QScopedPointer m_document; QV4::CompiledData::TypeReferenceMap m_typeReferences; @@ -547,7 +545,7 @@ public: QQmlScriptData *scriptData() const; protected: - void dataReceived(const Data &) override; + void dataReceived(const SourceCodeData &) override; void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) override; void done() override; @@ -578,7 +576,7 @@ public: void setPriority(int); protected: - void dataReceived(const Data &) override; + void dataReceived(const SourceCodeData &) override; void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit*) override; private: @@ -587,11 +585,6 @@ private: int m_priority; }; -QQmlDataBlob::Data::Data() -{ -} - - QT_END_NAMESPACE -- cgit v1.2.3 From 5ce2235f425b3c5047faf709c87c9b5c8e414b8b Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 15 Mar 2017 16:52:10 +0100 Subject: Avoid reading (not parsing) .qml files when using the cache By making SourceCodeData copyable we can delay the reading of the source file until we really need to. This also allows persisting the QFileInfo object and therefore having only one stat() call to check if the file exists, what its size is and what the last modification time is. Change-Id: Ic7e4d5f566d870f3b1fa8302227417fa813cb139 Reviewed-by: Lars Knoll --- src/qml/qml/qqmltypeloader.cpp | 78 +++++++++++++++++++++++++----------------- src/qml/qml/qqmltypeloader_p.h | 12 ++++--- 2 files changed, 54 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 193239e680..c5d4945bf1 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1246,8 +1246,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data) { QML_MEMORY_SCOPE_URL(blob->url()); QQmlDataBlob::SourceCodeData d; - d.inlineSourceCodeOrFileName = QString::fromUtf8(data); - d.sourceCodeAvailable = true; + d.inlineSourceCode = QString::fromUtf8(data); setData(blob, d); } @@ -1255,8 +1254,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName) { QML_MEMORY_SCOPE_URL(blob->url()); QQmlDataBlob::SourceCodeData d; - d.inlineSourceCodeOrFileName = fileName; - d.sourceCodeAvailable = false; + d.fileInfo = QFileInfo(fileName); setData(blob, d); } @@ -2237,7 +2235,7 @@ void QQmlTypeData::done() qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->url().toString(); if (!loadFromSource()) return; - m_backupSourceCode.clear(); + m_backupSourceCode = SourceCodeData(); m_compiledData = nullptr; } @@ -2346,11 +2344,7 @@ bool QQmlTypeData::loadImplicitImport() void QQmlTypeData::dataReceived(const SourceCodeData &data) { - QString error; - m_backupSourceCode = data.readAll(&error, &m_sourceTimeStamp); - // if we failed to read the source code, process it _after_ we've tried - // to use the disk cache, in order to support scenarios where the source - // was removed deliberately. + m_backupSourceCode = data; if (tryLoadFromDiskCache()) return; @@ -2358,8 +2352,8 @@ void QQmlTypeData::dataReceived(const SourceCodeData &data) if (isError()) return; - if (!error.isEmpty()) { - setError(error); + if (!m_backupSourceCode.exists()) { + setError(QQmlTypeLoader::tr("No such file or directory")); return; } @@ -2379,10 +2373,18 @@ void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *un bool QQmlTypeData::loadFromSource() { m_document.reset(new QmlIR::Document(isDebugging())); - m_document->jsModule.sourceTimeStamp = m_sourceTimeStamp; + m_document->jsModule.sourceTimeStamp = m_backupSourceCode.sourceTimeStamp(); QQmlEngine *qmlEngine = typeLoader()->engine(); QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames()); - if (!compiler.generateFromQml(m_backupSourceCode, finalUrlString(), m_document.data())) { + + QString sourceError; + const QString source = m_backupSourceCode.readAll(&sourceError); + if (!sourceError.isEmpty()) { + setError(sourceError); + return false; + } + + if (!compiler.generateFromQml(source, finalUrlString(), m_document.data())) { QList errors; errors.reserve(compiler.errors.count()); for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) { @@ -2891,8 +2893,9 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) QmlIR::Document irUnit(isDebugging()); + irUnit.jsModule.sourceTimeStamp = data.sourceTimeStamp(); QString error; - QString source = data.readAll(&error, &irUnit.jsModule.sourceTimeStamp); + QString source = data.readAll(&error); if (!error.isEmpty()) { setError(error); return; @@ -3071,28 +3074,19 @@ void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit * Q_UNIMPLEMENTED(); } -QString QQmlDataBlob::SourceCodeData::readAll(QString *error, qint64 *sourceTimeStamp) const +QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const { error->clear(); - if (sourceCodeAvailable) { - if (sourceTimeStamp) - *sourceTimeStamp = 0; - return inlineSourceCodeOrFileName; - } - QFile f(inlineSourceCodeOrFileName); + if (!inlineSourceCode.isEmpty()) + return inlineSourceCode; + + QFile f(fileInfo.absoluteFilePath()); if (!f.open(QIODevice::ReadOnly)) { *error = f.errorString(); return QString(); } - if (sourceTimeStamp) { - QDateTime timeStamp = QFileInfo(f).lastModified(); - // Files from the resource system do not have any time stamps, so fall back to the application - // executable. - if (!timeStamp.isValid()) - timeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified(); - *sourceTimeStamp = timeStamp.toMSecsSinceEpoch(); - } - QByteArray data(f.size(), Qt::Uninitialized); + + QByteArray data(fileInfo.size(), Qt::Uninitialized); if (f.read(data.data(), data.length()) != data.length()) { *error = f.errorString(); return QString(); @@ -3100,6 +3094,28 @@ QString QQmlDataBlob::SourceCodeData::readAll(QString *error, qint64 *sourceTime return QString::fromUtf8(data); } +qint64 QQmlDataBlob::SourceCodeData::sourceTimeStamp() const +{ + if (!inlineSourceCode.isEmpty()) + return 0; + + QDateTime timeStamp = fileInfo.lastModified(); + if (timeStamp.isValid()) + return timeStamp.toMSecsSinceEpoch(); + + static qint64 appTimeStamp = 0; + if (appTimeStamp == 0) + appTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified().toMSecsSinceEpoch(); + return appTimeStamp; +} + +bool QQmlDataBlob::SourceCodeData::exists() const +{ + if (!inlineSourceCode.isEmpty()) + return true; + return fileInfo.exists(); +} + QT_END_NAMESPACE #include "qqmltypeloader.moc" diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index c1b3548fa6..0bae857874 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -54,6 +54,7 @@ #include #include #include +#include #if QT_CONFIG(qml_network) #include #endif @@ -132,12 +133,14 @@ public: class SourceCodeData { public: - QString readAll(QString *error, qint64 *sourceTimeStamp = 0) const; + QString readAll(QString *error) const; + qint64 sourceTimeStamp() const; + bool exists() const; private: friend class QQmlDataBlob; friend class QQmlTypeLoader; - QString inlineSourceCodeOrFileName; - bool sourceCodeAvailable = false; + QString inlineSourceCode; + QFileInfo fileInfo; }; protected: @@ -460,8 +463,7 @@ private: void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override; - qint64 m_sourceTimeStamp = 0; - QString m_backupSourceCode; // used when cache verification fails. + SourceCodeData m_backupSourceCode; // used when cache verification fails. QScopedPointer m_document; QV4::CompiledData::TypeReferenceMap m_typeReferences; -- cgit v1.2.3 From 12569460e765ea01935ab60e06b5a5acf770ebe7 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Mon, 20 Mar 2017 22:26:44 +0100 Subject: QSGOpenVGLayer: Fix compilation Amends 48c31733383d14447d1c383cefca9ca40daa6a87. Change-Id: I9b30af689eaa9ca686b8ec2d034866eb4671ec95 Reviewed-by: Andy Nichols --- src/plugins/scenegraph/openvg/qsgopenvglayer.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/plugins/scenegraph/openvg/qsgopenvglayer.h b/src/plugins/scenegraph/openvg/qsgopenvglayer.h index 2af0bfb40f..8deedc3347 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvglayer.h +++ b/src/plugins/scenegraph/openvg/qsgopenvglayer.h @@ -83,6 +83,7 @@ public: void setDevicePixelRatio(qreal ratio) override; void setMirrorHorizontal(bool mirror) override; void setMirrorVertical(bool mirror) override; + void setSamples(int) override { } public slots: void markDirtyTexture() override; -- cgit v1.2.3 From 9b7071637415bdad82bf61caf21603963f7fe21a Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 21 Mar 2017 14:49:10 +0100 Subject: Fix handling of huge memory segments Allocating a MemorySegment larger than 4M was not working correctly. We would in this case reserve the right amount of memory, but where not able to use it, leading to an assertion in the HugeItemAllocator. Fix this by ensuring we can properly allocate the memory that was reserved in the Segment. Change-Id: I1e3d2b3beebdde0a509fd123ad2aa8b1bc35a26b Reviewed-by: Simon Hausmann --- src/qml/memory/qv4mm.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index a829e902fb..27adfcb517 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -113,14 +113,16 @@ struct MemorySegment { pageReservation = PageReservation::reserve(size, OSAllocator::JSGCHeapPages); base = reinterpret_cast((reinterpret_cast(pageReservation.base()) + Chunk::ChunkSize - 1) & ~(Chunk::ChunkSize - 1)); nChunks = NumChunks; - if (base != pageReservation.base()) + availableBytes = size - (reinterpret_cast(base) - reinterpret_cast(pageReservation.base())); + if (availableBytes < SegmentSize) --nChunks; } MemorySegment(MemorySegment &&other) { qSwap(pageReservation, other.pageReservation); qSwap(base, other.base); - qSwap(nChunks, other.nChunks); qSwap(allocatedMap, other.allocatedMap); + qSwap(availableBytes, other.availableBytes); + qSwap(nChunks, other.nChunks); } ~MemorySegment() { @@ -150,7 +152,7 @@ struct MemorySegment { void free(Chunk *chunk, size_t size) { DEBUG << "freeing chunk" << chunk; size_t index = static_cast(chunk - base); - size_t end = index + (size - 1)/Chunk::ChunkSize + 1; + size_t end = qMin(static_cast(NumChunks), index + (size - 1)/Chunk::ChunkSize + 1); while (index < end) { Q_ASSERT(testBit(index)); clearBit(index); @@ -169,11 +171,19 @@ struct MemorySegment { PageReservation pageReservation; Chunk *base = 0; quint64 allocatedMap = 0; + size_t availableBytes = 0; uint nChunks = 0; }; Chunk *MemorySegment::allocate(size_t size) { + if (!allocatedMap && size >= SegmentSize) { + // chunk allocated for one huge allocation + Q_ASSERT(availableBytes >= size); + pageReservation.commit(base, size); + allocatedMap = ~static_cast(0); + return base; + } size_t requiredChunks = (size + sizeof(Chunk) - 1)/sizeof(Chunk); uint sequence = 0; Chunk *candidate = 0; -- cgit v1.2.3 From 5bd11b5a8c2f627bc9c9f1b6c02602772ad67dae Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 16 Mar 2017 09:44:50 +0100 Subject: Avoid an extra stat() on the source .qml file when loading cache For timestamp comparison it is not necessary to create another QFileInfo() object and call exists() and lastModified(), when we can pass that information through from the type loader. Change-Id: I225cd36e672f1f390bddb4e6ebfafa3fc1269795 Reviewed-by: Lars Knoll --- src/qml/compiler/qv4compilationunitmapper.cpp | 7 +------ src/qml/compiler/qv4compilationunitmapper_p.h | 4 ++-- src/qml/compiler/qv4compilationunitmapper_unix.cpp | 5 +++-- src/qml/compiler/qv4compilationunitmapper_win.cpp | 4 ++-- src/qml/compiler/qv4compileddata.cpp | 4 ++-- src/qml/compiler/qv4compileddata_p.h | 2 +- src/qml/compiler/qv4compiler.cpp | 2 +- src/qml/compiler/qv4jsir_p.h | 4 ++-- src/qml/qml/qqmltypeloader.cpp | 18 +++++++++--------- src/qml/qml/qqmltypeloader_p.h | 2 +- 10 files changed, 24 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compilationunitmapper.cpp b/src/qml/compiler/qv4compilationunitmapper.cpp index 1ae0fb190c..d94f7ac238 100644 --- a/src/qml/compiler/qv4compilationunitmapper.cpp +++ b/src/qml/compiler/qv4compilationunitmapper.cpp @@ -59,7 +59,7 @@ CompilationUnitMapper::~CompilationUnitMapper() close(); } -bool CompilationUnitMapper::verifyHeader(const CompiledData::Unit *header, const QString &sourcePath, QString *errorString) +bool CompilationUnitMapper::verifyHeader(const CompiledData::Unit *header, QDateTime sourceTimeStamp, QString *errorString) { if (strncmp(header->magic, CompiledData::magic_str, sizeof(header->magic))) { *errorString = QStringLiteral("Magic bytes in the header do not match"); @@ -77,11 +77,6 @@ bool CompilationUnitMapper::verifyHeader(const CompiledData::Unit *header, const } if (header->sourceTimeStamp) { - QFileInfo sourceCode(sourcePath); - QDateTime sourceTimeStamp; - if (sourceCode.exists()) - sourceTimeStamp = sourceCode.lastModified(); - // Files from the resource system do not have any time stamps, so fall back to the application // executable. if (!sourceTimeStamp.isValid()) diff --git a/src/qml/compiler/qv4compilationunitmapper_p.h b/src/qml/compiler/qv4compilationunitmapper_p.h index 5b6939f1cf..b24f98df7c 100644 --- a/src/qml/compiler/qv4compilationunitmapper_p.h +++ b/src/qml/compiler/qv4compilationunitmapper_p.h @@ -68,11 +68,11 @@ public: CompilationUnitMapper(); ~CompilationUnitMapper(); - CompiledData::Unit *open(const QString &cacheFilePath, const QString &sourcePath, QString *errorString); + CompiledData::Unit *open(const QString &cacheFilePath, const QDateTime &sourceTimeStamp, QString *errorString); void close(); private: - static bool verifyHeader(const QV4::CompiledData::Unit *header, const QString &sourcePath, QString *errorString); + static bool verifyHeader(const QV4::CompiledData::Unit *header, QDateTime sourceTimeStamp, QString *errorString); #if defined(Q_OS_UNIX) size_t length; diff --git a/src/qml/compiler/qv4compilationunitmapper_unix.cpp b/src/qml/compiler/qv4compilationunitmapper_unix.cpp index 1aa3e05f5f..38dabc41cf 100644 --- a/src/qml/compiler/qv4compilationunitmapper_unix.cpp +++ b/src/qml/compiler/qv4compilationunitmapper_unix.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include "qv4compileddata_p.h" @@ -50,7 +51,7 @@ QT_BEGIN_NAMESPACE using namespace QV4; -CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QString &sourcePath, QString *errorString) +CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QDateTime &sourceTimeStamp, QString *errorString) { close(); @@ -72,7 +73,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co return nullptr; } - if (!verifyHeader(&header, sourcePath, errorString)) + if (!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/compiler/qv4compilationunitmapper_win.cpp b/src/qml/compiler/qv4compilationunitmapper_win.cpp index 37cac846a0..d7a93ae233 100644 --- a/src/qml/compiler/qv4compilationunitmapper_win.cpp +++ b/src/qml/compiler/qv4compilationunitmapper_win.cpp @@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE using namespace QV4; -CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QString &sourcePath, QString *errorString) +CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QDateTime &sourceTimeStamp, QString *errorString) { close(); @@ -87,7 +87,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co return nullptr; } - if (!verifyHeader(&header, sourcePath, errorString)) + if (!verifyHeader(&header, sourceTimeStamp, errorString)) return nullptr; const uint mappingFlags = header.flags & QV4::CompiledData::Unit::ContainsMachineCode diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 4688f936cc..1805ab3f54 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -343,7 +343,7 @@ bool CompilationUnit::verifyChecksum(QQmlEngine *engine, sizeof(data->dependencyMD5Checksum)) == 0; } -bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString) +bool CompilationUnit::loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, EvalISelFactory *iselFactory, QString *errorString) { if (!QQmlFile::isLocalFile(url)) { *errorString = QStringLiteral("File has to be a local file."); @@ -353,7 +353,7 @@ bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url); QScopedPointer cacheFile(new CompilationUnitMapper()); - CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourcePath, errorString); + CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourceTimeStamp, errorString); if (!mappedUnit) return false; diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 6d219b85aa..8cf5437928 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -899,7 +899,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase, public void destroy() Q_DECL_OVERRIDE; - bool loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString); + bool loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, EvalISelFactory *iselFactory, QString *errorString); protected: virtual void linkBackendToEngine(QV4::ExecutionEngine *engine) = 0; diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 9cfac4a676..64f034ddcb 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -425,7 +425,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp } unit.indexOfRootFunction = -1; unit.sourceFileIndex = getStringId(irModule->fileName); - unit.sourceTimeStamp = irModule->sourceTimeStamp; + unit.sourceTimeStamp = irModule->sourceTimeStamp.isValid() ? irModule->sourceTimeStamp.toMSecsSinceEpoch() : 0; unit.nImports = 0; unit.offsetToImports = 0; unit.nObjects = 0; diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 23ebe0c962..d9192c1a3b 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -61,6 +61,7 @@ #include #include #include +#include #include #if defined(CONST) && defined(Q_OS_WIN) @@ -942,7 +943,7 @@ struct Q_QML_PRIVATE_EXPORT Module { QVector functions; Function *rootFunction; QString fileName; - qint64 sourceTimeStamp; + QDateTime sourceTimeStamp; bool isQmlModule; // implies rootFunction is always 0 uint unitFlags; // flags merged into CompiledData::Unit::flags #ifdef QT_NO_QML_DEBUGGER @@ -955,7 +956,6 @@ struct Q_QML_PRIVATE_EXPORT Module { Module(bool debugMode) : rootFunction(0) - , sourceTimeStamp(0) , isQmlModule(false) , unitFlags(0) #ifndef QT_NO_QML_DEBUGGER diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index c5d4945bf1..9526615c0d 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2065,7 +2065,7 @@ bool QQmlTypeData::tryLoadFromDiskCache() QQmlRefPointer unit = v4->iselFactory->createUnitForLoading(); { QString error; - if (!unit->loadFromDisk(url(), v4->iselFactory.data(), &error)) { + if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), v4->iselFactory.data(), &error)) { qCDebug(DBG_DISK_CACHE) << "Error loading" << url().toString() << "from disk cache:" << error; return false; } @@ -2522,7 +2522,7 @@ void QQmlTypeData::compile(const QQmlRefPointer &typeNameCach QString errorString; if (m_compiledData->saveToDisk(url(), &errorString)) { QString error; - if (!m_compiledData->loadFromDisk(url(), enginePrivate->v4engine()->iselFactory.data(), &error)) { + if (!m_compiledData->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), enginePrivate->v4engine()->iselFactory.data(), &error)) { // ignore error, keep using the in-memory compilation unit. } } else { @@ -2882,7 +2882,7 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) if (!disableDiskCache() || forceDiskCache()) { QQmlRefPointer unit = v4->iselFactory->createUnitForLoading(); QString error; - if (unit->loadFromDisk(url(), v4->iselFactory.data(), &error)) { + if (unit->loadFromDisk(url(), data.sourceTimeStamp(), v4->iselFactory.data(), &error)) { initializeFromCompilationUnit(unit); return; } else { @@ -3094,18 +3094,18 @@ QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const return QString::fromUtf8(data); } -qint64 QQmlDataBlob::SourceCodeData::sourceTimeStamp() const +QDateTime QQmlDataBlob::SourceCodeData::sourceTimeStamp() const { if (!inlineSourceCode.isEmpty()) - return 0; + return QDateTime(); QDateTime timeStamp = fileInfo.lastModified(); if (timeStamp.isValid()) - return timeStamp.toMSecsSinceEpoch(); + return timeStamp; - static qint64 appTimeStamp = 0; - if (appTimeStamp == 0) - appTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified().toMSecsSinceEpoch(); + static QDateTime appTimeStamp; + if (!appTimeStamp.isValid()) + appTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified(); return appTimeStamp; } diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 0bae857874..1bd2c7f1e1 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -134,7 +134,7 @@ public: class SourceCodeData { public: QString readAll(QString *error) const; - qint64 sourceTimeStamp() const; + QDateTime sourceTimeStamp() const; bool exists() const; private: friend class QQmlDataBlob; -- cgit v1.2.3 From 110f69ab8168950be74779b635d46ef83553d71a Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 16 Mar 2017 10:02:24 +0100 Subject: Speed up source code reading Since we always convert the source code of .qml/.js/qmldir files from utf-8 to utf-16, we always end up copying bytes around. That means instead of allocating memory on the C++ heap and copying bytes from kernel space to user space and then a few times through QIODevice buffers until we reach QString::fromUtf8, we might as well mmap() the file directly - if possible. Change-Id: I54c88d4d9f03f9967130d65a7b53cfec93734018 Reviewed-by: Lars Knoll --- src/qml/qml/qqmltypeloader.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 9526615c0d..eedb649ef6 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -3086,7 +3086,15 @@ QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const return QString(); } - QByteArray data(fileInfo.size(), Qt::Uninitialized); + const qint64 fileSize = fileInfo.size(); + + if (uchar *mappedData = f.map(0, fileSize)) { + QString source = QString::fromUtf8(reinterpret_cast(mappedData), fileSize); + f.unmap(mappedData); + return source; + } + + QByteArray data(fileSize, Qt::Uninitialized); if (f.read(data.data(), data.length()) != data.length()) { *error = f.errorString(); return QString(); -- cgit v1.2.3 From 047af776233d39905e8ad2b8411fcf6d3cf0d22f Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 22 Mar 2017 11:49:14 +0100 Subject: Codegen: do not assume QStringRef(const QString *) is implicit It won't be for very much longer. Change-Id: I90fae21b621f104053b776296fc9f6525e8baf52 Reviewed-by: Lars Knoll --- src/qml/compiler/qv4codegen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 2c1b5c57cc..a10c0730bf 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1485,7 +1485,7 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col) IR::Function *f = _function; while (f && e->parent) { - if (f->insideWithOrCatch || (f->isNamedExpression && f->name == name)) + if (f->insideWithOrCatch || (f->isNamedExpression && QStringRef(f->name) == name)) return _block->NAME(name, line, col); int index = e->findMember(name); @@ -1496,7 +1496,7 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col) al->isArgumentsOrEval = true; return al; } - const int argIdx = f->indexOfArgument(&name); + const int argIdx = f->indexOfArgument(QStringRef(&name)); if (argIdx != -1) return _block->ARG(argIdx, scope); -- cgit v1.2.3 From c021e4b412e1e2977f4c7cf390cee4699b80e67e Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Mon, 13 Mar 2017 12:09:13 +0100 Subject: Build fix for configure -no-opengl Change-Id: I21f111a04d9e2ce367d7677dbb48abbd591a4e71 Reviewed-by: Shawn Rutledge Reviewed-by: Joni Poikelin Reviewed-by: Lars Knoll --- src/quick/items/qquickshadereffect.cpp | 2 ++ src/quick/items/qquickshadereffect_p.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'src') diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp index 436d7b33ce..d317c1d19b 100644 --- a/src/quick/items/qquickshadereffect.cpp +++ b/src/quick/items/qquickshadereffect.cpp @@ -873,9 +873,11 @@ void QQuickShaderEffectPrivate::updatePolish() q->m_impl->maybeUpdateShaders(); } +#if QT_CONFIG(opengl) bool QQuickShaderEffect::isOpenGLShaderEffect() const { return m_glImpl != Q_NULLPTR; } +#endif QT_END_NAMESPACE diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h index d269dc5e50..30bd018098 100644 --- a/src/quick/items/qquickshadereffect_p.h +++ b/src/quick/items/qquickshadereffect_p.h @@ -117,7 +117,9 @@ public: bool isComponentComplete() const; QString parseLog(); +#if QT_CONFIG(opengl) bool isOpenGLShaderEffect() const; +#endif Q_SIGNALS: void fragmentShaderChanged(); -- cgit v1.2.3 From 8f5366aed675ce7928448be2f6d739d0548b350e Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Mon, 13 Mar 2017 12:33:49 +0100 Subject: Build for for -no-feature-quick-sprite Change-Id: Iaf26d9cec7f9fa7a5d6d24c729b2dc92737cca1f Reviewed-by: Andy Nichols --- src/plugins/scenegraph/openvg/openvg.pro | 7 +++++-- src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp | 5 ++++- src/plugins/scenegraph/openvg/qsgopenvgcontext_p.h | 2 ++ src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp | 4 ++++ src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h | 2 ++ src/plugins/scenegraph/openvg/qsgopenvgspritenode.h | 2 ++ 6 files changed, 19 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/plugins/scenegraph/openvg/openvg.pro b/src/plugins/scenegraph/openvg/openvg.pro index 6d5b190b37..43c2636343 100644 --- a/src/plugins/scenegraph/openvg/openvg.pro +++ b/src/plugins/scenegraph/openvg/openvg.pro @@ -31,7 +31,6 @@ HEADERS += \ qsgopenvghelpers.h \ qsgopenvgfontglyphcache.h \ qsgopenvgpainternode.h \ - qsgopenvgspritenode.h \ qsgopenvgrenderable.h \ qopenvgoffscreensurface.h @@ -52,6 +51,10 @@ SOURCES += \ qsgopenvghelpers.cpp \ qsgopenvgfontglyphcache.cpp \ qsgopenvgpainternode.cpp \ - qsgopenvgspritenode.cpp \ qsgopenvgrenderable.cpp \ qopenvgoffscreensurface.cpp + +qtConfig(quick-sprite) { + HEADERS += qsgopenvgspritenode.h + SOURCES += qsgopenvgspritenode.cpp +} diff --git a/src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp b/src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp index 41fce7c7fc..76ebb7c4ee 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp +++ b/src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp @@ -45,7 +45,9 @@ #include "qsgopenvgglyphnode_p.h" #include "qsgopenvgfontglyphcache.h" #include "qsgopenvgpainternode.h" +#if QT_CONFIG(quick_sprite) #include "qsgopenvgspritenode.h" +#endif #include "qopenvgcontext_p.h" @@ -171,11 +173,12 @@ int QSGOpenVGRenderContext::maxTextureSize() const return qMin(width, height); } - +#if QT_CONFIG(quick_sprite) QSGSpriteNode *QSGOpenVGContext::createSpriteNode() { return new QSGOpenVGSpriteNode(); } +#endif QSGRendererInterface *QSGOpenVGContext::rendererInterface(QSGRenderContext *renderContext) { diff --git a/src/plugins/scenegraph/openvg/qsgopenvgcontext_p.h b/src/plugins/scenegraph/openvg/qsgopenvgcontext_p.h index fa9939a253..31a1e8643f 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvgcontext_p.h +++ b/src/plugins/scenegraph/openvg/qsgopenvgcontext_p.h @@ -95,7 +95,9 @@ public: QSurfaceFormat defaultSurfaceFormat() const override; QSGInternalRectangleNode *createInternalRectangleNode() override; QSGInternalImageNode *createInternalImageNode() override; +#if QT_CONFIG(quick_sprite) QSGSpriteNode *createSpriteNode() override; +#endif QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override; }; diff --git a/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp index 8aa179f705..41606c653a 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp +++ b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp @@ -43,7 +43,9 @@ #include "qsgopenvgpublicnodes.h" #include "qsgopenvgglyphnode_p.h" #include "qsgopenvgpainternode.h" +#if QT_CONFIG(quick_sprite) #include "qsgopenvgspritenode.h" +#endif #include "qsgopenvgrenderable.h" #include "qopenvgcontext_p.h" @@ -209,6 +211,7 @@ void QSGOpenVGNodeVisitor::endVisit(QSGRootNode *) { } +#if QT_CONFIG(quick_sprite) bool QSGOpenVGNodeVisitor::visit(QSGSpriteNode *node) { renderRenderableNode(static_cast(node)); @@ -218,6 +221,7 @@ bool QSGOpenVGNodeVisitor::visit(QSGSpriteNode *node) void QSGOpenVGNodeVisitor::endVisit(QSGSpriteNode *) { } +#endif bool QSGOpenVGNodeVisitor::visit(QSGRenderNode *) { diff --git a/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h index 4805d63024..c6461ca67d 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h +++ b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h @@ -73,8 +73,10 @@ public: void endVisit(QSGGlyphNode *) override; bool visit(QSGRootNode *) override; void endVisit(QSGRootNode *) override; +#if QT_CONFIG(quick_sprite) bool visit(QSGSpriteNode *) override; void endVisit(QSGSpriteNode *) override; +#endif bool visit(QSGRenderNode *) override; void endVisit(QSGRenderNode *) override; diff --git a/src/plugins/scenegraph/openvg/qsgopenvgspritenode.h b/src/plugins/scenegraph/openvg/qsgopenvgspritenode.h index 3ade2ef8ad..d47b389a0b 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvgspritenode.h +++ b/src/plugins/scenegraph/openvg/qsgopenvgspritenode.h @@ -43,6 +43,8 @@ #include #include "qsgopenvgrenderable.h" +QT_REQUIRE_CONFIG(quick_sprite); + QT_BEGIN_NAMESPACE class QSGOpenVGTexture; class QSGOpenVGSpriteNode : public QSGSpriteNode, public QSGOpenVGRenderable -- cgit v1.2.3 From d1c43e44572f5b554467e5f1c2db4914b549b569 Mon Sep 17 00:00:00 2001 From: Jesus Fernandez Date: Thu, 23 Mar 2017 16:15:46 +0100 Subject: Fix possible loss of data warning warning C4267: '=': conversion from 'size_t' to 'int', possible loss of data Amends merge resolution of 24d0266ee45cf6a3c5b9142453966199702fbf90. Change-Id: I55eca8d853bb957e5b4ea792036aaa0b2f122b38 Reviewed-by: Friedemann Kleint Reviewed-by: Simon Hausmann --- src/qml/memory/qv4mm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 180371c088..c025dd09a4 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -733,7 +733,7 @@ MemoryManager::MemoryManager(ExecutionEngine *engine) #ifdef MM_STATS static int allocationCount = 0; -static int lastAllocRequestedSlots = 0; +static size_t lastAllocRequestedSlots = 0; #endif Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize) -- cgit v1.2.3 From c32468189941c61be6266da3913de5c1c469bd95 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 24 Mar 2017 13:11:35 +0100 Subject: Fix prototype property when set to non-objects Commit 180decaf11ea6fb1147825a78a95c455400f7c7e regressed ch15/15.3/15.3.5/S15.3.5.3_A2_T6 in the sense that when a non-object was set for the prototype property, the protoProperty() helper function would perform an unsafe cast to Object * and return a non-null pointer, which however instanceof() does not expect. Change-Id: I134fd41f6b2d3349ebe7d9e91c6b6e5788f599b6 Reviewed-by: Robin Burchell --- src/qml/jsruntime/qv4functionobject_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 45d7485f1b..f4ac37219c 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -81,7 +81,7 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; } bool needsActivation() const { return function ? function->needsActivation() : false; } - const QV4::Object *protoProperty() const { return propertyData(Index_Prototype)->cast(); } + const QV4::Object *protoProperty() const { return propertyData(Index_Prototype)->as(); } Pointer scope; Function *function; -- cgit v1.2.3 From 65e005a72d62d8a42a60e0b8b789d1f04da91ccf Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 23 Mar 2017 19:33:29 +0100 Subject: in childMouseEventFilter, touchpoint grabber is also the mouse grabber When an item (such as Flickable) filters its children's mouse events, sometimes the mouse event may be one that is synthesized from a touch point. If that touch point is already grabbed, then in the context of childMouseEventFilter QQuickWindow::mouseGrabberItem() should return the item which has grabbed the touchpoint from which the mouse event was synthesized. Otherwise, there was a regression in which an item which can be dragged via touch (such as Slider in QQ Controls 2) could have its grab stolen by a filtering parent, such as Flickable, or the gesture recognizer in QtLocation. mouseGrabberItem() was returning null because touchMouseId and touchMouseDevice were not set, and the actual mouse was not grabbed. If a touch event is used to synthesize a mouse event, and during delivery an Item steals the grab of the synthetic mouse event, the original grabber needs to be notified that it has lost the grab. Task-number: QTBUG-59416 Change-Id: Ib121b06121df7593c0d549a6df42397b8ead1c45 Reviewed-by: Paolo Angelelli --- src/quick/items/qquickwindow.cpp | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index e6245f90f3..924de3645b 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -746,6 +746,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber) qCDebug(DBG_MOUSE_TARGET) << "grabber" << q->mouseGrabberItem() << "->" << grabber; QQuickItem *oldGrabber = q->mouseGrabberItem(); + bool fromTouch = false; if (grabber && touchMouseId != -1 && touchMouseDevice) { // update the touch item for mouse touch id to the new grabber @@ -753,6 +754,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber) auto point = touchMouseDevice->pointerEvent()->pointById(touchMouseId); if (point) point->setGrabber(grabber); + fromTouch = true; } else { QQuickPointerEvent *event = QQuickPointerDevice::genericMouseDevice()->pointerEvent(); Q_ASSERT(event->pointCount() == 1); @@ -762,8 +764,11 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber) if (oldGrabber) { QEvent e(QEvent::UngrabMouse); QSet hasFiltered; - if (!sendFilteredMouseEvent(oldGrabber->parentItem(), oldGrabber, &e, &hasFiltered)) + if (!sendFilteredMouseEvent(oldGrabber->parentItem(), oldGrabber, &e, &hasFiltered)) { oldGrabber->mouseUngrabEvent(); + if (fromTouch) + oldGrabber->touchUngrabEvent(); + } } } @@ -2585,28 +2590,39 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem break; } + bool touchMouseUnset = (touchMouseId == -1); // Only deliver mouse event if it is the touchMouseId or it could become the touchMouseId - if (touchMouseId == -1 || touchMouseId == tp.id()) { + if (touchMouseUnset || touchMouseId == tp.id()) { // targetEvent is already transformed wrt local position, velocity, etc. // FIXME: remove asTouchEvent!!! QScopedPointer mouseEvent(touchToMouseEvent(t, tp, event->asTouchEvent(), item, false)); + // If a filtering item calls QQuickWindow::mouseGrabberItem(), it should + // report the touchpoint's grabber. Whenever we send a synthetic mouse event, + // touchMouseId and touchMouseDevice must be set, even if it's only temporarily and isn't grabbed. + touchMouseId = tp.id(); + touchMouseDevice = event->device(); if (target->childMouseEventFilter(item, mouseEvent.data())) { qCDebug(DBG_TOUCH) << " - second chance intercepted on childMouseEventFilter by " << target; if (t != QEvent::MouseButtonRelease) { qCDebug(DBG_TOUCH_TARGET) << "TP" << tp.id() << "->" << target; - touchMouseDevice = event->device(); - if (touchMouseId == -1) { + if (touchMouseUnset) { // the point was grabbed as a pure touch point before, now it will be treated as mouse // but the old receiver still needs to be informed if (auto oldGrabber = touchMouseDevice->pointerEvent()->pointById(tp.id())->grabber()) oldGrabber->touchUngrabEvent(); } - touchMouseId = tp.id(); + touchMouseUnset = false; // We want to leave touchMouseId and touchMouseDevice set target->grabMouse(); } filtered = true; } + if (touchMouseUnset) { + // Now that we're done sending a synth mouse event, and it wasn't grabbed, + // the touchpoint is no longer acting as a synthetic mouse. Restore previous state. + touchMouseId = -1; + touchMouseDevice = nullptr; + } // Only one event can be filtered as a mouse event. break; } -- cgit v1.2.3 From 6d7c3c0743b3c6aac7d7faa1ffd18798ceced0ac Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 23 Mar 2017 20:19:34 +0100 Subject: Flickable: don't steal grab from item with keepTouchGrab set Sometimes filterMouseEvent can be given a mouse event which was synthesized from a touch point which was already grabbed. In such cases, if the grabber has keepTouchGrab set, respect it. This makes it possible again for a QQControls 2 slider to be draggable inside a Flickable which is also draggable in the same direction. Task-number: QTBUG-59416 Change-Id: I93b7fd9cb846b1e574615154f9a54316b60c0477 Reviewed-by: J-P Nurmi --- src/quick/items/qquickflickable.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 6a2946bdcc..27d7072f03 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -2301,7 +2301,8 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event) bool receiverDisabled = receiver && !receiver->isEnabled(); bool stealThisEvent = d->stealMouse; - if ((stealThisEvent || contains(localPos)) && (!receiver || !receiver->keepMouseGrab() || receiverDisabled)) { + bool receiverKeepsGrab = receiver && (receiver->keepMouseGrab() || receiver->keepTouchGrab()); + if ((stealThisEvent || contains(localPos)) && (!receiver || !receiverKeepsGrab || receiverDisabled)) { QScopedPointer mouseEvent(QQuickWindowPrivate::cloneMouseEvent(event, &localPos)); mouseEvent->setAccepted(false); @@ -2321,7 +2322,7 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event) default: break; } - if ((receiver && stealThisEvent && !receiver->keepMouseGrab() && receiver != this) || receiverDisabled) { + if ((receiver && stealThisEvent && !receiverKeepsGrab && receiver != this) || receiverDisabled) { d->clearDelayedPress(); grabMouse(); } else if (d->delayedPressEvent) { @@ -2337,7 +2338,7 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event) d->lastPosTime = -1; returnToBounds(); } - if (event->type() == QEvent::MouseButtonRelease || (receiver && receiver->keepMouseGrab() && !receiverDisabled)) { + if (event->type() == QEvent::MouseButtonRelease || (receiverKeepsGrab && !receiverDisabled)) { // mouse released, or another item has claimed the grab d->lastPosTime = -1; d->clearDelayedPress(); -- cgit v1.2.3 From 73f365f9f2d04131ae27a5dba26255feda18baa2 Mon Sep 17 00:00:00 2001 From: Kimmo Ollila Date: Mon, 27 Mar 2017 04:38:43 +0300 Subject: Add missing header inclusion Change-Id: I7c215db87552c63291e6c82d7b962ee17ec2f610 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmltypeloader.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index f115d4227c..40bd2e5020 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -64,6 +64,7 @@ #include #include #include +#include #include -- cgit v1.2.3 From 3026e2c5b0e8163c3ea6b691a1f88bd3f41eb171 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 27 Mar 2017 16:27:06 +0200 Subject: Add support for showing disassembly for cache mapped code Change-Id: I6199d624a23e2e1b67bcbb841f0bc999880a3993 Reviewed-by: Lars Knoll --- src/qml/jit/qv4assembler.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 5c90aba464..c5a60ec013 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -95,6 +95,12 @@ bool CompilationUnit::memoryMapCode(QString *errorString) JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(JSC::MacroAssemblerCodePtr(codePtr)); JSC::ExecutableAllocator::makeExecutable(codePtr, compiledFunction->codeSize); codeRefs[i] = codeRef; + + static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM"); + if (showCode) { + WTF::dataLogF("Mapped JIT code for %s\n", qPrintable(stringAt(compiledFunction->nameIndex))); + disassemble(codeRef.code(), compiledFunction->codeSize, " ", WTF::dataFile()); + } } return true; -- cgit v1.2.3 From ecda87091f290daec34bee6b55dd9cf920ffdcff Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 27 Mar 2017 16:27:39 +0200 Subject: Fix manual register allocation when cross-compiling for ARMv7 Let's assume that we always generate thumb2 code. I'm not even sure that we still support plain ARM anyway. Change-Id: Ie7ec4d1de8f9f6cb86d80193990e492782ff2cf2 Reviewed-by: Lars Knoll --- src/qml/jit/qv4targetplatform_p.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h index d9f8034b1f..ce6156802d 100644 --- a/src/qml/jit/qv4targetplatform_p.h +++ b/src/qml/jit/qv4targetplatform_p.h @@ -370,7 +370,7 @@ public: // There are two designated frame-pointer registers on ARM, depending on which instruction set // is used for the subroutine: r7 for Thumb or Thumb2, and r11 for ARM. We assign the constants // accordingly, and assign the locals-register to the "other" register. -#if CPU(ARM_THUMB2) +#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP) static const RegisterID FramePointerRegister = JSC::ARMRegisters::r7; static const RegisterID LocalsRegister = JSC::ARMRegisters::r11; #else // Thumbs down @@ -397,7 +397,7 @@ public: << RI(JSC::ARMRegisters::r4, QStringLiteral("r4"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) << RI(JSC::ARMRegisters::r5, QStringLiteral("r5"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) << RI(JSC::ARMRegisters::r6, QStringLiteral("r6"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) -#if !CPU(ARM_THUMB2) +#if !CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP) << RI(JSC::ARMRegisters::r7, QStringLiteral("r7"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) #endif << RI(JSC::ARMRegisters::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) @@ -405,7 +405,7 @@ public: << RI(JSC::ARMRegisters::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) #endif << RI(JSC::ARMRegisters::r10, QStringLiteral("r10"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) -#if CPU(ARM_THUMB2) +#if CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP) << RI(JSC::ARMRegisters::r11, QStringLiteral("r11"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) #endif << RI(JSC::ARMRegisters::d2, QStringLiteral("d2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) -- cgit v1.2.3 From 03006adeecfba8fdfa219e2a54f93eea21c81eeb Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 28 Mar 2017 14:40:44 +0200 Subject: Minor cleanup: Remove unused function Change-Id: Ie8d0c7b360ff120f381e33439037cf7b01257456 Reviewed-by: Lars Knoll --- src/qml/jit/qv4assembler_p.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index e507a14f12..81b164beb2 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -1235,13 +1235,6 @@ public: TargetConfiguration::MacroAssembler::storeDouble(fpScratchRegister, loadAddress(scratchRegister, target)); } - void storeValue(QV4::Primitive value, RegisterID destination) - { - Q_UNUSED(value); - Q_UNUSED(destination); - Q_UNREACHABLE(); - } - void storeValue(QV4::Primitive value, Address destination) { RegisterSizeDependentOps::storeValue(this, value, destination); -- cgit v1.2.3 From 05090868b816d2add1c22078a015a6dc19f401ae Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 28 Mar 2017 16:14:24 +0200 Subject: Simplify function prologue code in the JIT We don't have to do a engine->current->engine dance to get hold of the engine pointer, in order to update jsStackTop. We have a dedicated engine register :) Change-Id: I187ea67bf9f3e43b0048dca3cd6ee35f70d8737c Reviewed-by: Lars Knoll --- src/qml/jit/qv4assembler.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index c5a60ec013..d239ed9907 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -529,9 +529,7 @@ void Assembler::returnFromFunction(IR::Ret *s, RegisterInfo const int locals = stackLayout().calculateJSStackFrameSize(); subPtr(TrustedImm32(sizeof(QV4::Value)*locals), JITTargetPlatform::LocalsRegister); - loadPtr(Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister); - loadPtr(Address(JITTargetPlatform::ScratchRegister, targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, engine))), JITTargetPlatform::ScratchRegister); - storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::ScratchRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop)))); + storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop)))); leaveStandardStackFrame(regularRegistersToSave, fpRegistersToSave); ret(); -- cgit v1.2.3 From 1b8c7e72e4467925ecee49d2d66e81692ca9d525 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 28 Mar 2017 16:51:59 +0200 Subject: Fix pop(RegisterID) on ARMv7 when cross-compiling This is implemented as ldr instruction that automatically adjusts the indexing register, which for ARMv7 needs to be always 4-bytes, not sizeof(void*) which can be 8 on 64-bit hosts. Change-Id: I66cce2a7388ef12b321db643e8efb002158519aa Reviewed-by: Lars Knoll --- src/3rdparty/masm/assembler/MacroAssemblerARMv7.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h index 806f2e13b6..0d5d42bf71 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h @@ -1242,7 +1242,7 @@ public: void pop(RegisterID dest) { // store postindexed with writeback - m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true); + m_assembler.ldr(dest, ARMRegisters::sp, 4 /*sizeof(void*)*/, false, true); } void push(RegisterID src) -- cgit v1.2.3 From 0dbc575c1a8359534761167a5f5f1e29abedd51d Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 22 Feb 2017 16:16:14 +0100 Subject: Make keyboard events work in QQuickWidget Right now many cases outside of text input fields are simply broken, e.g. one cannot use a TableView or other controls with the keyboard. Removing the seemingly unnecessary focusObject() solves all problems since this way key events get delivered to the QQuickWidget which in turn forwards to the QQuickWindow. Directly routing into the QQuickWindow's focusObject(), which can be any item in the scene is wrong since it skips a big part of QQuickWindow's event handling logic. Task-number: QTBUG-45757 Change-Id: Ie53b9003d156ab019fa4b9cf461e209990e738f7 Reviewed-by: Paul Olav Tvete --- src/quickwidgets/qquickwidget.cpp | 7 +++---- src/quickwidgets/qquickwidget_p.h | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index ea02723db8..5d7fb04b9f 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -353,10 +353,9 @@ QImage QQuickWidgetPrivate::grabFramebuffer() return renderControl->grab(); } -QObject *QQuickWidgetPrivate::focusObject() -{ - return offscreenWindow ? offscreenWindow->focusObject() : 0; -} +// Intentionally not overriding the QQuickWindow's focusObject. +// Key events should go to our key event handlers, and then to the +// QQuickWindow, not any in-scene item. /*! \module QtQuickWidgets diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h index 559321cd51..6892e6e0b4 100644 --- a/src/quickwidgets/qquickwidget_p.h +++ b/src/quickwidgets/qquickwidget_p.h @@ -99,8 +99,6 @@ public: void destroyContext(); void handleContextCreationFailure(const QSurfaceFormat &format, bool isEs); - QObject *focusObject() Q_DECL_OVERRIDE; - #if QT_CONFIG(opengl) GLuint textureId() const Q_DECL_OVERRIDE; QImage grabFramebuffer() Q_DECL_OVERRIDE; -- cgit v1.2.3 From 4a6e072d6c7591ee58b56e3d6a2128e814c94848 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 29 Mar 2017 09:22:21 +0200 Subject: Fix stack pointer arithmetic when cross-compiling Replace the use of size(void*) with target assembler specific values for the pointer size, when calculating offsets into the stack for poke/peek/push/pop and placing arguments onto the stack before calling functions. Change-Id: I3aff540f0083967e75b61e0c29dbeb4d9ecfa433 Reviewed-by: Lars Knoll --- src/3rdparty/masm/assembler/MacroAssembler.h | 11 +++++++---- src/3rdparty/masm/assembler/MacroAssemblerARM64.h | 2 ++ src/3rdparty/masm/assembler/MacroAssemblerARMv7.h | 2 ++ src/3rdparty/masm/assembler/MacroAssemblerMIPS.h | 1 + src/3rdparty/masm/assembler/MacroAssemblerX86.h | 1 + src/3rdparty/masm/assembler/MacroAssemblerX86_64.h | 1 + src/qml/jit/qv4assembler_p.h | 2 +- 7 files changed, 15 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/3rdparty/masm/assembler/MacroAssembler.h b/src/3rdparty/masm/assembler/MacroAssembler.h index 7d9f156c8c..f37861eb66 100644 --- a/src/3rdparty/masm/assembler/MacroAssembler.h +++ b/src/3rdparty/masm/assembler/MacroAssembler.h @@ -94,6 +94,7 @@ public: using DataLabelCompact = typename MacroAssemblerBase::DataLabelCompact; using Jump = typename MacroAssemblerBase::Jump; using PatchableJump = typename MacroAssemblerBase::PatchableJump; + using MacroAssemblerBase::PointerSize; using MacroAssemblerBase::pop; using MacroAssemblerBase::jump; @@ -200,19 +201,19 @@ public: // described in terms of other macro assembly methods. void pop() { - addPtr(TrustedImm32(sizeof(void*)), MacroAssemblerBase::stackPointerRegister); + addPtr(TrustedImm32(PointerSize), MacroAssemblerBase::stackPointerRegister); } void peek(RegisterID dest, int index = 0) { - loadPtr(Address(MacroAssemblerBase::stackPointerRegister, (index * sizeof(void*))), dest); + loadPtr(Address(MacroAssemblerBase::stackPointerRegister, (index * PointerSize)), dest); } Address addressForPoke(int index) { - return Address(MacroAssemblerBase::stackPointerRegister, (index * sizeof(void*))); + return Address(MacroAssemblerBase::stackPointerRegister, (index * PointerSize)); } - + void poke(RegisterID src, int index = 0) { storePtr(src, addressForPoke(index)); @@ -223,10 +224,12 @@ public: store32(value, addressForPoke(index)); } +#if !defined(V4_BOOTSTRAP) void poke(TrustedImmPtr imm, int index = 0) { storePtr(imm, addressForPoke(index)); } +#endif #if (CPU(X86_64) || CPU(ARM64)) && !defined(V4_BOOTSTRAP) void peek64(RegisterID dest, int index = 0) diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARM64.h b/src/3rdparty/masm/assembler/MacroAssemblerARM64.h index a11637f7ca..11f1672e15 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerARM64.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerARM64.h @@ -127,6 +127,8 @@ private: static const ptrdiff_t REPATCH_OFFSET_CALL_TO_POINTER = -16; public: + static const int PointerSize = 8; + MacroAssemblerARM64() : m_dataMemoryTempRegister(this, dataTempRegister) , m_cachedMemoryTempRegister(this, memoryTempRegister) diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h index 0d5d42bf71..fe8170d098 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h @@ -46,6 +46,8 @@ protected: // the YarrJIT needs know about addressTempRegister in order to push inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); } public: + static const int PointerSize = 4; + MacroAssemblerARMv7() : m_makeJumpPatchable(false) { diff --git a/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h b/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h index 68584527fc..f2ad6a4470 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h @@ -37,6 +37,7 @@ namespace JSC { class MacroAssemblerMIPS : public AbstractMacroAssembler { public: typedef MIPSRegisters::FPRegisterID FPRegisterID; + static const int PointerSize = 4; MacroAssemblerMIPS() : m_fixedWidth(false) diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86.h b/src/3rdparty/masm/assembler/MacroAssemblerX86.h index 742a4b48f7..280cf427fc 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerX86.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerX86.h @@ -35,6 +35,7 @@ namespace JSC { class MacroAssemblerX86 : public MacroAssemblerX86Common { public: static const Scale ScalePtr = TimesFour; + static const int PointerSize = 4; using MacroAssemblerX86Common::add32; using MacroAssemblerX86Common::and32; diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h index 3566702413..8ee134c2fa 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h @@ -37,6 +37,7 @@ namespace JSC { class MacroAssemblerX86_64 : public MacroAssemblerX86Common { public: static const Scale ScalePtr = TimesEight; + static const int PointerSize = 8; using MacroAssemblerX86Common::add32; using MacroAssemblerX86Common::and32; diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 81b164beb2..3e3aab9452 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -1299,7 +1299,7 @@ public: template struct SizeOnStack { - enum { Size = Select= RegisterArgumentCount, sizeof(void*), 0>::Chosen }; + enum { Size = Select= RegisterArgumentCount, RegisterSize, 0>::Chosen }; }; template -- cgit v1.2.3 From e4894fe13d178b6aa8b5580b402df2d1b4f2615c Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 30 Mar 2017 15:16:10 +0200 Subject: Don't use incremental GC for now Revert back to not using the incremental garbage collector for now, as it apparently doesn't play well with weak values. This should fix the crashes seen in Qt Quick Controls 2 in CI Task-number: QTBUG-59600 Change-Id: I8e35e761d5d6e9022e1d183883cb5a9cb39b4975 Reviewed-by: Simon Hausmann --- src/qml/memory/qv4writebarrier_p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h index 455de4bf3d..a2f85822ca 100644 --- a/src/qml/memory/qv4writebarrier_p.h +++ b/src/qml/memory/qv4writebarrier_p.h @@ -55,8 +55,8 @@ QT_BEGIN_NAMESPACE -#define WRITEBARRIER_steele 1 -#define WRITEBARRIER_none -1 +#define WRITEBARRIER_steele -1 +#define WRITEBARRIER_none 1 #define WRITEBARRIER(x) (1/WRITEBARRIER_##x == 1) -- cgit v1.2.3