aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/masm/masm-defs.pri4
-rw-r--r--src/3rdparty/masm/yarr/YarrParser.h3
-rw-r--r--src/imports/imports.pro1
-rw-r--r--src/imports/labsanimation/dependencies.json2
-rw-r--r--src/imports/labsanimation/labsanimation.pro11
-rw-r--r--src/imports/labsanimation/plugin.cpp81
-rw-r--r--src/imports/labsanimation/plugins.qmltypes36
-rw-r--r--src/imports/labsanimation/qmldir3
-rw-r--r--src/imports/labsmodels/labsmodels.pro2
-rw-r--r--src/imports/models/models.pro2
-rw-r--r--src/imports/qtqml/plugin.cpp2
-rw-r--r--src/imports/qtqml/qtqml.pro3
-rw-r--r--src/imports/qtquick2/plugin.cpp5
-rw-r--r--src/imports/qtquick2/qtquick2.pro2
-rw-r--r--src/qml/compiler/qqmlpropertycachecreator_p.h5
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h59
-rw-r--r--src/qml/compiler/qv4codegen.cpp83
-rw-r--r--src/qml/compiler/qv4compileddata_p.h6
-rw-r--r--src/qml/compiler/qv4compiler.cpp1
-rw-r--r--src/qml/compiler/qv4compilercontext.cpp22
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h3
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp65
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h60
-rw-r--r--src/qml/configure.json87
-rw-r--r--src/qml/jit/jit.pri31
-rw-r--r--src/qml/jit/qv4assemblercommon.cpp4
-rw-r--r--src/qml/jit/qv4assemblercommon_p.h9
-rw-r--r--src/qml/jit/qv4baselineassembler.cpp4
-rw-r--r--src/qml/jit/qv4baselineassembler_p.h2
-rw-r--r--src/qml/jit/qv4baselinejit.cpp68
-rw-r--r--src/qml/jit/qv4baselinejit_p.h63
-rw-r--r--src/qml/jit/qv4blockscheduler.cpp208
-rw-r--r--src/qml/jit/qv4blockscheduler_p.h155
-rw-r--r--src/qml/jit/qv4domtree.cpp436
-rw-r--r--src/qml/jit/qv4domtree_p.h136
-rw-r--r--src/qml/jit/qv4graph.cpp103
-rw-r--r--src/qml/jit/qv4graph_p.h146
-rw-r--r--src/qml/jit/qv4graphbuilder.cpp1683
-rw-r--r--src/qml/jit/qv4graphbuilder_p.h298
-rw-r--r--src/qml/jit/qv4ir.cpp382
-rw-r--r--src/qml/jit/qv4ir_p.h228
-rw-r--r--src/qml/jit/qv4loopinfo.cpp199
-rw-r--r--src/qml/jit/qv4loopinfo_p.h159
-rw-r--r--src/qml/jit/qv4lowering.cpp200
-rw-r--r--src/qml/jit/qv4lowering_p.h107
-rw-r--r--src/qml/jit/qv4mi.cpp251
-rw-r--r--src/qml/jit/qv4mi_p.h627
-rw-r--r--src/qml/jit/qv4miblockset_p.h291
-rw-r--r--src/qml/jit/qv4node.cpp215
-rw-r--r--src/qml/jit/qv4node_p.h626
-rw-r--r--src/qml/jit/qv4operation.cpp770
-rw-r--r--src/qml/jit/qv4operation_p.h567
-rw-r--r--src/qml/jit/qv4runtimesupport_p.h255
-rw-r--r--src/qml/jit/qv4schedulers.cpp912
-rw-r--r--src/qml/jit/qv4schedulers_p.h162
-rw-r--r--src/qml/jit/qv4tracingjit.cpp91
-rw-r--r--src/qml/jsapi/qjsengine.cpp36
-rw-r--r--src/qml/jsapi/qjsengine.h3
-rw-r--r--src/qml/jsapi/qjsvalue.cpp6
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp13
-rw-r--r--src/qml/jsruntime/qv4engine_p.h4
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h20
-rw-r--r--src/qml/jsruntime/qv4function.cpp36
-rw-r--r--src/qml/jsruntime/qv4function_p.h25
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h12
-rw-r--r--src/qml/jsruntime/qv4global_p.h60
-rw-r--r--src/qml/jsruntime/qv4identifier.cpp16
-rw-r--r--src/qml/jsruntime/qv4identifiertable.cpp16
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp13
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp13
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h2
-rw-r--r--src/qml/jsruntime/qv4math_p.h27
-rw-r--r--src/qml/jsruntime/qv4object_p.h2
-rw-r--r--src/qml/jsruntime/qv4propertykey_p.h2
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp26
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp8
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp48
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h8
-rw-r--r--src/qml/jsruntime/qv4serialize.cpp73
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp189
-rw-r--r--src/qml/jsruntime/qv4vme_moth_p.h2
-rw-r--r--src/qml/jsruntime/qv4vtable_p.h2
-rw-r--r--src/qml/qml.pro4
-rw-r--r--src/qml/qml/ftw/ftw.pri4
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp54
-rw-r--r--src/qml/qml/ftw/qprimefornumbits_p.h80
-rw-r--r--src/qml/qml/ftw/qstringhash.cpp168
-rw-r--r--src/qml/qml/ftw/qstringhash_p.h69
-rw-r--r--src/qml/qml/qqml.h17
-rw-r--r--src/qml/qml/qqmlbinding.cpp6
-rw-r--r--src/qml/qml/qqmldata_p.h3
-rw-r--r--src/qml/qml/qqmlengine.cpp139
-rw-r--r--src/qml/qml/qqmlengine.h7
-rw-r--r--src/qml/qml/qqmlengine_p.h14
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h2
-rw-r--r--src/qml/qml/qqmlmetatype.cpp36
-rw-r--r--src/qml/qml/qqmlmetatype_p.h13
-rw-r--r--src/qml/qml/qqmlmetatypedata_p.h19
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp4
-rw-r--r--src/qml/qml/qqmlprivate.h5
-rw-r--r--src/qml/qml/qqmlproperty.cpp4
-rw-r--r--src/qml/qml/qqmltype.cpp82
-rw-r--r--src/qml/qml/qqmltype_p.h29
-rw-r--r--src/qml/qml/qqmltype_p_p.h1
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp181
-rw-r--r--src/qml/qtqmlglobal.h2
-rw-r--r--src/qml/types/types.pri41
-rw-r--r--src/qml/util/util.pri14
-rw-r--r--src/qmldebug/qqmlprofilerevent_p.h2
-rw-r--r--src/qmlmodels/configure.json31
-rw-r--r--src/qmlmodels/qmlmodels.pro57
-rw-r--r--src/qmlmodels/qqmladaptormodel.cpp (renamed from src/qml/util/qqmladaptormodel.cpp)0
-rw-r--r--src/qmlmodels/qqmladaptormodel_p.h (renamed from src/qml/util/qqmladaptormodel_p.h)6
-rw-r--r--src/qmlmodels/qqmlchangeset.cpp (renamed from src/qml/util/qqmlchangeset.cpp)0
-rw-r--r--src/qmlmodels/qqmlchangeset_p.h (renamed from src/qml/util/qqmlchangeset_p.h)8
-rw-r--r--src/qmlmodels/qqmldelegatecomponent.cpp (renamed from src/qml/types/qqmldelegatecomponent.cpp)2
-rw-r--r--src/qmlmodels/qqmldelegatecomponent_p.h (renamed from src/qml/types/qqmldelegatecomponent_p.h)8
-rw-r--r--src/qmlmodels/qqmldelegatemodel.cpp (renamed from src/qml/types/qqmldelegatemodel.cpp)2
-rw-r--r--src/qmlmodels/qqmldelegatemodel_p.h (renamed from src/qml/types/qqmldelegatemodel_p.h)8
-rw-r--r--src/qmlmodels/qqmldelegatemodel_p_p.h (renamed from src/qml/types/qqmldelegatemodel_p_p.h)2
-rw-r--r--src/qmlmodels/qqmlinstantiator.cpp (renamed from src/qml/types/qqmlinstantiator.cpp)4
-rw-r--r--src/qmlmodels/qqmlinstantiator_p.h (renamed from src/qml/types/qqmlinstantiator_p.h)4
-rw-r--r--src/qmlmodels/qqmlinstantiator_p_p.h (renamed from src/qml/types/qqmlinstantiator_p_p.h)2
-rw-r--r--src/qmlmodels/qqmlitemmodels.qdoc (renamed from src/qml/types/qqmlitemmodels.qdoc)0
-rw-r--r--src/qmlmodels/qqmlitemselectionmodel.qdoc (renamed from src/qml/types/qqmlitemselectionmodel.qdoc)0
-rw-r--r--src/qmlmodels/qqmllistaccessor.cpp (renamed from src/qml/util/qqmllistaccessor.cpp)0
-rw-r--r--src/qmlmodels/qqmllistaccessor_p.h (renamed from src/qml/util/qqmllistaccessor_p.h)0
-rw-r--r--src/qmlmodels/qqmllistcompositor.cpp (renamed from src/qml/util/qqmllistcompositor.cpp)0
-rw-r--r--src/qmlmodels/qqmllistcompositor_p.h (renamed from src/qml/util/qqmllistcompositor_p.h)0
-rw-r--r--src/qmlmodels/qqmllistmodel.cpp (renamed from src/qml/types/qqmllistmodel.cpp)0
-rw-r--r--src/qmlmodels/qqmllistmodel_p.h (renamed from src/qml/types/qqmllistmodel_p.h)7
-rw-r--r--src/qmlmodels/qqmllistmodel_p_p.h (renamed from src/qml/types/qqmllistmodel_p_p.h)1
-rw-r--r--src/qmlmodels/qqmllistmodelworkeragent.cpp (renamed from src/qml/types/qqmllistmodelworkeragent.cpp)10
-rw-r--r--src/qmlmodels/qqmllistmodelworkeragent_p.h (renamed from src/qml/types/qqmllistmodelworkeragent_p.h)32
-rw-r--r--src/qmlmodels/qqmlmodelsmodule.cpp (renamed from src/qml/types/qqmlmodelsmodule.cpp)1
-rw-r--r--src/qmlmodels/qqmlmodelsmodule_p.h (renamed from src/qml/types/qqmlmodelsmodule_p.h)4
-rw-r--r--src/qmlmodels/qqmlobjectmodel.cpp (renamed from src/qml/types/qqmlobjectmodel.cpp)0
-rw-r--r--src/qmlmodels/qqmlobjectmodel_p.h (renamed from src/qml/types/qqmlobjectmodel_p.h)6
-rw-r--r--src/qmlmodels/qqmltableinstancemodel.cpp (renamed from src/qml/types/qqmltableinstancemodel.cpp)2
-rw-r--r--src/qmlmodels/qqmltableinstancemodel_p.h (renamed from src/qml/types/qqmltableinstancemodel_p.h)6
-rw-r--r--src/qmlmodels/qqmltablemodel.cpp (renamed from src/qml/types/qqmltablemodel.cpp)0
-rw-r--r--src/qmlmodels/qqmltablemodel_p.h (renamed from src/qml/types/qqmltablemodel_p.h)6
-rw-r--r--src/qmlmodels/qqmltablemodelcolumn.cpp (renamed from src/qml/types/qqmltablemodelcolumn.cpp)0
-rw-r--r--src/qmlmodels/qqmltablemodelcolumn_p.h (renamed from src/qml/types/qqmltablemodelcolumn_p.h)4
-rw-r--r--src/qmlmodels/qquickpackage.cpp (renamed from src/qml/types/qquickpackage.cpp)0
-rw-r--r--src/qmlmodels/qquickpackage_p.h (renamed from src/qml/types/qquickpackage_p.h)0
-rw-r--r--src/qmlmodels/qtqmlmodelsglobal.h59
-rw-r--r--src/qmlmodels/qtqmlmodelsglobal_p.h61
-rw-r--r--src/quick/configure.json3
-rw-r--r--src/quick/doc/snippets/pointerHandlers/handlerFlick.qml88
-rw-r--r--src/quick/doc/snippets/pointerHandlers/wheelHandler.qml63
-rw-r--r--src/quick/doc/snippets/qml/boundaryRule.qml74
-rw-r--r--src/quick/doc/snippets/qml/tableview/cpp-tablemodel.cpp (renamed from src/quick/doc/snippets/qml/tableview/tablemodel.cpp)0
-rw-r--r--src/quick/doc/snippets/qml/tableview/cpp-tablemodel.qml (renamed from src/quick/doc/snippets/qml/tableview/tablemodel.qml)0
-rw-r--r--src/quick/doc/snippets/qml/tableview/qml-tablemodel.qml92
-rw-r--r--src/quick/handlers/handlers.pri6
-rw-r--r--src/quick/handlers/qquickmultipointhandler.cpp13
-rw-r--r--src/quick/handlers/qquickpinchhandler.cpp4
-rw-r--r--src/quick/handlers/qquickwheelhandler.cpp520
-rw-r--r--src/quick/handlers/qquickwheelhandler_p.h128
-rw-r--r--src/quick/handlers/qquickwheelhandler_p_p.h87
-rw-r--r--src/quick/items/qquickevents.cpp38
-rw-r--r--src/quick/items/qquickevents_p_p.h1
-rw-r--r--src/quick/items/qquickitemsmodule.cpp9
-rw-r--r--src/quick/items/qquickitemview_p_p.h6
-rw-r--r--src/quick/items/qquickrepeater.cpp1
-rw-r--r--src/quick/items/qquicktableview.cpp527
-rw-r--r--src/quick/items/qquicktableview_p.h10
-rw-r--r--src/quick/items/qquicktableview_p_p.h45
-rw-r--r--src/quick/items/qquickwindow.cpp2
-rw-r--r--src/quick/quick.pro2
-rw-r--r--src/quick/util/qquickanimation.cpp2
-rw-r--r--src/quick/util/qquickboundaryrule.cpp574
-rw-r--r--src/quick/util/qquickboundaryrule_p.h145
-rw-r--r--src/quick/util/util.pri2
-rw-r--r--src/src.pro4
177 files changed, 3682 insertions, 10697 deletions
diff --git a/src/3rdparty/masm/masm-defs.pri b/src/3rdparty/masm/masm-defs.pri
index 08c46a7ac2..90a795c6ce 100644
--- a/src/3rdparty/masm/masm-defs.pri
+++ b/src/3rdparty/masm/masm-defs.pri
@@ -33,10 +33,6 @@ disassembler {
DEFINES += WTF_USE_UDIS86=0
}
-force-compile-jit {
- DEFINES += V4_FORCE_COMPILE_JIT
-}
-
INCLUDEPATH += $$PWD/disassembler
INCLUDEPATH += $$PWD/disassembler/udis86
INCLUDEPATH += $$_OUT_PWD
diff --git a/src/3rdparty/masm/yarr/YarrParser.h b/src/3rdparty/masm/yarr/YarrParser.h
index f1ffc92189..a18b553ef0 100644
--- a/src/3rdparty/masm/yarr/YarrParser.h
+++ b/src/3rdparty/masm/yarr/YarrParser.h
@@ -703,7 +703,8 @@ private:
ASSERT(!hasError(m_errorCode));
ASSERT(min <= max);
- if (min == UINT_MAX) {
+ const unsigned quantifyLimit = 1 << 24;
+ if (min > quantifyLimit || (max != quantifyInfinite && max > quantifyLimit)) {
m_errorCode = ErrorCode::QuantifierTooLarge;
return;
}
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index 24e93fec1c..901c263be5 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -15,6 +15,7 @@ qtHaveModule(quick) {
QT_FOR_CONFIG += quick-private
SUBDIRS += \
+ labsanimation \
layouts \
qtquick2 \
window \
diff --git a/src/imports/labsanimation/dependencies.json b/src/imports/labsanimation/dependencies.json
new file mode 100644
index 0000000000..0d4f101c7a
--- /dev/null
+++ b/src/imports/labsanimation/dependencies.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/src/imports/labsanimation/labsanimation.pro b/src/imports/labsanimation/labsanimation.pro
new file mode 100644
index 0000000000..64e076401f
--- /dev/null
+++ b/src/imports/labsanimation/labsanimation.pro
@@ -0,0 +1,11 @@
+CXX_MODULE = qml
+TARGET = labsanimationplugin
+TARGETPATH = Qt/labs/animation
+IMPORT_VERSION = 1.0
+
+SOURCES += \
+ plugin.cpp
+
+QT = qml-private quick-private
+
+load(qml_plugin)
diff --git a/src/imports/labsanimation/plugin.cpp b/src/imports/labsanimation/plugin.cpp
new file mode 100644
index 0000000000..d8c0c071ca
--- /dev/null
+++ b/src/imports/labsanimation/plugin.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins 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 <QtQml/qqmlextensionplugin.h>
+#include <QtQml/qqml.h>
+
+#include <private/qquickboundaryrule_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlmodule Qt.labs.animation 1.0
+ \title Qt Quick experimental animation types
+ \ingroup qmlmodules
+ \brief Provides QML experimental types for animation
+ \since 5.14
+
+ This QML module contains experimental QML types related to animation.
+
+ To use the types in this module, import the module with the following line:
+
+ \code
+ import Qt.labs.animation 1.0
+ \endcode
+*/
+
+//![class decl]
+class QtLabsAnimationPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+public:
+ QtLabsAnimationPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { }
+ void registerTypes(const char *uri) override
+ {
+ Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.animation"));
+ qmlRegisterType<QQuickBoundaryRule>(uri, 1, 0, "BoundaryRule");
+ qmlRegisterModule(uri, 1, 0);
+ }
+};
+//![class decl]
+
+QT_END_NAMESPACE
+
+#include "plugin.moc"
diff --git a/src/imports/labsanimation/plugins.qmltypes b/src/imports/labsanimation/plugins.qmltypes
new file mode 100644
index 0000000000..065e65ad7a
--- /dev/null
+++ b/src/imports/labsanimation/plugins.qmltypes
@@ -0,0 +1,36 @@
+import QtQuick.tooling 1.2
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable Qt.labs.animation 1.0'
+
+Module {
+ dependencies: ["QtQuick 2.0"]
+ Component {
+ name: "QQuickBoundaryRule"
+ prototype: "QObject"
+ exports: ["Qt.labs.animation/BoundaryRule 1.0"]
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "OvershootFilter"
+ values: {
+ "None": 0,
+ "Peak": 1
+ }
+ }
+ Property { name: "enabled"; type: "bool" }
+ Property { name: "minimum"; type: "double" }
+ Property { name: "minimumOvershoot"; type: "double" }
+ Property { name: "maximum"; type: "double" }
+ Property { name: "maximumOvershoot"; type: "double" }
+ Property { name: "overshootScale"; type: "double" }
+ Property { name: "currentOvershoot"; type: "double"; isReadonly: true }
+ Property { name: "peakOvershoot"; type: "double"; isReadonly: true }
+ Property { name: "overshootFilter"; type: "OvershootFilter" }
+ Property { name: "easing"; type: "QEasingCurve" }
+ Property { name: "returnDuration"; type: "int" }
+ Method { name: "returnToBounds"; type: "bool" }
+ }
+}
diff --git a/src/imports/labsanimation/qmldir b/src/imports/labsanimation/qmldir
new file mode 100644
index 0000000000..b24fc98bfa
--- /dev/null
+++ b/src/imports/labsanimation/qmldir
@@ -0,0 +1,3 @@
+module Qt.labs.animation
+plugin labsanimationplugin
+classname QtLabsAnimationPlugin
diff --git a/src/imports/labsmodels/labsmodels.pro b/src/imports/labsmodels/labsmodels.pro
index 1795ae5e43..5ef2ad76f6 100644
--- a/src/imports/labsmodels/labsmodels.pro
+++ b/src/imports/labsmodels/labsmodels.pro
@@ -6,6 +6,6 @@ IMPORT_VERSION = 1.0
SOURCES += \
plugin.cpp
-QT = qml-private
+QT = qml-private qmlmodels-private
load(qml_plugin)
diff --git a/src/imports/models/models.pro b/src/imports/models/models.pro
index fc87533cea..fd13b12401 100644
--- a/src/imports/models/models.pro
+++ b/src/imports/models/models.pro
@@ -6,6 +6,6 @@ IMPORT_VERSION = 2.$$QT_MINOR_VERSION
SOURCES += \
plugin.cpp
-QT = qml-private
+QT = qml-private qmlmodels-private
load(qml_plugin)
diff --git a/src/imports/qtqml/plugin.cpp b/src/imports/qtqml/plugin.cpp
index eb8c0ffc2f..7595d6d65b 100644
--- a/src/imports/qtqml/plugin.cpp
+++ b/src/imports/qtqml/plugin.cpp
@@ -43,7 +43,7 @@
#include <QtQml/private/qqmlbind_p.h>
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-#include <QtQml/private/qqmlmodelsmodule_p.h>
+#include <QtQmlModels/private/qqmlmodelsmodule_p.h>
#endif
QT_BEGIN_NAMESPACE
diff --git a/src/imports/qtqml/qtqml.pro b/src/imports/qtqml/qtqml.pro
index d5bb313d0c..7a5169b8fc 100644
--- a/src/imports/qtqml/qtqml.pro
+++ b/src/imports/qtqml/qtqml.pro
@@ -6,6 +6,7 @@ IMPORT_VERSION = 2.$$QT_MINOR_VERSION
SOURCES += \
plugin.cpp
-QT = qml-private
+# In Qt6 we won't need qmlmodels-private here
+QT = qml-private qmlmodels-private
load(qml_plugin)
diff --git a/src/imports/qtquick2/plugin.cpp b/src/imports/qtquick2/plugin.cpp
index 4dc6fee916..a5a2c73ced 100644
--- a/src/imports/qtquick2/plugin.cpp
+++ b/src/imports/qtquick2/plugin.cpp
@@ -38,8 +38,11 @@
****************************************************************************/
#include <QtQml/qqmlextensionplugin.h>
+
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
#include <QtQml/private/qqmlengine_p.h>
-#include <QtQml/private/qqmlmodelsmodule_p.h>
+#include <QtQmlModels/private/qqmlmodelsmodule_p.h>
+#endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
#include <private/qtquick2_p.h>
diff --git a/src/imports/qtquick2/qtquick2.pro b/src/imports/qtquick2/qtquick2.pro
index 744dce4195..1b45d69eb7 100644
--- a/src/imports/qtquick2/qtquick2.pro
+++ b/src/imports/qtquick2/qtquick2.pro
@@ -6,6 +6,6 @@ IMPORT_VERSION = 2.$$QT_MINOR_VERSION
SOURCES += \
plugin.cpp
-QT += quick-private qml-private
+QT += quick-private qml-private qmlmodels-private
load(qml_plugin)
diff --git a/src/qml/compiler/qqmlpropertycachecreator_p.h b/src/qml/compiler/qqmlpropertycachecreator_p.h
index 21d653af55..346cfb5803 100644
--- a/src/qml/compiler/qqmlpropertycachecreator_p.h
+++ b/src/qml/compiler/qqmlpropertycachecreator_p.h
@@ -704,8 +704,9 @@ inline QQmlCompileError QQmlPropertyCacheAliasCreator<ObjectContainer>::property
QVarLengthArray<const QV4::CompiledData::Alias *, 4> seenAliases({lastAlias});
do {
- const CompiledObject *targetObject = objectContainer->objectAt(
- objectForId(component, lastAlias->targetObjectId));
+ const int targetObjectIndex = objectForId(component, lastAlias->targetObjectId);
+ Q_ASSERT(targetObjectIndex >= 0);
+ const CompiledObject *targetObject = objectContainer->objectAt(targetObjectIndex);
Q_ASSERT(targetObject);
auto nextAlias = targetObject->aliasesBegin();
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index 1d0a57c536..acd4aa62ea 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -66,8 +66,6 @@ namespace Moth {
class BytecodeGenerator {
public:
- typedef CompiledData::Function::TraceInfoCount TraceInfoCount;
-
BytecodeGenerator(int line, bool debug)
: startLine(line), debugMode(debug) {}
@@ -164,15 +162,6 @@ public:
addInstructionHelper(Moth::Instr::Type(InstrT), genericInstr);
}
- // Same as addInstruction, but also add a trace slot. Move only, because the instruction cannot
- // be reused afterwards.
- template<int InstrT>
- void addTracingInstruction(InstrData<InstrT> data)
- {
- data.traceSlot = nextTraceInfo();
- addInstruction(data);
- }
-
Q_REQUIRED_RESULT Jump jump()
{
QT_WARNING_PUSH
@@ -184,12 +173,12 @@ QT_WARNING_POP
Q_REQUIRED_RESULT Jump jumpTrue()
{
- return addTracingJumpInstruction(Instruction::JumpTrue());
+ return addJumpInstruction(Instruction::JumpTrue());
}
Q_REQUIRED_RESULT Jump jumpFalse()
{
- return addTracingJumpInstruction(Instruction::JumpFalse());
+ return addJumpInstruction(Instruction::JumpFalse());
}
Q_REQUIRED_RESULT Jump jumpNotUndefined()
@@ -209,7 +198,7 @@ QT_WARNING_POP
Instruction::CmpStrictEqual cmp;
cmp.lhs = lhs;
addInstruction(std::move(cmp));
- addTracingJumpInstruction(Instruction::JumpTrue()).link(target);
+ addJumpInstruction(Instruction::JumpTrue()).link(target);
}
void jumpStrictNotEqual(const StackSlot &lhs, const Label &target)
@@ -217,7 +206,13 @@ QT_WARNING_POP
Instruction::CmpStrictNotEqual cmp;
cmp.lhs = lhs;
addInstruction(std::move(cmp));
- addTracingJumpInstruction(Instruction::JumpTrue()).link(target);
+ addJumpInstruction(Instruction::JumpTrue()).link(target);
+ }
+
+ void checkException()
+ {
+ Instruction::CheckException chk;
+ addInstruction(chk);
}
void setUnwindHandler(ExceptionHandler *handler)
@@ -258,13 +253,6 @@ QT_WARNING_POP
void finalize(Compiler::Context *context);
template<int InstrT>
- Jump addTracingJumpInstruction(InstrData<InstrT> &&data)
- {
- data.traceSlot = nextTraceInfo();
- return addJumpInstruction(data);
- }
-
- template<int InstrT>
Jump addJumpInstruction(const InstrData<InstrT> &data)
{
Instr genericInstr;
@@ -275,9 +263,9 @@ QT_WARNING_POP
void addCJumpInstruction(bool jumpOnFalse, const Label *trueLabel, const Label *falseLabel)
{
if (jumpOnFalse)
- addTracingJumpInstruction(Instruction::JumpFalse()).link(*falseLabel);
+ addJumpInstruction(Instruction::JumpFalse()).link(*falseLabel);
else
- addTracingJumpInstruction(Instruction::JumpTrue()).link(*trueLabel);
+ addJumpInstruction(Instruction::JumpTrue()).link(*trueLabel);
}
void clearLastInstruction()
@@ -285,27 +273,6 @@ QT_WARNING_POP
lastInstrType = -1;
}
- TraceInfoCount nextTraceInfo()
- {
- // If tracing is disabled, use slot 0 to unconditionally store all trace info
- if (nTraceInfos == CompiledData::Function::NoTracing())
- return TraceInfoCount(0);
- return nTraceInfos++;
- }
-
- void setTracing(bool onoff, int argumentCount)
- {
- if (onoff)
- nTraceInfos = argumentCount;
- else
- nTraceInfos = CompiledData::Function::NoTracing();
- }
-
- TraceInfoCount traceInfoCount() const
- {
- return nTraceInfos;
- }
-
void addLoopStart(const Label &start)
{
_labelInfos.push_back({ start.index });
@@ -346,8 +313,6 @@ private:
int lastInstrType = -1;
Moth::Instr lastInstr;
- TraceInfoCount nTraceInfos = TraceInfoCount(0);
-
struct LabelInfo {
int labelIndex;
};
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 88d3dbe9c5..1bf0e7147d 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -289,13 +289,13 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
case UMinus: {
expr.loadInAccumulator();
Instruction::UMinus uminus = {};
- bytecodeGenerator->addTracingInstruction(uminus);
+ bytecodeGenerator->addInstruction(uminus);
return Reference::fromAccumulator(this);
}
case UPlus: {
expr.loadInAccumulator();
Instruction::UPlus uplus = {};
- bytecodeGenerator->addTracingInstruction(uplus);
+ bytecodeGenerator->addInstruction(uplus);
return Reference::fromAccumulator(this);
}
case Not: {
@@ -315,10 +315,10 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
Reference e = expr.asLValue();
e.loadInAccumulator();
Instruction::UPlus uplus = {};
- bytecodeGenerator->addTracingInstruction(uplus);
+ bytecodeGenerator->addInstruction(uplus);
Reference originalValue = Reference::fromStackSlot(this).storeRetainAccumulator();
Instruction::Increment inc = {};
- bytecodeGenerator->addTracingInstruction(inc);
+ bytecodeGenerator->addInstruction(inc);
e.storeConsumeAccumulator();
return originalValue;
} else {
@@ -330,7 +330,7 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
Reference e = expr.asLValue();
e.loadInAccumulator();
Instruction::Increment inc = {};
- bytecodeGenerator->addTracingInstruction(inc);
+ bytecodeGenerator->addInstruction(inc);
if (exprAccept(nx))
return e.storeConsumeAccumulator();
else
@@ -341,10 +341,10 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
Reference e = expr.asLValue();
e.loadInAccumulator();
Instruction::UPlus uplus = {};
- bytecodeGenerator->addTracingInstruction(uplus);
+ bytecodeGenerator->addInstruction(uplus);
Reference originalValue = Reference::fromStackSlot(this).storeRetainAccumulator();
Instruction::Decrement dec = {};
- bytecodeGenerator->addTracingInstruction(dec);
+ bytecodeGenerator->addInstruction(dec);
e.storeConsumeAccumulator();
return originalValue;
} else {
@@ -356,7 +356,7 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
Reference e = expr.asLValue();
e.loadInAccumulator();
Instruction::Decrement dec = {};
- bytecodeGenerator->addTracingInstruction(dec);
+ bytecodeGenerator->addInstruction(dec);
if (exprAccept(nx))
return e.storeConsumeAccumulator();
else
@@ -1139,7 +1139,7 @@ bool Codegen::visit(ArrayPattern *ast)
index.loadInAccumulator();
Instruction::Increment inc = {};
- bytecodeGenerator->addTracingInstruction(inc);
+ bytecodeGenerator->addInstruction(inc);
index.storeConsumeAccumulator();
};
@@ -1196,11 +1196,12 @@ bool Codegen::visit(ArrayPattern *ast)
next.value = lhsValue.stackSlot();
next.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(next);
- bytecodeGenerator->addTracingJumpInstruction(Instruction::JumpTrue()).link(end);
+ bytecodeGenerator->addJumpInstruction(Instruction::JumpTrue()).link(end);
lhsValue.loadInAccumulator();
pushAccumulator();
+ bytecodeGenerator->checkException();
bytecodeGenerator->jump().link(in);
end.link();
}
@@ -1487,20 +1488,20 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
right.loadInAccumulator();
Instruction::Add add;
add.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(add);
+ bytecodeGenerator->addInstruction(add);
break;
}
case QSOperator::Sub: {
if (right.isConstant() && right.constant == Encode(int(1))) {
left.loadInAccumulator();
Instruction::Decrement dec = {};
- bytecodeGenerator->addTracingInstruction(dec);
+ bytecodeGenerator->addInstruction(dec);
} else {
left = left.storeOnStack();
right.loadInAccumulator();
Instruction::Sub sub;
sub.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(sub);
+ bytecodeGenerator->addInstruction(sub);
}
break;
}
@@ -1517,7 +1518,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
right.loadInAccumulator();
Instruction::Mul mul;
mul.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(mul);
+ bytecodeGenerator->addInstruction(mul);
break;
}
case QSOperator::Div: {
@@ -1533,7 +1534,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
right.loadInAccumulator();
Instruction::Mod mod;
mod.lhs = left.stackSlot();
- bytecodeGenerator->addTracingInstruction(mod);
+ bytecodeGenerator->addInstruction(mod);
break;
}
case QSOperator::BitAnd:
@@ -1902,7 +1903,7 @@ bool Codegen::visit(CallExpression *ast)
call.thisObject = baseObject.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Instruction::TailCall call;
call.func = base.stackSlot();
@@ -1931,14 +1932,14 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.lookupIndex = registerGetterLookup(base.propertyNameIndex);
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Instruction::CallProperty call;
call.base = base.propertyBase.stackSlot();
call.name = base.propertyNameIndex;
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
} else if (base.type == Reference::Subscript) {
Instruction::CallElement call;
@@ -1946,33 +1947,33 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.index = base.elementSubscript.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else if (base.type == Reference::Name) {
if (base.name == QStringLiteral("eval")) {
Instruction::CallPossiblyDirectEval call;
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else if (!disable_lookups && useFastLookups && base.global) {
if (base.qmlGlobal) {
Instruction::CallQmlContextPropertyLookup call;
call.index = registerQmlContextPropertyGetterLookup(base.nameAsIndex());
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Instruction::CallGlobalLookup call;
call.index = registerGlobalGetterLookup(base.nameAsIndex());
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
} else {
Instruction::CallName call;
call.name = base.nameAsIndex();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
} else if (base.type == Reference::SuperProperty) {
Reference receiver = base.baseObject();
@@ -1989,14 +1990,14 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.thisObject = receiver.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
} else {
Q_ASSERT(base.isStackSlot());
Instruction::CallValue call;
call.name = base.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ bytecodeGenerator->addInstruction(call);
}
setExprResult(Reference::fromAccumulator(this));
@@ -2732,14 +2733,14 @@ bool Codegen::visit(TemplateLiteral *ast)
Instruction::Add instr;
instr.lhs = temp2;
- bytecodeGenerator->addTracingInstruction(instr);
+ bytecodeGenerator->addInstruction(instr);
} else {
expr.loadInAccumulator();
}
Instruction::Add instr;
instr.lhs = temp;
- bytecodeGenerator->addTracingInstruction(instr);
+ bytecodeGenerator->addInstruction(instr);
}
auto r = Reference::fromAccumulator(this);
@@ -2997,7 +2998,6 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
bool savedFunctionEndsWithReturn = functionEndsWithReturn;
functionEndsWithReturn = endsWithReturn(_module, body);
- bytecodeGenerator->setTracing(_functionContext->canUseTracingJit(), _context->arguments.size());
// reserve the js stack frame (Context & js Function & accumulator)
bytecodeGenerator->newRegisterArray(sizeof(CallData)/sizeof(Value) - 1 + _context->arguments.size());
@@ -3084,7 +3084,6 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
Q_ASSERT(_context == _functionContext);
bytecodeGenerator->finalize(_context);
_context->registerCountInFunction = bytecodeGenerator->registerCount();
- _context->nTraceInfos = bytecodeGenerator->traceInfoCount();
static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
if (showCode) {
qDebug() << "=== Bytecode for" << _context->name << "strict mode" << _context->isStrict
@@ -3203,11 +3202,13 @@ bool Codegen::visit(DoWhileStatement *ast)
cond.link();
if (AST::cast<TrueLiteral *>(ast->expression)) {
// do {} while (true) -> just jump back to the loop body, no need to generate a condition
+ bytecodeGenerator->checkException();
bytecodeGenerator->jump().link(body);
} else if (AST::cast<FalseLiteral *>(ast->expression)) {
// do {} while (false) -> fall through, no need to generate a condition
} else {
TailCallBlocker blockTailCalls(this);
+ bytecodeGenerator->checkException();
condition(ast->expression, &body, &end, false);
}
@@ -3288,7 +3289,7 @@ bool Codegen::visit(ForEachStatement *ast)
next.value = lhsValue.stackSlot();
next.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(next);
- bytecodeGenerator->addTracingJumpInstruction(Instruction::JumpTrue()).link(end);
+ bytecodeGenerator->addJumpInstruction(Instruction::JumpTrue()).link(end);
// each iteration gets it's own context, as per spec
{
@@ -3324,6 +3325,7 @@ bool Codegen::visit(ForEachStatement *ast)
setJumpOutLocation(bytecodeGenerator, ast->statement, ast->forToken);
}
+ bytecodeGenerator->checkException();
bytecodeGenerator->jump().link(in);
error:
@@ -3372,6 +3374,7 @@ bool Codegen::visit(ForStatement *ast)
bytecodeGenerator->addInstruction(clone);
}
statement(ast->expression);
+ bytecodeGenerator->checkException();
bytecodeGenerator->jump().link(cond);
end.link();
@@ -3654,6 +3657,8 @@ bool Codegen::visit(WhileStatement *ast)
ControlFlowLoop flow(this, &end, &cond);
bytecodeGenerator->addLoopStart(cond);
+ bytecodeGenerator->checkException();
+
if (!AST::cast<TrueLiteral *>(ast->expression)) {
TailCallBlocker blockTailCalls(this);
condition(ast->expression, &start, &end, true);
@@ -4225,7 +4230,7 @@ void Codegen::Reference::storeAccumulator() const
Instruction::StoreElement store;
store.base = elementBase;
store.index = elementSubscript.stackSlot();
- codegen->bytecodeGenerator->addTracingInstruction(store);
+ codegen->bytecodeGenerator->addInstruction(store);
} return;
case Invalid:
case Accumulator:
@@ -4315,12 +4320,12 @@ QT_WARNING_POP
if (!scope) {
Instruction::LoadLocal load;
load.index = index;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} else {
Instruction::LoadScopedLocal load;
load.index = index;
load.scope = scope;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
tdzCheck(requiresTDZCheck);
return;
@@ -4344,16 +4349,16 @@ QT_WARNING_POP
if (qmlGlobal) {
Instruction::LoadQmlContextPropertyLookup load;
load.index = codegen->registerQmlContextPropertyGetterLookup(nameAsIndex());
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} else {
Instruction::LoadGlobalLookup load;
load.index = codegen->registerGlobalGetterLookup(nameAsIndex());
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
} else {
Instruction::LoadName load;
load.name = nameAsIndex();
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
return;
case Member:
@@ -4362,11 +4367,11 @@ QT_WARNING_POP
if (!disable_lookups && codegen->useFastLookups) {
Instruction::GetLookup load;
load.index = codegen->registerGetterLookup(propertyNameIndex);
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} else {
Instruction::LoadProperty load;
load.name = propertyNameIndex;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
}
return;
case Import: {
@@ -4381,7 +4386,7 @@ QT_WARNING_POP
tdzCheck(subscriptRequiresTDZCheck);
Instruction::LoadElement load;
load.base = elementBase;
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ codegen->bytecodeGenerator->addInstruction(load);
} return;
case Invalid:
break;
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 4cfd2d86e8..dd7ba471c3 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -79,7 +79,7 @@ QT_BEGIN_NAMESPACE
// Also change the comment behind the number to describe the latest change. This has the added
// benefit that if another patch changes the version too, it will result in a merge conflict, and
// not get removed silently.
-#define QV4_DATA_STRUCTURE_VERSION 0x22 // Add trace slot to UPlus
+#define QV4_DATA_STRUCTURE_VERSION 0x23 // Remove trace slots
class QIODevice;
class QQmlPropertyData;
@@ -296,10 +296,6 @@ struct Function
quint32_le nLabelInfos;
size_t labelInfosOffset() const { return lineNumberOffset() + nLineNumbers * sizeof(CodeOffsetToLine); }
- typedef quint16_le TraceInfoCount;
- TraceInfoCount nTraceInfos;
- static constexpr TraceInfoCount NoTracing() { return TraceInfoCount::max(); }
-
// Keep all unaligned data at the end
quint8 flags;
quint8 padding1;
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 01c033cb2a..123d77f788 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -424,7 +424,6 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
Q_ASSERT(function->lineNumberOffset() == currentOffset);
currentOffset += function->nLineNumbers * sizeof(CompiledData::CodeOffsetToLine);
- function->nTraceInfos = irFunction->nTraceInfos;
function->nRegisters = irFunction->registerCountInFunction;
if (!irFunction->labelInfo.empty()) {
diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp
index 52215c2ce6..d1a5fee92b 100644
--- a/src/qml/compiler/qv4compilercontext.cpp
+++ b/src/qml/compiler/qv4compilercontext.cpp
@@ -410,26 +410,4 @@ void Context::setupFunctionIndices(Moth::BytecodeGenerator *bytecodeGenerator)
nRegisters = bytecodeGenerator->currentRegister() - registerOffset;
}
-bool Context::canUseTracingJit() const
-{
-#if QT_CONFIG(qml_tracing)
- static bool forceTracing = !qEnvironmentVariableIsEmpty("QV4_FORCE_TRACING");
- if (forceTracing) //### we can probably remove this when tracing is turned on by default
- return true; // to be used by unittests
-
- static bool disableTracing = !qEnvironmentVariableIsEmpty("QV4_DISABLE_TRACING");
- if (disableTracing)
- return false;
-
- static QStringList onlyTrace =
- qEnvironmentVariable("QV4_ONLY_TRACE").split(QLatin1Char(','), QString::SkipEmptyParts);
- if (!onlyTrace.isEmpty())
- return onlyTrace.contains(name);
-
- return true;
-#else
- return false;
-#endif
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h
index 57ef4be36e..f56942fffa 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -162,7 +162,6 @@ struct Context {
int line = 0;
int column = 0;
int registerCountInFunction = 0;
- uint nTraceInfos = 0;
int functionIndex = -1;
int blockIndex = -1;
@@ -363,8 +362,6 @@ struct Context {
return parent->canHaveTailCalls();
return false;
}
-
- bool canUseTracingJit() const;
};
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index b019f191fa..5148154a6a 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -171,8 +171,6 @@ QString dumpArguments(int argc, int argv, int nFormals)
return QStringLiteral("(") + dumpRegister(argv, nFormals) + QStringLiteral(", ") + QString::number(argc) + QStringLiteral(")");
}
-#define TRACE_SLOT QStringLiteral(" {%1}").arg(traceSlot)
-
void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*startLine*/, const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping)
{
MOTH_JUMP_TABLE;
@@ -241,9 +239,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_BEGIN_INSTR(LoadLocal)
if (index < nLocals)
- d << "l" << index << TRACE_SLOT;
+ d << "l" << index;
else
- d << "a" << (index - nLocals) << TRACE_SLOT;
+ d << "a" << (index - nLocals);
MOTH_END_INSTR(LoadLocal)
MOTH_BEGIN_INSTR(StoreLocal)
@@ -255,9 +253,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_BEGIN_INSTR(LoadScopedLocal)
if (index < nLocals)
- d << "l" << index << "@" << scope << TRACE_SLOT;
+ d << "l" << index << "@" << scope;
else
- d << "a" << (index - nLocals) << "@" << scope << TRACE_SLOT;
+ d << "a" << (index - nLocals) << "@" << scope;
MOTH_END_INSTR(LoadScopedLocal)
MOTH_BEGIN_INSTR(StoreScopedLocal)
@@ -280,15 +278,15 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(LoadClosure)
MOTH_BEGIN_INSTR(LoadName)
- d << name << TRACE_SLOT;
+ d << name;
MOTH_END_INSTR(LoadName)
MOTH_BEGIN_INSTR(LoadGlobalLookup)
- d << index << TRACE_SLOT;
+ d << index;
MOTH_END_INSTR(LoadGlobalLookup)
MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup)
- d << index << TRACE_SLOT;
+ d << index;
MOTH_END_INSTR(LoadQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(StoreNameSloppy)
@@ -300,20 +298,19 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(StoreNameStrict)
MOTH_BEGIN_INSTR(LoadElement)
- d << dumpRegister(base, nFormals) << "[acc]" << TRACE_SLOT;
+ d << dumpRegister(base, nFormals) << "[acc]";
MOTH_END_INSTR(LoadElement)
MOTH_BEGIN_INSTR(StoreElement)
- d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]"
- << TRACE_SLOT;
+ d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]";
MOTH_END_INSTR(StoreElement)
MOTH_BEGIN_INSTR(LoadProperty)
- d << "acc[" << name << "]" << TRACE_SLOT;
+ d << "acc[" << name << "]";
MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(GetLookup)
- d << "acc(" << index << ")" << TRACE_SLOT;
+ d << "acc(" << index << ")";
MOTH_END_INSTR(GetLookup)
MOTH_BEGIN_INSTR(StoreProperty)
@@ -343,49 +340,48 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Resume)
MOTH_BEGIN_INSTR(CallValue)
- d << dumpRegister(name, nFormals) << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << dumpRegister(name, nFormals) << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallWithReceiver)
d << dumpRegister(name, nFormals) << dumpRegister(thisObject, nFormals)
- << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallWithReceiver)
MOTH_BEGIN_INSTR(CallProperty)
d << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals)
- << TRACE_SLOT;
+ ;
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
d << dumpRegister(base, nFormals) << "." << lookupIndex
- << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallPropertyLookup)
MOTH_BEGIN_INSTR(CallElement)
d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]"
- << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallElement)
MOTH_BEGIN_INSTR(CallName)
- d << name << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << name << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallName)
MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
- d << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallPossiblyDirectEval)
MOTH_BEGIN_INSTR(CallGlobalLookup)
- d << index << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << index << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallGlobalLookup)
MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
- d << index << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ d << index << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(CallWithSpread)
d << "new " << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals)
- << dumpArguments(argc, argv, nFormals)
- << TRACE_SLOT;
+ << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallWithSpread)
MOTH_BEGIN_INSTR(Construct)
@@ -528,11 +524,11 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Jump)
MOTH_BEGIN_INSTR(JumpTrue)
- d << ABSOLUTE_OFFSET() << TRACE_SLOT;
+ d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpTrue)
MOTH_BEGIN_INSTR(JumpFalse)
- d << ABSOLUTE_OFFSET() << TRACE_SLOT;
+ d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpFalse)
MOTH_BEGIN_INSTR(JumpNotUndefined)
@@ -543,6 +539,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpNoException)
+ MOTH_BEGIN_INSTR(CheckException)
+ MOTH_END_INSTR(CheckException)
+
MOTH_BEGIN_INSTR(CmpEqNull)
MOTH_END_INSTR(CmpEqNull)
@@ -593,26 +592,22 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(UNot)
MOTH_BEGIN_INSTR(UPlus)
- d << TRACE_SLOT;
MOTH_END_INSTR(UPlus)
MOTH_BEGIN_INSTR(UMinus)
- d << TRACE_SLOT;
MOTH_END_INSTR(UMinus)
MOTH_BEGIN_INSTR(UCompl)
MOTH_END_INSTR(UCompl)
MOTH_BEGIN_INSTR(Increment)
- d << TRACE_SLOT;
MOTH_END_INSTR(Increment)
MOTH_BEGIN_INSTR(Decrement)
- d << TRACE_SLOT;
MOTH_END_INSTR(Decrement)
MOTH_BEGIN_INSTR(Add)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Add)
MOTH_BEGIN_INSTR(BitAnd)
@@ -668,7 +663,7 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Exp)
MOTH_BEGIN_INSTR(Mul)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Mul)
MOTH_BEGIN_INSTR(Div)
@@ -676,11 +671,11 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Div)
MOTH_BEGIN_INSTR(Mod)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Mod)
MOTH_BEGIN_INSTR(Sub)
- d << dumpRegister(lhs, nFormals) << ", acc" << TRACE_SLOT;
+ d << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Sub)
MOTH_BEGIN_INSTR(CmpIn)
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 6a8c9a9549..35a5fdfba5 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -77,20 +77,20 @@ QT_BEGIN_NAMESPACE
#define INSTR_StoreReg(op) INSTRUCTION(op, StoreReg, 1, reg)
#define INSTR_MoveReg(op) INSTRUCTION(op, MoveReg, 2, srcReg, destReg)
#define INSTR_LoadImport(op) INSTRUCTION(op, LoadImport, 1, index)
-#define INSTR_LoadLocal(op) INSTRUCTION(op, LoadLocal, 2, index, traceSlot)
+#define INSTR_LoadLocal(op) INSTRUCTION(op, LoadLocal, 1, index)
#define INSTR_StoreLocal(op) INSTRUCTION(op, StoreLocal, 1, index)
-#define INSTR_LoadScopedLocal(op) INSTRUCTION(op, LoadScopedLocal, 3, scope, index, traceSlot)
+#define INSTR_LoadScopedLocal(op) INSTRUCTION(op, LoadScopedLocal, 2, scope, index)
#define INSTR_StoreScopedLocal(op) INSTRUCTION(op, StoreScopedLocal, 2, scope, index)
#define INSTR_LoadRuntimeString(op) INSTRUCTION(op, LoadRuntimeString, 1, stringId)
#define INSTR_MoveRegExp(op) INSTRUCTION(op, MoveRegExp, 2, regExpId, destReg)
#define INSTR_LoadClosure(op) INSTRUCTION(op, LoadClosure, 1, value)
-#define INSTR_LoadName(op) INSTRUCTION(op, LoadName, 2, name, traceSlot)
-#define INSTR_LoadGlobalLookup(op) INSTRUCTION(op, LoadGlobalLookup, 2, index, traceSlot)
-#define INSTR_LoadQmlContextPropertyLookup(op) INSTRUCTION(op, LoadQmlContextPropertyLookup, 2, index, traceSlot)
+#define INSTR_LoadName(op) INSTRUCTION(op, LoadName, 1, name)
+#define INSTR_LoadGlobalLookup(op) INSTRUCTION(op, LoadGlobalLookup, 1, index)
+#define INSTR_LoadQmlContextPropertyLookup(op) INSTRUCTION(op, LoadQmlContextPropertyLookup, 1, index)
#define INSTR_StoreNameSloppy(op) INSTRUCTION(op, StoreNameSloppy, 1, name)
#define INSTR_StoreNameStrict(op) INSTRUCTION(op, StoreNameStrict, 1, name)
-#define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 2, name, traceSlot)
-#define INSTR_GetLookup(op) INSTRUCTION(op, GetLookup, 2, index, traceSlot)
+#define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 1, name)
+#define INSTR_GetLookup(op) INSTRUCTION(op, GetLookup, 1, index)
#define INSTR_LoadIdObject(op) INSTRUCTION(op, LoadIdObject, 2, index, base)
#define INSTR_Yield(op) INSTRUCTION(op, Yield, 0)
#define INSTR_YieldStar(op) INSTRUCTION(op, YieldStar, 0)
@@ -100,18 +100,18 @@ QT_BEGIN_NAMESPACE
#define INSTR_SetLookup(op) INSTRUCTION(op, SetLookup, 2, index, base)
#define INSTR_LoadSuperProperty(op) INSTRUCTION(op, LoadSuperProperty, 1, property)
#define INSTR_StoreSuperProperty(op) INSTRUCTION(op, StoreSuperProperty, 1, property)
-#define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 2, base, traceSlot)
-#define INSTR_StoreElement(op) INSTRUCTION(op, StoreElement, 3, base, index, traceSlot)
-#define INSTR_CallValue(op) INSTRUCTION(op, CallValue, 4, name, argc, argv, traceSlot)
-#define INSTR_CallWithReceiver(op) INSTRUCTION(op, CallWithReceiver, 5, name, thisObject, argc, argv, traceSlot)
-#define INSTR_CallProperty(op) INSTRUCTION(op, CallProperty, 5, name, base, argc, argv, traceSlot)
-#define INSTR_CallPropertyLookup(op) INSTRUCTION(op, CallPropertyLookup, 5, lookupIndex, base, argc, argv, traceSlot)
-#define INSTR_CallElement(op) INSTRUCTION(op, CallElement, 5, base, index, argc, argv, traceSlot)
-#define INSTR_CallName(op) INSTRUCTION(op, CallName, 4, name, argc, argv, traceSlot)
-#define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 3, argc, argv, traceSlot)
-#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 4, index, argc, argv, traceSlot)
-#define INSTR_CallQmlContextPropertyLookup(op) INSTRUCTION(op, CallQmlContextPropertyLookup, 4, index, argc, argv, traceSlot)
-#define INSTR_CallWithSpread(op) INSTRUCTION(op, CallWithSpread, 5, func, thisObject, argc, argv, traceSlot)
+#define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 1, base)
+#define INSTR_StoreElement(op) INSTRUCTION(op, StoreElement, 2, base, index)
+#define INSTR_CallValue(op) INSTRUCTION(op, CallValue, 3, name, argc, argv)
+#define INSTR_CallWithReceiver(op) INSTRUCTION(op, CallWithReceiver, 4, name, thisObject, argc, argv)
+#define INSTR_CallProperty(op) INSTRUCTION(op, CallProperty, 4, name, base, argc, argv)
+#define INSTR_CallPropertyLookup(op) INSTRUCTION(op, CallPropertyLookup, 4, lookupIndex, base, argc, argv)
+#define INSTR_CallElement(op) INSTRUCTION(op, CallElement, 4, base, index, argc, argv)
+#define INSTR_CallName(op) INSTRUCTION(op, CallName, 3, name, argc, argv)
+#define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 2, argc, argv)
+#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 3, index, argc, argv)
+#define INSTR_CallQmlContextPropertyLookup(op) INSTRUCTION(op, CallQmlContextPropertyLookup, 3, index, argc, argv)
+#define INSTR_CallWithSpread(op) INSTRUCTION(op, CallWithSpread, 4, func, thisObject, argc, argv)
#define INSTR_Construct(op) INSTRUCTION(op, Construct, 3, func, argc, argv)
#define INSTR_ConstructWithSpread(op) INSTRUCTION(op, ConstructWithSpread, 3, func, argc, argv)
#define INSTR_SetUnwindHandler(op) INSTRUCTION(op, SetUnwindHandler, 1, offset)
@@ -148,10 +148,11 @@ QT_BEGIN_NAMESPACE
#define INSTR_LoadSuperConstructor(op) INSTRUCTION(op, LoadSuperConstructor, 0)
#define INSTR_ToObject(op) INSTRUCTION(op, ToObject, 0)
#define INSTR_Jump(op) INSTRUCTION(op, Jump, 1, offset)
-#define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 2, traceSlot, offset)
-#define INSTR_JumpFalse(op) INSTRUCTION(op, JumpFalse, 2, traceSlot, offset)
+#define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 1, offset)
+#define INSTR_JumpFalse(op) INSTRUCTION(op, JumpFalse, 1, offset)
#define INSTR_JumpNotUndefined(op) INSTRUCTION(op, JumpNotUndefined, 1, offset)
#define INSTR_JumpNoException(op) INSTRUCTION(op, JumpNoException, 1, offset)
+#define INSTR_CheckException(op) INSTRUCTION(op, CheckException, 0)
#define INSTR_CmpEqNull(op) INSTRUCTION(op, CmpEqNull, 0)
#define INSTR_CmpNeNull(op) INSTRUCTION(op, CmpNeNull, 0)
#define INSTR_CmpEqInt(op) INSTRUCTION(op, CmpEqInt, 1, lhs)
@@ -167,12 +168,12 @@ QT_BEGIN_NAMESPACE
#define INSTR_CmpIn(op) INSTRUCTION(op, CmpIn, 1, lhs)
#define INSTR_CmpInstanceOf(op) INSTRUCTION(op, CmpInstanceOf, 1, lhs)
#define INSTR_UNot(op) INSTRUCTION(op, UNot, 0)
-#define INSTR_UPlus(op) INSTRUCTION(op, UPlus, 1, traceSlot)
-#define INSTR_UMinus(op) INSTRUCTION(op, UMinus, 1, traceSlot)
+#define INSTR_UPlus(op) INSTRUCTION(op, UPlus, 0)
+#define INSTR_UMinus(op) INSTRUCTION(op, UMinus, 0)
#define INSTR_UCompl(op) INSTRUCTION(op, UCompl, 0)
-#define INSTR_Increment(op) INSTRUCTION(op, Increment, 1, traceSlot)
-#define INSTR_Decrement(op) INSTRUCTION(op, Decrement, 1, traceSlot)
-#define INSTR_Add(op) INSTRUCTION(op, Add, 2, lhs, traceSlot)
+#define INSTR_Increment(op) INSTRUCTION(op, Increment, 0)
+#define INSTR_Decrement(op) INSTRUCTION(op, Decrement, 0)
+#define INSTR_Add(op) INSTRUCTION(op, Add, 1, lhs)
#define INSTR_BitAnd(op) INSTRUCTION(op, BitAnd, 1, lhs)
#define INSTR_BitOr(op) INSTRUCTION(op, BitOr, 1, lhs)
#define INSTR_BitXor(op) INSTRUCTION(op, BitXor, 1, lhs)
@@ -186,10 +187,10 @@ QT_BEGIN_NAMESPACE
#define INSTR_ShrConst(op) INSTRUCTION(op, ShrConst, 1, rhs)
#define INSTR_ShlConst(op) INSTRUCTION(op, ShlConst, 1, rhs)
#define INSTR_Exp(op) INSTRUCTION(op, Exp, 1, lhs)
-#define INSTR_Mul(op) INSTRUCTION(op, Mul, 2, lhs, traceSlot)
+#define INSTR_Mul(op) INSTRUCTION(op, Mul, 1, lhs)
#define INSTR_Div(op) INSTRUCTION(op, Div, 1, lhs)
-#define INSTR_Mod(op) INSTRUCTION(op, Mod, 2, lhs, traceSlot)
-#define INSTR_Sub(op) INSTRUCTION(op, Sub, 2, lhs, traceSlot)
+#define INSTR_Mod(op) INSTRUCTION(op, Mod, 1, lhs)
+#define INSTR_Sub(op) INSTRUCTION(op, Sub, 1, lhs)
#define INSTR_LoadQmlImportedScripts(op) INSTRUCTION(op, LoadQmlImportedScripts, 1, result)
#define INSTR_InitializeBlockDeadTemporalZone(op) INSTRUCTION(op, InitializeBlockDeadTemporalZone, 2, firstReg, count)
#define INSTR_ThrowOnNullOrUndefined(op) INSTRUCTION(op, ThrowOnNullOrUndefined, 0)
@@ -241,6 +242,7 @@ QT_BEGIN_NAMESPACE
F(JumpFalse) \
F(JumpNoException) \
F(JumpNotUndefined) \
+ F(CheckException) \
F(CmpEqNull) \
F(CmpNeNull) \
F(CmpEqInt) \
diff --git a/src/qml/configure.json b/src/qml/configure.json
index c35f5be06b..2f88aef1fb 100644
--- a/src/qml/configure.json
+++ b/src/qml/configure.json
@@ -8,7 +8,6 @@
"commandline": {
"options": {
"qml-network": "boolean",
- "qml-tracing": "boolean",
"qml-debug": "boolean"
}
},
@@ -24,6 +23,52 @@
],
"qmake": "CONFIG += c++11"
}
+ },
+ "pointer_32bit": {
+ "label": "32bit pointers",
+ "type": "compile",
+ "test": {
+ "main": "static_assert(sizeof(void *) == 4, \"fail\");"
+ }
+ },
+ "pointer_64bit": {
+ "label": "64bit pointers",
+ "type": "compile",
+ "test": {
+ "main": "static_assert(sizeof(void *) == 8, \"fail\");"
+ }
+ },
+ "arm_thumb": {
+ "label": "THUMB mode on ARM",
+ "type": "compile",
+ "test": {
+ "main": [
+ "#if defined(thumb2) || defined(__thumb2__)",
+ "# define THUMB_OK",
+ "#elif (defined(__thumb) || defined(__thumb__)) && __TARGET_ARCH_THUMB-0 == 4",
+ "# define THUMB_OK",
+ "#elif defined(__ARM_ARCH_ISA_THUMB) && __ARM_ARCH_ISA_THUMB == 2",
+ "// clang 3.5 and later will set this if the core supports the Thumb-2 ISA.",
+ "# define THUMB_OK",
+ "#else",
+ "# error \"fail\"",
+ "#endif"
+ ]
+ }
+ },
+ "arm_fp": {
+ "label": "Sufficiently recent FPU on ARM",
+ "type": "compile",
+ "test": {
+ "main": [
+ "// if !defined(__ARM_FP) we might be on MSVC or we might have a device",
+ "// without an FPU.",
+ "// TODO: The latter case is not supported, but the test still succeeds.",
+ "#if defined(__ARM_FP) && (__ARM_FP <= 0x04)",
+ "# error \"fail\"",
+ "#endif"
+ ]
+ }
}
},
@@ -40,12 +85,26 @@
"condition": "features.network",
"output": [ "publicFeature" ]
},
- "qml-tracing": {
- "label": "QML tracing JIT support",
- "purpose": "Provides a JIT that uses trace information generated by the interpreter.",
+ "qml-jit": {
+ "label": "QML just-in-time compiler",
+ "purpose": "Provides a JIT for QML and JavaScript",
"section": "QML",
+ "condition": [
+ " (arch.i386 && tests.pointer_32bit)
+ || (arch.x86_64 && tests.pointer_64bit)
+ || (arch.arm && tests.pointer_32bit && tests.arm_fp && tests.arm_thumb
+ && (config.linux || config.ios || config.tvos || config.qnx))
+ || (arch.arm64 && tests.pointer_64bit && tests.arm_fp
+ && (config.linux || config.ios || config.tvos || config.qnx || config.integrity))"
+ ],
"output": [ "privateFeature" ],
- "autoDetect": false
+ "autoDetect": "!config.ios && !config.tvos",
+ "comment": "On arm and arm64 we need a specialization of cacheFlush() for each OS to be
+ enabeled. Therefore the config white list.
+ Also Mind that e.g. x86_32 has arch.x86_64 but 32bit pointers. Therefore
+ the checks for architecture and pointer size.
+ Finally, ios and tvos can technically use the JIT but Apple does not allow
+ it. Therefore, it's disabled by default."
},
"qml-debug": {
"label": "QML debugging and profiling support",
@@ -90,12 +149,6 @@
"section": "QML",
"output": [ "privateFeature" ]
},
- "qml-list-model": {
- "label": "QML list model",
- "purpose": "Provides the ListModel QML type.",
- "section": "QML",
- "output": [ "privateFeature" ]
- },
"qml-xml-http-request": {
"label": "QML XML http request",
"purpose": "Provides support for sending XML http requests.",
@@ -119,12 +172,6 @@
"condition": "features.animation",
"output": [ "privateFeature" ]
},
- "qml-delegate-model": {
- "label": "QML delegate model",
- "purpose": "Provides the DelegateModel QML type.",
- "section": "QML",
- "output": [ "privateFeature" ]
- },
"qml-worker-script": {
"label": "QML WorkerScript",
"purpose": "Enables the use of threads in QML.",
@@ -140,12 +187,10 @@
"entries": [
"qml-network",
"qml-debug",
- "qml-tracing",
+ "qml-jit",
"qml-sequence-object",
- "qml-list-model",
"qml-xml-http-request",
- "qml-locale",
- "qml-delegate-model"
+ "qml-locale"
]
}
]
diff --git a/src/qml/jit/jit.pri b/src/qml/jit/jit.pri
index bc0d20dba7..503ce0ebcd 100644
--- a/src/qml/jit/jit.pri
+++ b/src/qml/jit/jit.pri
@@ -10,34 +10,3 @@ HEADERS += \
$$PWD/qv4baselinejit_p.h \
$$PWD/qv4baselineassembler_p.h \
$$PWD/qv4assemblercommon_p.h
-
-qtConfig(qml-tracing) {
-SOURCES += \
- $$PWD/qv4ir.cpp \
- $$PWD/qv4operation.cpp \
- $$PWD/qv4node.cpp \
- $$PWD/qv4graph.cpp \
- $$PWD/qv4graphbuilder.cpp \
- $$PWD/qv4lowering.cpp \
- $$PWD/qv4tracingjit.cpp \
- $$PWD/qv4mi.cpp \
- $$PWD/qv4domtree.cpp \
- $$PWD/qv4schedulers.cpp \
- $$PWD/qv4blockscheduler.cpp \
- $$PWD/qv4loopinfo.cpp
-
-HEADERS += \
- $$PWD/qv4ir_p.h \
- $$PWD/qv4operation_p.h \
- $$PWD/qv4runtimesupport_p.h \
- $$PWD/qv4node_p.h \
- $$PWD/qv4graph_p.h \
- $$PWD/qv4graphbuilder_p.h \
- $$PWD/qv4lowering_p.h \
- $$PWD/qv4mi_p.h \
- $$PWD/qv4miblockset_p.h \
- $$PWD/qv4domtree_p.h \
- $$PWD/qv4schedulers_p.h \
- $$PWD/qv4blockscheduler_p.h \
- $$PWD/qv4loopinfo_p.h
-}
diff --git a/src/qml/jit/qv4assemblercommon.cpp b/src/qml/jit/qv4assemblercommon.cpp
index dd810d9d70..800ee22cd7 100644
--- a/src/qml/jit/qv4assemblercommon.cpp
+++ b/src/qml/jit/qv4assemblercommon.cpp
@@ -53,8 +53,6 @@
#undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES
-#ifdef V4_ENABLE_JIT
-
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
@@ -366,5 +364,3 @@ void PlatformAssemblerCommon::storeInt32AsValue(int srcInt, Address destAddr)
} // QV4 namepsace
QT_END_NAMESPACE
-
-#endif // V4_ENABLE_JIT
diff --git a/src/qml/jit/qv4assemblercommon_p.h b/src/qml/jit/qv4assemblercommon_p.h
index d3d7eedae2..f305213ce2 100644
--- a/src/qml/jit/qv4assemblercommon_p.h
+++ b/src/qml/jit/qv4assemblercommon_p.h
@@ -58,7 +58,7 @@
#include <wtf/Vector.h>
#include <assembler/MacroAssembler.h>
-#ifdef V4_ENABLE_JIT
+QT_REQUIRE_CONFIG(qml_jit);
QT_BEGIN_NAMESPACE
@@ -619,6 +619,9 @@ public:
for (Jump j : catchyJumps)
j.link(this);
+ // We don't need to check for isInterrupted here because if that is set,
+ // then the first checkException() in any exception handler will find another "exception"
+ // and jump out of the exception handler.
loadPtr(exceptionHandlerAddress(), ScratchRegister);
Jump exitFunction = branchPtr(Equal, ScratchRegister, TrustedImmPtr(0));
jump(ScratchRegister);
@@ -633,6 +636,8 @@ public:
void checkException()
{
+ // This actually reads 4 bytes, starting at hasException.
+ // Therefore, it also reads the isInterrupted flag, and triggers an exception on that.
addCatchyJump(
branch32(NotEqual,
Address(EngineRegister, offsetof(EngineBase, hasException)),
@@ -735,6 +740,4 @@ private:
QT_END_NAMESPACE
-#endif // V4_ENABLE_JIT
-
#endif // QV4PLATFORMASSEMBLER_P_H
diff --git a/src/qml/jit/qv4baselineassembler.cpp b/src/qml/jit/qv4baselineassembler.cpp
index 238c11f478..5e34087ff5 100644
--- a/src/qml/jit/qv4baselineassembler.cpp
+++ b/src/qml/jit/qv4baselineassembler.cpp
@@ -55,8 +55,6 @@
#undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES
-#ifdef V4_ENABLE_JIT
-
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
@@ -1620,5 +1618,3 @@ void BaselineAssembler::ret()
} // QV4 namepsace
QT_END_NAMESPACE
-
-#endif // V4_ENABLE_JIT
diff --git a/src/qml/jit/qv4baselineassembler_p.h b/src/qml/jit/qv4baselineassembler_p.h
index 3bbaefd000..5e5d9d0672 100644
--- a/src/qml/jit/qv4baselineassembler_p.h
+++ b/src/qml/jit/qv4baselineassembler_p.h
@@ -55,6 +55,8 @@
#include <private/qv4function_p.h>
#include <QHash>
+QT_REQUIRE_CONFIG(qml_jit);
+
QT_BEGIN_NAMESPACE
namespace QV4 {
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index 80155d7b20..f4807f1917 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -42,8 +42,6 @@
#include <private/qv4lookup_p.h>
#include <private/qv4generatorobject_p.h>
-#ifdef V4_ENABLE_JIT
-
QT_USE_NAMESPACE
using namespace QV4;
using namespace QV4::JIT;
@@ -151,7 +149,7 @@ void BaselineJIT::generate_LoadImport(int index)
as->loadImport(index);
}
-void BaselineJIT::generate_LoadLocal(int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadLocal(int index)
{
as->loadLocal(index);
}
@@ -162,7 +160,7 @@ void BaselineJIT::generate_StoreLocal(int index)
as->storeLocal(index);
}
-void BaselineJIT::generate_LoadScopedLocal(int scope, int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadScopedLocal(int scope, int index)
{
as->loadLocal(index, scope);
}
@@ -195,7 +193,7 @@ void BaselineJIT::generate_LoadClosure(int value)
BASELINEJIT_GENERATE_RUNTIME_CALL(Closure, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_LoadName(int name, int /*traceSlot*/)
+void BaselineJIT::generate_LoadName(int name)
{
STORE_IP();
as->prepareCallWithArgCount(2);
@@ -204,7 +202,7 @@ void BaselineJIT::generate_LoadName(int name, int /*traceSlot*/)
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadName, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_LoadGlobalLookup(int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadGlobalLookup(int index)
{
as->prepareCallWithArgCount(3);
as->passInt32AsArg(index, 2);
@@ -213,7 +211,7 @@ void BaselineJIT::generate_LoadGlobalLookup(int index, int /*traceSlot*/)
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadGlobalLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_LoadQmlContextPropertyLookup(int index, int /*traceSlot*/)
+void BaselineJIT::generate_LoadQmlContextPropertyLookup(int index)
{
as->prepareCallWithArgCount(2);
as->passInt32AsArg(index, 1);
@@ -243,7 +241,7 @@ void BaselineJIT::generate_StoreNameStrict(int name)
BASELINEJIT_GENERATE_RUNTIME_CALL(StoreNameStrict, CallResultDestination::Ignore);
}
-void BaselineJIT::generate_LoadElement(int base, int /*traceSlot*/)
+void BaselineJIT::generate_LoadElement(int base)
{
STORE_IP();
STORE_ACC();
@@ -254,7 +252,7 @@ void BaselineJIT::generate_LoadElement(int base, int /*traceSlot*/)
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadElement, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_StoreElement(int base, int index, int /*traceSlot*/)
+void BaselineJIT::generate_StoreElement(int base, int index)
{
STORE_IP();
STORE_ACC();
@@ -266,7 +264,7 @@ void BaselineJIT::generate_StoreElement(int base, int index, int /*traceSlot*/)
BASELINEJIT_GENERATE_RUNTIME_CALL(StoreElement, CallResultDestination::Ignore);
}
-void BaselineJIT::generate_LoadProperty(int name, int /*traceSlot*/)
+void BaselineJIT::generate_LoadProperty(int name)
{
STORE_IP();
STORE_ACC();
@@ -277,7 +275,7 @@ void BaselineJIT::generate_LoadProperty(int name, int /*traceSlot*/)
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadProperty, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_GetLookup(int index, int /*traceSlot*/)
+void BaselineJIT::generate_GetLookup(int index)
{
STORE_IP();
STORE_ACC();
@@ -355,7 +353,7 @@ void BaselineJIT::generate_Resume(int)
Q_UNREACHABLE();
}
-void BaselineJIT::generate_CallValue(int name, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallValue(int name, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -366,7 +364,7 @@ void BaselineJIT::generate_CallValue(int name, int argc, int argv, int /*traceSl
BASELINEJIT_GENERATE_RUNTIME_CALL(CallValue, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -378,7 +376,7 @@ void BaselineJIT::generate_CallWithReceiver(int name, int thisObject, int argc,
BASELINEJIT_GENERATE_RUNTIME_CALL(CallWithReceiver, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -390,7 +388,7 @@ void BaselineJIT::generate_CallProperty(int name, int base, int argc, int argv,
BASELINEJIT_GENERATE_RUNTIME_CALL(CallProperty, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -402,7 +400,7 @@ void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int arg
BASELINEJIT_GENERATE_RUNTIME_CALL(CallPropertyLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -414,7 +412,7 @@ void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv,
BASELINEJIT_GENERATE_RUNTIME_CALL(CallElement, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallName(int name, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallName(int name, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -425,7 +423,7 @@ void BaselineJIT::generate_CallName(int name, int argc, int argv, int /*traceSlo
BASELINEJIT_GENERATE_RUNTIME_CALL(CallName, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallPossiblyDirectEval(int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallPossiblyDirectEval(int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(3);
@@ -435,7 +433,7 @@ void BaselineJIT::generate_CallPossiblyDirectEval(int argc, int argv, int /*trac
BASELINEJIT_GENERATE_RUNTIME_CALL(CallPossiblyDirectEval, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -446,8 +444,7 @@ void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv, int /
BASELINEJIT_GENERATE_RUNTIME_CALL(CallGlobalLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int argv,
- int /*traceSlot*/)
+void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(4);
@@ -458,7 +455,7 @@ void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int
BASELINEJIT_GENERATE_RUNTIME_CALL(CallQmlContextPropertyLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv)
{
STORE_IP();
as->prepareCallWithArgCount(5);
@@ -777,12 +774,12 @@ void BaselineJIT::generate_Jump(int offset)
labels.insert(as->jump(absoluteOffset(offset)));
}
-void BaselineJIT::generate_JumpTrue(int /*traceSlot*/, int offset)
+void BaselineJIT::generate_JumpTrue(int offset)
{
labels.insert(as->jumpTrue(absoluteOffset(offset)));
}
-void BaselineJIT::generate_JumpFalse(int /*traceSlot*/, int offset)
+void BaselineJIT::generate_JumpFalse(int offset)
{
labels.insert(as->jumpFalse(absoluteOffset(offset)));
}
@@ -797,6 +794,11 @@ void BaselineJIT::generate_JumpNotUndefined(int offset)
labels.insert(as->jumpNotUndefined(absoluteOffset(offset)));
}
+void BaselineJIT::generate_CheckException()
+{
+ as->checkException();
+}
+
void BaselineJIT::generate_CmpEqNull() { as->cmpeqNull(); }
void BaselineJIT::generate_CmpNeNull() { as->cmpneNull(); }
void BaselineJIT::generate_CmpEqInt(int lhs) { as->cmpeqInt(lhs); }
@@ -831,12 +833,12 @@ void BaselineJIT::generate_CmpInstanceOf(int lhs)
}
void BaselineJIT::generate_UNot() { as->unot(); }
-void BaselineJIT::generate_UPlus(int /*traceSlot*/) { as->toNumber(); }
-void BaselineJIT::generate_UMinus(int /*traceSlot*/) { as->uminus(); }
+void BaselineJIT::generate_UPlus() { as->toNumber(); }
+void BaselineJIT::generate_UMinus() { as->uminus(); }
void BaselineJIT::generate_UCompl() { as->ucompl(); }
-void BaselineJIT::generate_Increment(int /*traceSlot*/) { as->inc(); }
-void BaselineJIT::generate_Decrement(int /*traceSlot*/) { as->dec(); }
-void BaselineJIT::generate_Add(int lhs, int /*traceSlot*/) { as->add(lhs); }
+void BaselineJIT::generate_Increment() { as->inc(); }
+void BaselineJIT::generate_Decrement() { as->dec(); }
+void BaselineJIT::generate_Add(int lhs) { as->add(lhs); }
void BaselineJIT::generate_BitAnd(int lhs) { as->bitAnd(lhs); }
void BaselineJIT::generate_BitOr(int lhs) { as->bitOr(lhs); }
@@ -860,10 +862,10 @@ void BaselineJIT::generate_Exp(int lhs) {
as->passJSSlotAsArg(lhs, 0);
BASELINEJIT_GENERATE_RUNTIME_CALL(Exp, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_Mul(int lhs, int /*traceSlot*/) { as->mul(lhs); }
+void BaselineJIT::generate_Mul(int lhs) { as->mul(lhs); }
void BaselineJIT::generate_Div(int lhs) { as->div(lhs); }
-void BaselineJIT::generate_Mod(int lhs, int /*traceSlot*/) { as->mod(lhs); }
-void BaselineJIT::generate_Sub(int lhs, int /*traceSlot*/) { as->sub(lhs); }
+void BaselineJIT::generate_Mod(int lhs) { as->mod(lhs); }
+void BaselineJIT::generate_Sub(int lhs) { as->sub(lhs); }
//void BaselineJIT::generate_BinopContext(int alu, int lhs)
//{
@@ -913,5 +915,3 @@ void BaselineJIT::endInstruction(Instr::Type instr)
{
Q_UNUSED(instr);
}
-
-#endif // V4_ENABLE_JIT
diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h
index 37ab37eac2..284faf0ff0 100644
--- a/src/qml/jit/qv4baselinejit_p.h
+++ b/src/qml/jit/qv4baselinejit_p.h
@@ -56,7 +56,7 @@
#include <private/qv4instr_moth_p.h>
#include <private/qv4bytecodehandler_p.h>
-//QT_REQUIRE_CONFIG(qml_jit);
+QT_REQUIRE_CONFIG(qml_jit);
QT_BEGIN_NAMESPACE
@@ -65,7 +65,6 @@ namespace JIT {
class BaselineAssembler;
-#ifdef V4_ENABLE_JIT
class BaselineJIT final: public Moth::ByteCodeHandler
{
public:
@@ -88,22 +87,22 @@ public:
void generate_StoreReg(int reg) override;
void generate_MoveReg(int srcReg, int destReg) override;
void generate_LoadImport(int index) override;
- void generate_LoadLocal(int index, int traceSlot) override;
+ void generate_LoadLocal(int index) override;
void generate_StoreLocal(int index) override;
- void generate_LoadScopedLocal(int scope, int index, int traceSlot) override;
+ void generate_LoadScopedLocal(int scope, int index) override;
void generate_StoreScopedLocal(int scope, int index) override;
void generate_LoadRuntimeString(int stringId) override;
void generate_MoveRegExp(int regExpId, int destReg) override;
void generate_LoadClosure(int value) override;
- void generate_LoadName(int name, int traceSlot) override;
- void generate_LoadGlobalLookup(int index, int traceSlot) override;
- void generate_LoadQmlContextPropertyLookup(int index, int traceSlot) override;
+ void generate_LoadName(int name) override;
+ void generate_LoadGlobalLookup(int index) override;
+ void generate_LoadQmlContextPropertyLookup(int index) override;
void generate_StoreNameSloppy(int name) override;
void generate_StoreNameStrict(int name) override;
- void generate_LoadElement(int base, int traceSlot) override;
- void generate_StoreElement(int base, int index, int traceSlot) override;
- void generate_LoadProperty(int name, int traceSlot) override;
- void generate_GetLookup(int index, int traceSlot) override;
+ void generate_LoadElement(int base) override;
+ void generate_StoreElement(int base, int index) override;
+ void generate_LoadProperty(int name) override;
+ void generate_GetLookup(int index) override;
void generate_StoreProperty(int name, int base) override;
void generate_SetLookup(int index, int base) override;
void generate_LoadSuperProperty(int property) override;
@@ -112,16 +111,16 @@ public:
void generate_YieldStar() override;
void generate_Resume(int) override;
- void generate_CallValue(int name, int argc, int argv, int traceSlot) override;
- void generate_CallWithReceiver(int name, int thisObject, int argc, int argv, int traceSlot) override;
- void generate_CallProperty(int name, int base, int argc, int argv, int traceSlot) override;
- void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv, int traceSlot) override;
- void generate_CallElement(int base, int index, int argc, int argv, int traceSlot) override;
- void generate_CallName(int name, int argc, int argv, int traceSlot) override;
- void generate_CallPossiblyDirectEval(int argc, int argv, int traceSlot) override;
- void generate_CallGlobalLookup(int index, int argc, int argv, int traceSlot) override;
- void generate_CallQmlContextPropertyLookup(int index, int argc, int argv, int traceSlot) override;
- void generate_CallWithSpread(int func, int thisObject, int argc, int argv, int traceSlot) override;
+ void generate_CallValue(int name, int argc, int argv) override;
+ void generate_CallWithReceiver(int name, int thisObject, int argc, int argv) override;
+ void generate_CallProperty(int name, int base, int argc, int argv) override;
+ void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv) override;
+ void generate_CallElement(int base, int index, int argc, int argv) override;
+ void generate_CallName(int name, int argc, int argv) override;
+ void generate_CallPossiblyDirectEval(int argc, int argv) override;
+ void generate_CallGlobalLookup(int index, int argc, int argv) override;
+ void generate_CallQmlContextPropertyLookup(int index, int argc, int argv) override;
+ void generate_CallWithSpread(int func, int thisObject, int argc, int argv) override;
void generate_TailCall(int func, int thisObject, int argc, int argv) override;
void generate_Construct(int func, int argc, int argv) override;
void generate_ConstructWithSpread(int func, int argc, int argv) override;
@@ -160,10 +159,11 @@ public:
void generate_LoadSuperConstructor() override;
void generate_ToObject() override;
void generate_Jump(int offset) override;
- void generate_JumpTrue(int traceSlot, int offset) override;
- void generate_JumpFalse(int traceSlot, int offset) override;
+ void generate_JumpTrue(int offset) override;
+ void generate_JumpFalse(int offset) override;
void generate_JumpNoException(int offset) override;
void generate_JumpNotUndefined(int offset) override;
+ void generate_CheckException() override;
void generate_CmpEqNull() override;
void generate_CmpNeNull() override;
void generate_CmpEqInt(int lhs) override;
@@ -179,12 +179,12 @@ public:
void generate_CmpIn(int lhs) override;
void generate_CmpInstanceOf(int lhs) override;
void generate_UNot() override;
- void generate_UPlus(int) override;
- void generate_UMinus(int traceSlot) override;
+ void generate_UPlus() override;
+ void generate_UMinus() override;
void generate_UCompl() override;
- void generate_Increment(int traceSlot) override;
- void generate_Decrement(int traceSlot) override;
- void generate_Add(int lhs, int traceSlot) override;
+ void generate_Increment() override;
+ void generate_Decrement() override;
+ void generate_Add(int lhs) override;
void generate_BitAnd(int lhs) override;
void generate_BitOr(int lhs) override;
void generate_BitXor(int lhs) override;
@@ -198,10 +198,10 @@ public:
void generate_ShrConst(int rhs) override;
void generate_ShlConst(int rhs) override;
void generate_Exp(int lhs) override;
- void generate_Mul(int lhs, int traceSlot) override;
+ void generate_Mul(int lhs) override;
void generate_Div(int lhs) override;
- void generate_Mod(int lhs, int traceSlot) override;
- void generate_Sub(int lhs, int traceSlot) override;
+ void generate_Mod(int lhs) override;
+ void generate_Sub(int lhs) override;
void generate_InitializeBlockDeadTemporalZone(int firstReg, int count) override;
void generate_ThrowOnNullOrUndefined() override;
void generate_GetTemplateObject(int index) override;
@@ -214,7 +214,6 @@ private:
QScopedPointer<BaselineAssembler> as;
QSet<int> labels;
};
-#endif // V4_ENABLE_JIT
} // namespace JIT
} // namespace QV4
diff --git a/src/qml/jit/qv4blockscheduler.cpp b/src/qml/jit/qv4blockscheduler.cpp
deleted file mode 100644
index 3e2bfe15c5..0000000000
--- a/src/qml/jit/qv4blockscheduler.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-
-#include "qv4blockscheduler_p.h"
-#include "qv4domtree_p.h"
-#include "qv4loopinfo_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcBlockScheduler, "qt.v4.ir.blockscheduler")
-
-bool BlockScheduler::checkCandidate(MIBlock *candidate)
-{
- Q_ASSERT(loopInfo.loopHeaderFor(candidate) == currentGroup.group);
-
- for (MIBlock *pred : candidate->inEdges()) {
- if (pred->isDeoptBlock())
- continue;
-
- if (emitted.alreadyProcessed(pred))
- continue;
-
- if (dominatorTree.dominates(candidate->index(), pred->index())) {
- // this is a loop, where there in
- // -> candidate edge is the jump back to the top of the loop.
- continue;
- }
-
- if (pred == candidate)
- // this is a very tight loop, e.g.:
- // L1: ...
- // goto L1
- // This can happen when, for example, the basic-block merging gets rid of the empty
- // body block. In this case, we can safely schedule this block (if all other
- // incoming edges are either loop-back edges, or have been scheduled already).
- continue;
-
- return false; // an incoming edge that is not yet emitted, and is not a back-edge
- }
-
- if (loopInfo.isLoopHeader(candidate)) {
- // postpone everything, and schedule the loop first.
- postponedGroups.push(currentGroup);
- currentGroup = WorkForGroup(candidate);
- }
-
- return true;
-}
-
-MIBlock *BlockScheduler::pickNext()
-{
- while (true) {
- while (currentGroup.postponed.isEmpty()) {
- if (postponedGroups.isEmpty())
- return nullptr;
- if (currentGroup.group) // record the first and the last node of a group
- loopsStartEnd[currentGroup.group] = sequence.back();
- currentGroup = postponedGroups.pop();
- }
-
- MIBlock *next = currentGroup.postponed.pop();
- if (checkCandidate(next))
- return next;
- }
-
- Q_UNREACHABLE();
- return nullptr;
-}
-
-void BlockScheduler::emitBlock(MIBlock *bb)
-{
- if (emitted.alreadyProcessed(bb))
- return;
-
- sequence.push_back(bb);
- emitted.markAsProcessed(bb);
-}
-
-void BlockScheduler::schedule(MIBlock *functionEntryPoint)
-{
- MIBlock *next = functionEntryPoint;
-
- while (next) {
- emitBlock(next);
- // postpone all outgoing edges, if they were not already processed
- QVarLengthArray<MIBlock *, 32> nonExceptionEdges;
- // first postpone all exception edges, so they will be processed last
- for (int i = next->outEdges().size(); i != 0; ) {
- --i;
- MIBlock *out = next->outEdges().at(i);
- if (emitted.alreadyProcessed(out))
- continue;
- if (out == nullptr)
- continue;
- if (out->instructions().front().opcode() == Meta::OnException)
- postpone(out);
- else
- nonExceptionEdges.append(out);
- }
- for (MIBlock *edge : nonExceptionEdges)
- postpone(edge);
- next = pickNext();
- }
-
- // finally schedule all de-optimization blocks at the end
- for (auto bb : dominatorTree.function()->blocks()) {
- if (bb->isDeoptBlock())
- emitBlock(bb);
- }
-}
-
-void BlockScheduler::postpone(MIBlock *bb)
-{
- if (currentGroup.group == loopInfo.loopHeaderFor(bb)) {
- currentGroup.postponed.append(bb);
- return;
- }
-
- for (int i = postponedGroups.size(); i != 0; ) {
- --i;
- WorkForGroup &g = postponedGroups[i];
- if (g.group == loopInfo.loopHeaderFor(bb)) {
- g.postponed.append(bb);
- return;
- }
- }
-
- Q_UNREACHABLE();
-}
-
-void BlockScheduler::dump() const
-{
- if (!lcBlockScheduler().isDebugEnabled())
- return;
-
- QString s = QStringLiteral("Scheduled blocks:\n");
- for (auto *bb : sequence) {
- s += QLatin1String(" L") + QString::number(bb->index());
- MIBlock *loopEnd = loopsStartEnd[bb];
- if (loopEnd)
- s += QLatin1String(", loop start, ends at L") + QString::number(loopEnd->index());
- s += QLatin1Char('\n');
- }
- qCDebug(lcBlockScheduler).noquote().nospace() << s;
-}
-
-BlockScheduler::BlockScheduler(const DominatorTree &dominatorTree, const LoopInfo &loopInfo)
- : dominatorTree(dominatorTree)
- , loopInfo(loopInfo)
- , sequence(0)
- , emitted(dominatorTree.function())
-{
- schedule(dominatorTree.function()->blocks().front());
-
- dump();
-
- if (dominatorTree.function()->blockCount() != sequence.size()) {
- qFatal("The block scheduler did not schedule all blocks. This is most likely due to"
- "a non-natural loop.");
- // Usually caused by having an execution path that manages to skip over unwind handler
- // reset: any exception happening after will jump back to the unwind handler, and thereby
- // creating a loop that can be entered in 2 different ways.
- }
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4blockscheduler_p.h b/src/qml/jit/qv4blockscheduler_p.h
deleted file mode 100644
index 1289fda9f0..0000000000
--- a/src/qml/jit/qv4blockscheduler_p.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4BLOCKSCHEDULER_P_H
-#define QV4BLOCKSCHEDULER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qstack.h>
-
-#include "qv4mi_p.h"
-#include "qv4util_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class DominatorTree;
-class LoopInfo;
-
-// High-level algorithm:
-// 0. start with the first node (the start node) of a function
-// 1. emit the node
-// 2. add all outgoing edges that are not yet emitted to the postponed stack
-// 3. When the postponed stack is empty, pop a stack from the loop stack. If that is empty too,
-// we're done.
-// 4. pop a node from the postponed stack, and check if it can be scheduled:
-// a. if all incoming edges are scheduled, go to 4.
-// b. if an incoming edge is unscheduled, but it's a back-edge (an edge in a loop that jumps
-// back to the start of the loop), ignore it
-// c. if there is any unscheduled edge that is not a back-edge, ignore this node, and go to 4.
-// 5. if this node is the start of a loop, push the postponed stack on the loop stack.
-// 6. go back to 1.
-//
-// The postponing action in step 2 will put the node into its containing group. The case where this
-// is important is when a (labeled) continue or a (labeled) break statement occur in a loop: the
-// outgoing edge points to a node that is not part of the current loop (and possibly not of the
-// parent loop).
-//
-// Linear scan register allocation benefits greatly from short life-time intervals with few holes
-// (see for example section 4 (Lifetime Analysis) of [Wimmer1]). This algorithm makes sure that the
-// blocks of a group are scheduled together, with no non-loop blocks in between. This applies
-// recursively for nested loops. It also schedules groups of if-then-else-endif blocks together for
-// the same reason.
-class BlockScheduler
-{
- const DominatorTree &dominatorTree;
- const LoopInfo &loopInfo;
-
- struct WorkForGroup
- {
- MIBlock *group;
- QStack<MIBlock *> postponed;
-
- WorkForGroup(MIBlock *group = nullptr) : group(group) {}
- };
- WorkForGroup currentGroup;
- QStack<WorkForGroup> postponedGroups;
- std::vector<MIBlock *> sequence;
-
- class ProcessedBlocks
- {
- BitVector processed;
-
- public:
- ProcessedBlocks(MIFunction *function)
- : processed(int(function->blockCount()), false)
- {}
-
- bool alreadyProcessed(MIBlock *bb) const
- {
- Q_ASSERT(bb);
-
- return processed.at(bb->index());
- }
-
- void markAsProcessed(MIBlock *bb)
- {
- processed.setBit(bb->index());
- }
- } emitted;
- QHash<MIBlock *, MIBlock *> loopsStartEnd;
-
- bool checkCandidate(MIBlock *candidate);
- MIBlock *pickNext();
- void emitBlock(MIBlock *bb);
- void schedule(MIBlock *functionEntryPoint);
- void postpone(MIBlock *bb);
- void dump() const;
-
-public:
- BlockScheduler(const DominatorTree &dominatorTree, const LoopInfo &loopInfo);
-
- const std::vector<MIBlock *> &scheduledBlockSequence() const
- { return sequence; }
-
- QHash<MIBlock *, MIBlock *> loopEndsByStartBlock() const
- { return loopsStartEnd; }
-};
-
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4BLOCKSCHEDULER_P_H
diff --git a/src/qml/jit/qv4domtree.cpp b/src/qml/jit/qv4domtree.cpp
deleted file mode 100644
index 9484f4e2dc..0000000000
--- a/src/qml/jit/qv4domtree.cpp
+++ /dev/null
@@ -1,436 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-#include <QtCore/qbuffer.h>
-
-#include "qv4domtree_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcDomTree, "qt.v4.ir.domTree")
-Q_LOGGING_CATEGORY(lcDomFrontier, "qt.v4.ir.domFrontier")
-
-DominatorTree::DominatorTree(MIFunction *f)
- : m_function(f)
- , m_data(new Data)
-{
- calculateIDoms();
- m_data.reset();
-}
-
-void DominatorTree::dumpImmediateDominators() const
-{
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream qout(&buf);
- qout << "Immediate dominators for " << m_function->irFunction()->name() << ":" << endl;
- for (MIBlock *to : m_function->blocks()) {
- MIBlock::Index from = m_idom.at(to->index());
- if (from != MIBlock::InvalidIndex)
- qout << " " << from;
- else
- qout << " (none)";
- qout << " dominates " << to->index() << endl;
- }
- qCDebug(lcDomTree, "%s", buf.data().constData());
-}
-
-void DominatorTree::setImmediateDominator(MIBlock::Index dominated, MIBlock::Index dominator)
-{
- if (m_idom.size() <= size_t(dominated))
- m_idom.resize(dominated + 1);
- m_idom[dominated] = dominator;
-}
-
-bool DominatorTree::dominates(MIBlock::Index dominator, MIBlock::Index dominated) const
-{
- // dominator can be Invalid when the dominated block has no dominator (i.e. the start node)
- Q_ASSERT(dominated != MIBlock::InvalidIndex);
-
- if (dominator == dominated)
- return false;
-
- for (MIBlock::Index it = m_idom[dominated]; it != MIBlock::InvalidIndex; it = m_idom[it]) {
- if (it == dominator)
- return true;
- }
-
- return false;
-}
-
-// Calculate a depth-first iteration order on the nodes of the dominator tree.
-//
-// The order of the nodes in the vector is not the same as one where a recursive depth-first
-// iteration is done on a tree. Rather, the nodes are (reverse) sorted on tree depth.
-// So for the:
-// 1 dominates 2
-// 2 dominates 3
-// 3 dominates 4
-// 2 dominates 5
-// the order will be:
-// 4, 3, 5, 2, 1
-// or:
-// 4, 5, 3, 2, 1
-// So the order of nodes on the same depth is undefined, but it will be after the nodes
-// they dominate, and before the nodes that dominate them.
-//
-// The reason for this order is that a proper DFS pre-/post-order would require inverting
-// the idom vector by either building a real tree datastructure or by searching the idoms
-// for siblings and children. Both have a higher time complexity than sorting by depth.
-std::vector<MIBlock *> DominatorTree::calculateDFNodeIterOrder() const
-{
- std::vector<int> depths = calculateNodeDepths();
- std::vector<MIBlock *> order = m_function->blocks();
- std::sort(order.begin(), order.end(), [&depths](MIBlock *one, MIBlock *two) -> bool {
- return depths.at(one->index()) > depths.at(two->index());
- });
- return order;
-}
-
-// Algorithm:
-// - for each node:
-// - get the depth of a node. If it's unknown (-1):
-// - get the depth of the immediate dominator.
-// - if that's unknown too, calculate it by calling calculateNodeDepth
-// - set the current node's depth to that of immediate dominator + 1
-std::vector<int> DominatorTree::calculateNodeDepths() const
-{
- std::vector<int> nodeDepths(size_t(m_function->blockCount()), -1);
- for (MIBlock *bb : m_function->blocks()) {
- int &bbDepth = nodeDepths[bb->index()];
- if (bbDepth == -1) {
- const int immDom = m_idom[bb->index()];
- if (immDom == -1) {
- // no immediate dominator, so it's either the start block, or an unreachable block
- bbDepth = 0;
- } else {
- int immDomDepth = nodeDepths[immDom];
- if (immDomDepth == -1)
- immDomDepth = calculateNodeDepth(immDom, nodeDepths);
- bbDepth = immDomDepth + 1;
- }
- }
- }
- return nodeDepths;
-}
-
-// Algorithm:
-// - search for the first dominator of a node that has a known depth. As all nodes are
-// reachable from the start node, and that node's depth is 0, this is finite.
-// - while doing that search, put all unknown nodes in the worklist
-// - pop all nodes from the worklist, and set their depth to the previous' (== dominating)
-// node's depth + 1
-// This way every node's depth is calculated once, and the complexity is O(n).
-int DominatorTree::calculateNodeDepth(MIBlock::Index nodeIdx, std::vector<int> &nodeDepths) const
-{
- std::vector<int> worklist;
- worklist.reserve(8);
- int depth = -1;
-
- do {
- worklist.push_back(nodeIdx);
- nodeIdx = m_idom[nodeIdx];
- depth = nodeDepths[nodeIdx];
- } while (depth == -1);
-
- for (auto it = worklist.rbegin(), eit = worklist.rend(); it != eit; ++it)
- nodeDepths[*it] = ++depth;
-
- return depth;
-}
-
-namespace {
-struct DFSTodo {
- MIBlock::Index node = MIBlock::InvalidIndex;
- MIBlock::Index parent = MIBlock::InvalidIndex;
-
- DFSTodo() = default;
- DFSTodo(MIBlock::Index node, MIBlock::Index parent)
- : node(node)
- , parent(parent)
- {}
-};
-} // anonymous namespace
-
-void DominatorTree::dfs(MIBlock::Index node)
-{
- std::vector<DFSTodo> worklist;
- worklist.reserve(m_data->vertex.capacity() / 2);
- DFSTodo todo(node, MIBlock::InvalidIndex);
-
- while (true) {
- MIBlock::Index n = todo.node;
-
- if (m_data->dfnum[n] == 0) {
- m_data->dfnum[n] = m_data->size;
- m_data->vertex[m_data->size] = n;
- m_data->parent[n] = todo.parent;
- ++m_data->size;
-
- MIBlock::OutEdges out = m_function->block(n)->outEdges();
- for (int i = out.size() - 1; i > 0; --i)
- worklist.emplace_back(out[i]->index(), n);
-
- if (!out.isEmpty()) {
- todo.node = out.first()->index();
- todo.parent = n;
- continue;
- }
- }
-
- if (worklist.empty())
- break;
-
- todo = worklist.back();
- worklist.pop_back();
- }
-}
-
-void DominatorTree::link(MIBlock::Index p, MIBlock::Index n)
-{
- m_data->ancestor[n] = p;
- m_data->best[n] = n;
-}
-
-void DominatorTree::calculateIDoms()
-{
- Q_ASSERT(m_function->block(0)->inEdges().count() == 0);
-
- const size_t bbCount = m_function->blockCount();
- m_data->vertex = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->parent = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->dfnum = std::vector<unsigned>(bbCount, 0);
- m_data->semi = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->ancestor = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_idom = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->samedom = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
- m_data->best = std::vector<MIBlock::Index>(bbCount, MIBlock::InvalidIndex);
-
- QHash<MIBlock::Index, std::vector<MIBlock::Index>> bucket;
- bucket.reserve(int(bbCount));
-
- dfs(m_function->block(0)->index());
-
- std::vector<MIBlock::Index> worklist;
- worklist.reserve(m_data->vertex.capacity() / 2);
-
- for (int i = m_data->size - 1; i > 0; --i) {
- MIBlock::Index n = m_data->vertex[i];
- MIBlock::Index p = m_data->parent[n];
- MIBlock::Index s = p;
-
- for (auto inEdge : m_function->block(n)->inEdges()) {
- if (inEdge->isDeoptBlock())
- continue;
- MIBlock::Index v = inEdge->index();
- MIBlock::Index ss = MIBlock::InvalidIndex;
- if (m_data->dfnum[v] <= m_data->dfnum[n])
- ss = v;
- else
- ss = m_data->semi[ancestorWithLowestSemi(v, worklist)];
- if (m_data->dfnum[ss] < m_data->dfnum[s])
- s = ss;
- }
- m_data->semi[n] = s;
- bucket[s].push_back(n);
- link(p, n);
- if (bucket.contains(p)) {
- for (MIBlock::Index v : bucket[p]) {
- MIBlock::Index y = ancestorWithLowestSemi(v, worklist);
- MIBlock::Index semi_v = m_data->semi[v];
- if (m_data->semi[y] == semi_v)
- m_idom[v] = semi_v;
- else
- m_data->samedom[v] = y;
- }
- bucket.remove(p);
- }
- }
-
- for (unsigned i = 1; i < m_data->size; ++i) {
- MIBlock::Index n = m_data->vertex[i];
- Q_ASSERT(n != MIBlock::InvalidIndex);
- Q_ASSERT(!bucket.contains(n));
- Q_ASSERT(m_data->ancestor[n] != MIBlock::InvalidIndex);
- Q_ASSERT((m_data->semi[n] != MIBlock::InvalidIndex
- && m_data->dfnum[m_data->ancestor[n]] <= m_data->dfnum[m_data->semi[n]])
- || m_data->semi[n] == n);
- MIBlock::Index sdn = m_data->samedom[n];
- if (sdn != MIBlock::InvalidIndex)
- m_idom[n] = m_idom[sdn];
- }
-
- if (lcDomTree().isDebugEnabled())
- dumpImmediateDominators();
-
- m_data.reset(nullptr);
-}
-
-MIBlock::Index DominatorTree::ancestorWithLowestSemi(MIBlock::Index v,
- std::vector<MIBlock::Index> &worklist)
-{
- worklist.clear();
- for (MIBlock::Index it = v; it != MIBlock::InvalidIndex; it = m_data->ancestor[it])
- worklist.push_back(it);
-
- if (worklist.size() < 2)
- return m_data->best[v];
-
- MIBlock::Index b = MIBlock::InvalidIndex;
- MIBlock::Index last = worklist.back();
- Q_ASSERT(worklist.size() <= INT_MAX);
- for (int it = static_cast<int>(worklist.size()) - 2; it >= 0; --it) {
- MIBlock::Index bbIt = worklist[it];
- m_data->ancestor[bbIt] = last;
- MIBlock::Index &best_it = m_data->best[bbIt];
- if (b != MIBlock::InvalidIndex
- && m_data->dfnum[m_data->semi[b]] < m_data->dfnum[m_data->semi[best_it]]) {
- best_it = b;
- } else {
- b = best_it;
- }
- }
- return b;
-}
-
-void DominatorFrontier::compute(const DominatorTree &domTree)
-{
- struct NodeProgress {
- std::vector<MIBlock::Index> children;
- std::vector<MIBlock::Index> todo;
- };
-
- MIFunction *function = domTree.function();
- m_df.resize(function->blockCount());
-
- // compute children of each node in the dominator tree
- std::vector<std::vector<MIBlock::Index> > children; // BasicBlock index -> children
- children.resize(function->blockCount());
- for (MIBlock *n : function->blocks()) {
- const MIBlock::Index nodeIndex = n->index();
- Q_ASSERT(function->block(nodeIndex) == n);
- const MIBlock::Index nodeDominator = domTree.immediateDominator(nodeIndex);
- if (nodeDominator == MIBlock::InvalidIndex)
- continue; // there is no dominator to add this node to as a child (e.g. the start node)
- children[nodeDominator].push_back(nodeIndex);
- }
-
- // Fill the worklist and initialize the node status for each basic-block
- std::vector<NodeProgress> nodeStatus;
- nodeStatus.resize(function->blockCount());
- std::vector<MIBlock::Index> worklist;
- worklist.reserve(function->blockCount());
- for (MIBlock *bb : function->blocks()) {
- MIBlock::Index nodeIndex = bb->index();
- worklist.push_back(nodeIndex);
- NodeProgress &np = nodeStatus[nodeIndex];
- np.children = children[nodeIndex];
- np.todo = children[nodeIndex];
- }
-
- BitVector DF_done(int(function->blockCount()), false);
-
- while (!worklist.empty()) {
- MIBlock::Index node = worklist.back();
-
- if (DF_done.at(node)) {
- worklist.pop_back();
- continue;
- }
-
- NodeProgress &np = nodeStatus[node];
- auto it = np.todo.begin();
- while (it != np.todo.end()) {
- if (DF_done.at(*it)) {
- it = np.todo.erase(it);
- } else {
- worklist.push_back(*it);
- break;
- }
- }
-
- if (np.todo.empty()) {
- MIBlockSet &miBlockSet = m_df[node];
- miBlockSet.init(function);
- for (MIBlock *y : function->block(node)->outEdges()) {
- if (domTree.immediateDominator(y->index()) != node)
- miBlockSet.insert(y);
- }
- for (MIBlock::Index child : np.children) {
- const MIBlockSet &ws = m_df[child];
- for (auto w : ws) {
- const MIBlock::Index wIndex = w->index();
- if (node == wIndex || !domTree.dominates(node, w->index()))
- miBlockSet.insert(w);
- }
- }
- DF_done.setBit(node);
- worklist.pop_back();
- }
- }
-
- if (lcDomFrontier().isDebugEnabled())
- dump(domTree.function());
-}
-
-void DominatorFrontier::dump(MIFunction *function)
-{
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- QTextStream qout(&buf);
- qout << "Dominator Frontiers:" << endl;
- for (MIBlock *n : function->blocks()) {
- qout << "\tDF[" << n->index() << "]: {";
- const MIBlockSet &SList = m_df[n->index()];
- for (MIBlockSet::const_iterator i = SList.begin(), ei = SList.end(); i != ei; ++i) {
- if (i != SList.begin())
- qout << ", ";
- qout << (*i)->index();
- }
- qout << "}" << endl;
- }
- qCDebug(lcDomFrontier, "%s", buf.data().constData());
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4domtree_p.h b/src/qml/jit/qv4domtree_p.h
deleted file mode 100644
index 703e17ab61..0000000000
--- a/src/qml/jit/qv4domtree_p.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4DOMTREE_P_H
-#define QV4DOMTREE_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 "qv4mi_p.h"
-#include "qv4miblockset_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class DominatorTree
-{
- Q_DISABLE_COPY_MOVE(DominatorTree)
-
-public:
- DominatorTree(MIFunction *f);
- ~DominatorTree() = default;
-
- void dumpImmediateDominators() const;
- MIFunction *function() const
- { return m_function; }
-
- void setImmediateDominator(MIBlock::Index dominated, MIBlock::Index dominator);
-
- MIBlock::Index immediateDominator(MIBlock::Index blockIndex) const
- { return m_idom[blockIndex]; }
-
- bool dominates(MIBlock::Index dominator, MIBlock::Index dominated) const;
-
- bool insideSameDominatorChain(MIBlock::Index one, MIBlock::Index other) const
- { return one == other || dominates(one, other) || dominates(other, one); }
-
- std::vector<MIBlock *> calculateDFNodeIterOrder() const;
-
- std::vector<int> calculateNodeDepths() const;
-
-private: // functions
- int calculateNodeDepth(MIBlock::Index nodeIdx, std::vector<int> &nodeDepths) const;
- void link(MIBlock::Index p, MIBlock::Index n);
- void calculateIDoms();
- void dfs(MIBlock::Index node);
- MIBlock::Index ancestorWithLowestSemi(MIBlock::Index v, std::vector<MIBlock::Index> &worklist);
-
-private: // data
- struct Data {
- std::vector<unsigned> dfnum; // MIBlock index -> dfnum
- std::vector<MIBlock::Index> vertex;
- std::vector<MIBlock::Index> parent; // MIBlock index -> parent MIBlock index
- std::vector<MIBlock::Index> ancestor; // MIBlock index -> ancestor MIBlock index
- std::vector<MIBlock::Index> best; // MIBlock index -> best MIBlock index
- std::vector<MIBlock::Index> semi; // MIBlock index -> semi dominator MIBlock index
- std::vector<MIBlock::Index> samedom; // MIBlock index -> same dominator MIBlock index
- unsigned size = 0;
- };
-
- MIFunction *m_function;
- QScopedPointer<Data> m_data;
- std::vector<MIBlock::Index> m_idom; // MIBlock index -> immediate dominator MIBlock index
-};
-
-class DominatorFrontier
-{
-public:
- DominatorFrontier(const DominatorTree &domTree)
- { compute(domTree); }
-
- const MIBlockSet &operator[](MIBlock *n) const
- { return m_df[n->index()]; }
-
-private: // functions
- void compute(const DominatorTree &domTree);
- void dump(MIFunction *function);
-
-private: // data
- std::vector<MIBlockSet> m_df; // MIBlock index -> dominator frontier
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4DOMTREE_P_H
diff --git a/src/qml/jit/qv4graph.cpp b/src/qml/jit/qv4graph.cpp
deleted file mode 100644
index 4025ceb993..0000000000
--- a/src/qml/jit/qv4graph.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4graph_p.h"
-#include "qv4operation_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Graph *Graph::create(Function *function)
-{
- auto storage = function->pool()->allocate(sizeof(Graph));
- auto g = new (storage) Graph(function);
- g->m_undefinedNode = g->createNode(g->opBuilder()->get<Meta::Undefined>());
- g->m_emptyNode = g->createNode(g->opBuilder()->get<Meta::Empty>());
- g->m_nullNode = g->createNode(g->opBuilder()->getConstant(QV4::Value::nullValue()));
- g->m_trueNode = g->createNode(g->opBuilder()->getConstant(QV4::Value::fromBoolean(true)));
- g->m_falseNode = g->createNode(g->opBuilder()->getConstant(QV4::Value::fromBoolean(false)));
- return g;
-}
-
-Graph::MemoryPool *Graph::pool() const
-{
- return m_function->pool();
-}
-
-Node *Graph::createNode(const Operation *op, Node *const operands[], size_t opCount,
- bool incomplete)
-{
- return Node::create(pool(), m_nextNodeId++, op, opCount, operands, incomplete);
-}
-
-Node *Graph::createConstantBoolNode(bool value)
-{
- return createNode(opBuilder()->getConstant(Primitive::fromBoolean(value)));
-}
-
-Node *Graph::createConstantIntNode(int value)
-{
- return createNode(opBuilder()->getConstant(Primitive::fromInt32(value)));
-}
-
-Graph::Graph(Function *function)
- : m_function(function)
- , m_opBuilder(OperationBuilder::create(pool()))
-{}
-
-Node *Graph::createConstantHeapNode(Heap::Base *heap)
-{
- return createNode(opBuilder()->getConstant(Primitive::fromHeapObject(heap)));
-}
-
-void Graph::addEndInput(Node *n)
-{
- if (m_endNode) {
- auto newEnd = m_opBuilder->getEnd(m_endNode->operation()->controlInputCount() + 1);
- m_endNode->setOperation(newEnd);
- m_endNode->addInput(m_function->pool(), n);
- }
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4graph_p.h b/src/qml/jit/qv4graph_p.h
deleted file mode 100644
index 4706399c94..0000000000
--- a/src/qml/jit/qv4graph_p.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4GRAPH_P_H
-#define QV4GRAPH_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 <private/qqmljsmemorypool_p.h>
-#include <private/qv4global_p.h>
-#include <private/qv4node_p.h>
-
-#include <array>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class Function;
-class Operation;
-class OperationBuilder;
-
-class Graph final
-{
- Q_DISABLE_COPY_MOVE(Graph)
-
-public:
- using MemoryPool = QQmlJS::MemoryPool;
-
-public:
- static Graph *create(Function *function);
- ~Graph() = delete;
-
- MemoryPool *pool() const;
- OperationBuilder *opBuilder() const
- { return m_opBuilder; }
-
- Node *createNode(const Operation *op, Node * const operands[] = nullptr, size_t opCount = 0,
- bool incomplete = false);
- template <typename... Nodes>
- Node *createNode(Operation *op, Nodes*... nodes) {
- std::array<Node *, sizeof...(nodes)> nodesArray {{ nodes... }};
- return createNode(op, nodesArray.data(), nodesArray.size());
- }
- Node *createConstantBoolNode(bool value);
- Node *createConstantIntNode(int value);
- Node *createConstantHeapNode(Heap::Base *heap);
-
- Node *undefinedNode() const { return m_undefinedNode; }
- Node *emptyNode() const { return m_emptyNode; }
- Node *nullNode() const { return m_nullNode; }
- Node *trueConstant() const { return m_trueNode; }
- Node *falseConstant() const { return m_falseNode; }
-
- Node *startNode() const { return m_startNode; }
- Node *engineNode() const { return m_engineNode; }
- Node *functionNode() const { return m_functionNode; }
- Node *cppFrameNode() const { return m_cppFrameNode; }
- Node *endNode() const { return m_endNode; }
- Node *initialFrameState() const { return m_initialFrameState; }
- void setStartNode(Node *n) { m_startNode = n; }
- void setEngineNode(Node *n) { m_engineNode = n; }
- void setFunctionNode(Node *n) { m_functionNode = n; }
- void setCppFrameNode(Node *n) { m_cppFrameNode = n; }
- void setEndNode(Node *n) { m_endNode = n; }
- void setInitialFrameState(Node *n) { m_initialFrameState = n; }
-
- unsigned nodeCount() const
- { return unsigned(m_nextNodeId); }
-
- void addEndInput(Node *n);
-
-private: // types and methods
- Graph(Function *function);
-
-private: // fields
- Function *m_function;
- OperationBuilder *m_opBuilder;
- Node::Id m_nextNodeId = 0;
- Node *m_undefinedNode = nullptr;
- Node *m_emptyNode = nullptr;
- Node *m_nullNode = nullptr;
- Node *m_trueNode = nullptr;
- Node *m_falseNode = nullptr;
- Node *m_startNode = nullptr;
- Node *m_engineNode = nullptr;
- Node *m_functionNode = nullptr;
- Node *m_cppFrameNode = nullptr;
- Node *m_endNode = nullptr;
- Node *m_initialFrameState = nullptr;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4GRAPH_P_H
diff --git a/src/qml/jit/qv4graphbuilder.cpp b/src/qml/jit/qv4graphbuilder.cpp
deleted file mode 100644
index 2c073701ee..0000000000
--- a/src/qml/jit/qv4graphbuilder.cpp
+++ /dev/null
@@ -1,1683 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-
-#include "qv4graphbuilder_p.h"
-#include "qv4function_p.h"
-#include "qv4lookup_p.h"
-#include "qv4stackframe_p.h"
-#include "qv4operation_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcIRGraphBuilder, "qt.v4.ir.graphbuilder")
-
-using MemoryPool = QQmlJS::MemoryPool;
-
-namespace {
-template <typename T, size_t N>
-char (&ArraySizeHelper(T (&array)[N]))[N];
-template <typename T, size_t N>
-char (&ArraySizeHelper(const T (&array)[N]))[N];
-
-template <typename Array>
-inline size_t arraySize(const Array &array)
-{
- Q_UNUSED(array); // for MSVC
- return sizeof(ArraySizeHelper(array));
-}
-} // anonymous namespace
-
-class GraphBuilder::InterpreterEnvironment
-{
-public:
- struct FrameState: public QQmlJS::FixedPoolArray<Node *>
- {
- FrameState(MemoryPool *pool, int totalSlotCount)
- : FixedPoolArray(pool, totalSlotCount)
- {}
-
- Node *&unwindHandlerOffset()
- { return at(size() - 1); }
-
- static FrameState *create(MemoryPool *pool, int jsSlotCount)
- {
- auto totalSlotCount = jsSlotCount;
- auto fs = pool->New<FrameState>(pool, totalSlotCount);
- return fs;
- }
-
- static FrameState *clone(MemoryPool *pool, FrameState *other)
- {
- FrameState *fs = create(pool, other->size());
-
- for (int i = 0, ei = other->size(); i != ei; ++i)
- fs->at(i) = other->at(i);
-
- return fs;
- }
- };
-
-public:
- InterpreterEnvironment(GraphBuilder *graphBuilder, Node *controlDependency)
- : m_graphBuilder(graphBuilder)
- , m_effectDependency(controlDependency)
- , m_controlDependency(controlDependency)
- , m_currentFrame(nullptr)
- {}
-
- void createEnvironment()
- {
- Function *f = function();
- QV4::Function *v4Function = f->v4Function();
- const size_t nRegisters = v4Function->compiledFunction->nRegisters;
-
- // 1 extra slot for the unwindHandlerOffset
- m_currentFrame = FrameState::create(graph()->pool(), int(nRegisters + 1));
- }
-
- void setupStartEnvironment()
- {
- Function *f = function();
- QV4::Function *v4Function = f->v4Function();
- const size_t nFormals = v4Function->compiledFunction->nFormals;
- const size_t nRegisters = v4Function->compiledFunction->nRegisters;
-
- createEnvironment();
-
- Node *startNode = graph()->startNode();
- auto opB = opBuilder();
- auto create = [&](int index, const char *name) {
- m_currentFrame->at(index) = graph()->createNode(
- opB->getParam(index, f->addString(QLatin1String(name))), startNode);
- };
- create(0, "%function");
- create(1, "%context");
- create(2, "%acc");
- create(3, "%this");
- create(4, "%newTarget");
- create(5, "%argc");
- const quint32_le *formalNameIdx = v4Function->compiledFunction->formalsTable();
- for (size_t i = 0; i < nFormals; ++i, ++formalNameIdx) {
- const int slot = int(CallData::HeaderSize() + i);
- Q_ASSERT(*formalNameIdx <= quint32(std::numeric_limits<int>::max()));
- auto op = opB->getParam(
- slot,
- f->addString(v4Function->compilationUnit->stringAt(int(*formalNameIdx))));
- Node *argNode = graph()->createNode(op, startNode);
- m_currentFrame->at(slot) = argNode;
- }
- Node *undefinedNode = graph()->undefinedNode();
- Node *emptyNode = graph()->emptyNode();
- const auto firstDeadZoneRegister
- = v4Function->compiledFunction->firstTemporalDeadZoneRegister;
- const auto registerDeadZoneSize
- = v4Function->compiledFunction->sizeOfRegisterTemporalDeadZone;
- for (size_t i = CallData::HeaderSize() + nFormals; i < nRegisters; ++i) {
- const bool isDead = i >= firstDeadZoneRegister
- && i < size_t(firstDeadZoneRegister + registerDeadZoneSize);
- m_currentFrame->at(int(i)) = isDead ? emptyNode : undefinedNode;
- }
- setUnwindHandlerOffset(0);
- }
-
- Function *function() const { return m_graphBuilder->function(); }
- Graph *graph() const { return function()->graph(); }
- OperationBuilder *opBuilder() const { return graph()->opBuilder(); }
- GraphBuilder *graphBuilder() const { return m_graphBuilder; }
-
- Node *bindAcc(Node *node)
- {
- bindNodeToSlot(node, CallData::Accumulator);
- return node;
- }
-
- Node *accumulator() const
- { return slot(CallData::Accumulator); }
-
- Node *bindNodeToSlot(Node *node, int slot)
- {
- m_currentFrame->at(size_t(slot)) = node;
- return node;
- }
-
- Node *slot(int slot) const
- { return m_currentFrame->at(slot); }
-
- int slotCount() const
- { return m_currentFrame->size(); }
-
- Node *effectDependency() const
- { return m_effectDependency; }
-
- void setEffectDependency(Node *newNode)
- { m_effectDependency = newNode; }
-
- Node *controlDependency() const
- { return m_controlDependency; }
-
- void setControlDependency(Node *newNode)
- { m_controlDependency = newNode; }
-
- Node *createFrameState()
- {
- return graph()->createNode(graphBuilder()->opBuilder()->getFrameState(slotCount()),
- m_currentFrame->begin(), slotCount());
- }
-
- Node *merge(InterpreterEnvironment *other);
-
- InterpreterEnvironment *copy() const
- {
- auto *newEnv = graph()->pool()->New<InterpreterEnvironment>(graphBuilder(),
- controlDependency());
- newEnv->setEffectDependency(effectDependency());
- newEnv->m_currentFrame = FrameState::clone(graph()->pool(), m_currentFrame);
- return newEnv;
- }
-
- int unwindHandlerOffset() const
- {
- auto uhOp = m_currentFrame->unwindHandlerOffset()->operation();
- Q_ASSERT(uhOp->kind() == Meta::Constant);
- return ConstantPayload::get(*uhOp)->value().int_32();
- }
-
- void setUnwindHandlerOffset(int newOffset)
- { m_currentFrame->unwindHandlerOffset() = graphBuilder()->createConstant(newOffset); }
-
- FrameState *frameState() const
- { return m_currentFrame; }
-
-private:
- GraphBuilder *m_graphBuilder;
- Node *m_effectDependency;
- Node *m_controlDependency;
- FrameState *m_currentFrame;
-};
-
-namespace {
-class InterpreterSubEnvironment final
-{
- Q_DISABLE_COPY_MOVE(InterpreterSubEnvironment)
-
-public:
- explicit InterpreterSubEnvironment(GraphBuilder *builder)
- : m_builder(builder)
- , m_parent(builder->env()->copy())
- {}
-
- ~InterpreterSubEnvironment()
- { m_builder->setEnv(m_parent); }
-
-private:
- GraphBuilder *m_builder;
- GraphBuilder::InterpreterEnvironment *m_parent;
-};
-} // anonymous namespace
-
-Node *GraphBuilder::InterpreterEnvironment::merge(InterpreterEnvironment *other)
-{
- Q_ASSERT(m_currentFrame->size() == other->m_currentFrame->size());
-
- auto gb = graphBuilder();
- Node *mergedControl = gb->mergeControl(controlDependency(), other->controlDependency());
- setControlDependency(mergedControl);
- setEffectDependency(gb->mergeEffect(effectDependency(), other->effectDependency(), mergedControl));
-
- // insert/update phi nodes, but not for the unwind handler:
- for (int i = 0, ei = m_currentFrame->size() - 1; i != ei; ++i) {
- //### use lifeness info to trim this!
- m_currentFrame->at(i) = gb->mergeValue(m_currentFrame->at(i),
- other->m_currentFrame->at(i),
- mergedControl);
- }
- Q_ASSERT(unwindHandlerOffset() >= 0); // specifically: don't crash
- return mergedControl;
-}
-
-void GraphBuilder::buildGraph(IR::Function *function)
-{
- const char *code = function->v4Function()->codeData;
- uint len = function->v4Function()->compiledFunction->codeSize;
-
- GraphBuilder builder(function);
- builder.startGraph();
-
- InterpreterEnvironment initial(&builder, function->graph()->startNode());
- initial.setupStartEnvironment();
- builder.setEnv(&initial);
- builder.graph()->setInitialFrameState(initial.createFrameState());
- builder.decode(code, len);
- builder.endGraph();
-};
-
-GraphBuilder::GraphBuilder(IR::Function *function)
- : m_func(function)
- , m_graph(function->graph())
- , m_currentEnv(nullptr)
-{
- for (unsigned i = 0, ei = m_func->v4Function()->compiledFunction->nLabelInfos; i != ei; ++i) {
- unsigned label = m_func->v4Function()->compiledFunction->labelInfoTable()[i];
- m_labelInfos.emplace_back(label);
- if (lcIRGraphBuilder().isDebugEnabled()) {
- const LabelInfo &li = m_labelInfos.back();
- qCDebug(lcIRGraphBuilder) << "Loop start at" << li.labelOffset;
- }
- }
-}
-
-void GraphBuilder::startGraph()
-{
- size_t nValuesOut = 1 + CallData::HeaderSize()
- + m_func->v4Function()->compiledFunction->nFormals;
- Node *start = m_graph->createNode(opBuilder()->getStart(uint16_t(nValuesOut)), nullptr, 0);
- m_func->nodeInfo(start)->setBytecodeOffsets(0, 0);
- m_graph->setStartNode(start);
- m_graph->setEngineNode(m_graph->createNode(opBuilder()->get<Meta::Engine>(), &start, 1));
- auto frame = m_graph->createNode(opBuilder()->get<Meta::CppFrame>(), &start, 1);
- m_graph->setCppFrameNode(frame);
- m_graph->setFunctionNode(m_graph->createNode(opBuilder()->get<Meta::Function>(),
- &frame, 1));
-}
-
-void GraphBuilder::endGraph()
-{
- const auto inputCount = uint16_t(m_exitControls.size());
- Node **inputs = &m_exitControls.front();
- Q_ASSERT(m_graph->endNode() == nullptr);
- m_graph->setEndNode(m_graph->createNode(opBuilder()->getEnd(inputCount), inputs, inputCount));
-}
-
-Node *GraphBuilder::bindAcc(Node *n)
-{
- return env()->bindAcc(n);
-}
-
-/* IMPORTANT!!!
- *
- * This might change the success environment, so don't call:
- * env()->bindAcc(createNode(...))
- * because the binding should only happen on success, but the call to env() will get the
- * environment from *before* the new success environment was created. Instead, do:
- * bindAcc(createNode(....))
- */
-Node *GraphBuilder::createAndLinkNode(Operation *op, Node *operands[], size_t opCount,
- bool incomplete)
-{
- Q_ASSERT(op->effectInputCount() < 2);
- Q_ASSERT(op->controlInputCount() < 2);
-
- QVarLengthArray<Node *, 32> inputs(static_cast<int>(opCount));
- std::copy_n(operands, opCount, inputs.data());
-
- if (op->effectInputCount() == 1)
- inputs.append(env()->effectDependency());
- if (op->controlInputCount() == 1)
- inputs.append(env()->controlDependency());
- if (op->hasFrameStateInput())
- inputs.append(env()->createFrameState());
-
- Node *node = m_graph->createNode(op, inputs.data(), inputs.size(), incomplete);
-
- if (op->needsBytecodeOffsets()) {
- m_func->nodeInfo(node)->setBytecodeOffsets(currentInstructionOffset(),
- nextInstructionOffset());
- }
-
- if (op->effectOutputCount() > 0)
- env()->setEffectDependency(node);
- if (op->controlOutputCount() > 0)
- env()->setControlDependency(node);
-
- if (op->canThrow() && env()->unwindHandlerOffset()) {
- InterpreterSubEnvironment successEnv(this);
- Node *control = env()->controlDependency();
- control = m_graph->createNode(opBuilder()->get<Meta::OnException>(), &control, 1);
- env()->setControlDependency(control);
- auto unwindHandlerOffset = env()->unwindHandlerOffset();
- mergeIntoSuccessor(unwindHandlerOffset);
- }
-
- return node;
-}
-
-Node *GraphBuilder::createNode(Operation *op, bool incomplete)
-{
- return createAndLinkNode(op, nullptr, 0, incomplete);
-}
-
-Node *GraphBuilder::createNode(Operation *op, Node *n1)
-{
- Node *buf[] = { n1 };
- return createAndLinkNode(op, buf, arraySize(buf));
-}
-
-Node *GraphBuilder::createNode(Operation *op, Node *n1, Node *n2)
-{
- Node *buf[] = { n1, n2 };
- return createAndLinkNode(op, buf, arraySize(buf));
-}
-
-Node *GraphBuilder::createNode(Operation *op, Node *n1, Node *n2, Node *n3)
-{
- Node *buf[] = { n1, n2, n3 };
- return createAndLinkNode(op, buf, arraySize(buf));
-}
-
-Node *GraphBuilder::createNode(Operation *op, Node *n1, Node *n2, Node *n3, Node *n4)
-{
- Node *buf[] = { n1, n2, n3, n4 };
- return createAndLinkNode(op, buf, arraySize(buf));
-}
-
-Node *GraphBuilder::createRegion(unsigned nControlInputs)
-{
- return createNode(opBuilder()->getRegion(nControlInputs), true);
-}
-
-Node *GraphBuilder::createIfTrue()
-{
- return createNode(opBuilder()->get<Meta::IfTrue>());
-}
-
-Node *GraphBuilder::createIfFalse()
-{
- return createNode(opBuilder()->get<Meta::IfFalse>());
-}
-
-Node *GraphBuilder::createConstant(int v)
-{
- return m_graph->createNode(opBuilder()->getConstant(Primitive::fromInt32(v)));
-}
-
-Node *GraphBuilder::createPhi(unsigned nInputs, Node *input, Node *control)
-{
- auto phiOp = opBuilder()->getPhi(nInputs);
- QVarLengthArray<Node *, 32> buffer(int(nInputs + 1));
- std::fill_n(buffer.data(), nInputs, input);
- buffer[int(nInputs)] = control;
- return m_graph->createNode(phiOp, buffer.data(), nInputs + 1, true);
-}
-
-Node *GraphBuilder::createEffectPhi(unsigned nInputs, Node *input, Node *control)
-{
- auto phiOp = opBuilder()->getEffectPhi(nInputs);
- QVarLengthArray<Node *, 32> buffer(int(nInputs + 1));
- std::fill_n(buffer.data(), nInputs, input);
- buffer[int(nInputs)] = control;
- return m_graph->createNode(phiOp, buffer.data(), nInputs + 1, true);
-}
-
-Node *GraphBuilder::createHandleUnwind(int offset)
-{
- return createNode(opBuilder()->getHandleUnwind(offset));
-}
-
-Node *GraphBuilder::mergeControl(Node *c1, Node *c2)
-{
- if (c1->operation()->kind() == Meta::Region) {
- const unsigned nInputs = c1->operation()->controlInputCount() + 1;
- c1->addInput(m_graph->pool(), c2);
- c1->setOperation(opBuilder()->getRegion(nInputs));
- return c1;
- }
- auto op = opBuilder()->getRegion(2);
- Node *inputs[] = { c1, c2 };
- return m_graph->createNode(op, inputs, 2);
-}
-
-Node *GraphBuilder::mergeEffect(Node *e1, Node *e2, Node *control)
-{
- const unsigned nInputs = control->operation()->controlInputCount();
- if (e1->operation()->kind() == Meta::EffectPhi && e1->controlInput() == control) {
- e1->insertInput(m_graph->pool(), nInputs - 1, e2);
- e1->setOperation(opBuilder()->getEffectPhi(nInputs));
- return e1;
- }
-
- if (e1 != e2) {
- Node *phi = createEffectPhi(nInputs, e1, control);
- phi->replaceInput(nInputs - 1, e2);
- return phi;
- }
-
- return e1;
-}
-
-Node *GraphBuilder::mergeValue(Node *v1, Node *v2, Node *control)
-{
- const unsigned nInputs = control->operation()->controlInputCount();
- if (v1->operation()->kind() == Meta::Phi && v1->controlInput() == control) {
- v1->insertInput(m_graph->pool(), nInputs - 1, v2);
- v1->setOperation(opBuilder()->getPhi(nInputs));
- return v1;
- }
-
- if (v1 != v2) {
- Node *phi = createPhi(nInputs, v1, control);
- phi->replaceInput(nInputs - 1, v2);
- return phi;
- }
-
- return v1;
-}
-
-Node *GraphBuilder::createToBoolean(Node *input)
-{
- return createNode(opBuilder()->get<Meta::ToBoolean>(), input);
-}
-
-void GraphBuilder::populate(VarArgNodes &args, int argc, int argv)
-{
- for (int i = 0; i < argc; ++i)
- args.append(env()->slot(argv + i));
- Q_ASSERT(argc >= 0 && argc <= std::numeric_limits<uint16_t>::max());
-}
-
-void GraphBuilder::queueFunctionExit(Node *exitNode)
-{
- m_exitControls.push_back(exitNode);
- setEnv(nullptr);
-}
-
-Node *GraphBuilder::mergeIntoSuccessor(int offset)
-{
- InterpreterEnvironment *&successorEnvironment = m_envForOffset[offset];
-
- Node *region = nullptr;
- if (successorEnvironment == nullptr) {
- region = createRegion(1);
- successorEnvironment = env();
- } else {
- // Merge any values which are live coming into the successor.
- region = successorEnvironment->merge(env());
- }
- setEnv(nullptr);
- return region;
-}
-
-const GraphBuilder::LabelInfo *GraphBuilder::labelInfoAt(unsigned offset) const
-{
- for (const LabelInfo &li : m_labelInfos) {
- if (li.labelOffset == offset)
- return &li;
- }
- return nullptr;
-}
-
-const GraphBuilder::LabelInfo *GraphBuilder::isLoopStart(unsigned offset) const
-{
- if (auto li = labelInfoAt(offset)) {
- //### in the future, check if this is a loop start, or some other label
- return li;
- }
-
- return nullptr;
-}
-
-void GraphBuilder::handleLoopStart(const LabelInfo &labelInfo)
-{
- Q_ASSERT(env() != nullptr);
-
- // We unconditionally insert a region node with phi nodes here. Now there might already be
- // such a node, (e.g. the region after an if-then-else), but for simplicity we ignore that.
- // A subsequent pass will fold/remove chains of Region nodes.
- //### FIXME: add a DCE pass
-
- const auto offset = int(labelInfo.labelOffset);
- Node *control = createRegion(1);
- env()->setControlDependency(control);
- Node *effect = createEffectPhi(1, env()->effectDependency(), control);
- env()->setEffectDependency(effect);
-
- // insert/update phi nodes, but not for the unwind handler:
- for (int i = 0, ei = env()->slotCount() - 1; i != ei; ++i) {
- //### use lifeness info to trim this further!
- if (i == CallData::Accumulator)
- continue; // should never be alive on loop entry
- env()->bindNodeToSlot(createPhi(1, env()->slot(i), control), i);
- }
-
- m_envForOffset.insert(offset, env()->copy());
-}
-
-void GraphBuilder::startUnwinding()
-{
- if (int target = env()->unwindHandlerOffset()) {
- mergeIntoSuccessor(target);
- } else {
- bindAcc(graph()->undefinedNode());
- generate_Ret();
- }
-}
-
-void GraphBuilder::generate_Ret()
-{
- Node* control = createNode(opBuilder()->get<Meta::Return>(), env()->accumulator());
- queueFunctionExit(control);
-}
-
-void GraphBuilder::generate_Debug() { Q_UNREACHABLE(); }
-
-void GraphBuilder::generate_LoadConst(int index)
-{
- auto func = function()->v4Function();
- Value v = func->compilationUnit->constants[index];
- bindAcc(createNode(opBuilder()->getConstant(v)));
-}
-
-void GraphBuilder::generate_LoadZero()
-{
- bindAcc(createConstant(0));
-}
-
-void GraphBuilder::generate_LoadTrue()
-{
- bindAcc(m_graph->trueConstant());
-}
-
-void GraphBuilder::generate_LoadFalse()
-{
- bindAcc(m_graph->falseConstant());
-}
-
-void GraphBuilder::generate_LoadNull()
-{
- bindAcc(m_graph->nullNode());
-}
-
-void GraphBuilder::generate_LoadUndefined()
-{
- bindAcc(m_graph->undefinedNode());
-}
-
-void GraphBuilder::generate_LoadInt(int value)
-{
- bindAcc(m_graph->createNode(opBuilder()->getConstant(Primitive::fromInt32(value))));
-}
-
-void GraphBuilder::generate_MoveConst(int constIndex, int destTemp)
-{
- auto func = function()->v4Function();
- Value v = func->compilationUnit->constants[constIndex];
- env()->bindNodeToSlot(createNode(opBuilder()->getConstant(v)), destTemp);
-}
-
-void GraphBuilder::generate_LoadReg(int reg)
-{
- bindAcc(env()->slot(reg));
-}
-
-void GraphBuilder::generate_StoreReg(int reg)
-{
- Node *n = env()->accumulator();
- if (reg == CallData::This)
- n = createNode(opBuilder()->get<Meta::StoreThis>(), n);
- env()->bindNodeToSlot(n, reg);
-}
-
-void GraphBuilder::generate_MoveReg(int srcReg, int destReg)
-{
- env()->bindNodeToSlot(env()->slot(srcReg), destReg);
-}
-
-void GraphBuilder::generate_LoadImport(int index)
-{
- auto func = function()->v4Function();
- Value v = *func->compilationUnit->imports[index];
- bindAcc(createNode(opBuilder()->getConstant(v)));
-}
-
-void GraphBuilder::generate_LoadLocal(int index, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::ScopedLoad>(),
- createConstant(0),
- createConstant(index)));
-}
-
-void GraphBuilder::generate_StoreLocal(int index)
-{
- createNode(opBuilder()->get<Meta::ScopedStore>(),
- createConstant(0),
- createConstant(index),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadScopedLocal(int scope, int index, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::ScopedLoad>(),
- createConstant(scope),
- createConstant(index)));
-}
-
-void GraphBuilder::generate_StoreScopedLocal(int scope, int index)
-{
- createNode(opBuilder()->get<Meta::ScopedStore>(),
- createConstant(scope),
- createConstant(index),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadRuntimeString(int stringId)
-{
- auto func = function()->v4Function();
- Value v = Value::fromHeapObject(func->compilationUnit->runtimeStrings[stringId]);
- bindAcc(createNode(opBuilder()->getConstant(v)));
-}
-
-void GraphBuilder::generate_MoveRegExp(int regExpId, int destReg)
-{
- env()->bindNodeToSlot(createNode(opBuilder()->get<Meta::LoadRegExp>(),
- createConstant(regExpId)), destReg);
-}
-
-void GraphBuilder::generate_LoadClosure(int value)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadClosure>(),
- createConstant(value)));
-}
-
-void GraphBuilder::generate_LoadName(int name, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadName>(),
- createConstant(name)));
-}
-
-void GraphBuilder::generate_LoadGlobalLookup(int index, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadGlobalLookup>(), createConstant(index)));
-}
-
-void GraphBuilder::generate_StoreNameSloppy(int name)
-{
- createNode(opBuilder()->get<Meta::JSStoreNameSloppy>(), createConstant(name), env()->accumulator());
-}
-
-void GraphBuilder::generate_StoreNameStrict(int name)
-{
- createNode(opBuilder()->get<Meta::JSStoreNameStrict>(), createConstant(name), env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadElement(int base, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadElement>(),
- env()->slot(base),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_StoreElement(int base, int index, int /*traceSlot*/)
-{
- createNode(opBuilder()->get<Meta::JSStoreElement>(),
- env()->slot(base),
- env()->slot(index),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadProperty(int name, int /*traceSlot*/)
-{
- Node *n = createNode(opBuilder()->get<Meta::JSLoadProperty>(),
- env()->accumulator(),
- createConstant(name));
- bindAcc(n);
-}
-
-void GraphBuilder::generate_GetLookup(int index, int /*traceSlot*/)
-{
- Node *n = createNode(opBuilder()->get<Meta::JSGetLookup>(),
- env()->accumulator(),
- createConstant(index));
- bindAcc(n);
-}
-
-void GraphBuilder::generate_StoreProperty(int name, int base)
-{
- createNode(opBuilder()->get<Meta::JSStoreProperty>(),
- env()->slot(base),
- createConstant(name),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_SetLookup(int index, int base)
-{
-
- function()->v4Function()->isStrict()
- ? createNode(opBuilder()->get<Meta::JSSetLookupStrict>(), env()->slot(base),
- createConstant(index), env()->accumulator())
- : createNode(opBuilder()->get<Meta::JSSetLookupSloppy>(), env()->slot(base),
- createConstant(index), env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadSuperProperty(int property)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadSuperProperty>(),
- env()->slot(property)));
-}
-
-void GraphBuilder::generate_StoreSuperProperty(int property)
-{
- createNode(opBuilder()->get<Meta::JSStoreSuperProperty>(),
- createConstant(property),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_LoadQmlContextPropertyLookup(int propertyIndex, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::QMLLoadQmlContextPropertyLookup>(),
- createConstant(propertyIndex)));
-}
-
-void GraphBuilder::generate_Yield() { Q_UNREACHABLE(); }
-void GraphBuilder::generate_YieldStar() { Q_UNREACHABLE(); }
-void GraphBuilder::generate_Resume(int /*offset*/) { Q_UNREACHABLE(); }
-
-void GraphBuilder::finalizeCall(Operation::Kind kind, VarArgNodes &args, int argc, int argv)
-{
- populate(args, argc, argv);
- bindAcc(createAndLinkNode(opBuilder()->getJSVarArgsCall(kind, uint16_t(args.size())),
- args.data(), size_t(args.size())));
-}
-
-void GraphBuilder::generate_CallValue(int name, int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(name));
- finalizeCall(Meta::JSCallValue, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallWithReceiver(int name, int thisObject, int argc, int argv,
- int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(name));
- args.append(env()->slot(thisObject));
- finalizeCall(Meta::JSCallWithReceiver, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallProperty(int name, int base, int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(base));
- args.append(createConstant(name));
- finalizeCall(Meta::JSCallProperty, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv,
- int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(base));
- args.append(createConstant(lookupIndex));
- finalizeCall(Meta::JSCallLookup, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallElement(int base, int index, int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(base));
- args.append(env()->slot(index));
- finalizeCall(Meta::JSCallElement, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallName(int name, int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(createConstant(name));
- finalizeCall(Meta::JSCallName, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallPossiblyDirectEval(int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- finalizeCall(Meta::JSCallPossiblyDirectEval, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallGlobalLookup(int index, int argc, int argv, int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(createConstant(index));
- finalizeCall(Meta::JSCallGlobalLookup, args, argc, argv);
-}
-
-void GraphBuilder::generate_CallQmlContextPropertyLookup(int index, int argc, int argv,
- int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(createConstant(index));
- finalizeCall(Meta::QMLCallQmlContextPropertyLookup, args, argc, argv);
-}
-
-void GraphBuilder::generate_SetUnwindHandler(int offset)
-{
- m_currentUnwindHandlerOffset = offset ? absoluteOffset(offset) : 0;
- env()->setUnwindHandlerOffset(m_currentUnwindHandlerOffset);
-}
-
-void GraphBuilder::generate_UnwindDispatch()
-{
- auto e = createNode(opBuilder()->get<Meta::HasException>(), graph()->engineNode());
- createNode(opBuilder()->get<Meta::Branch>(), e);
- {
- InterpreterSubEnvironment subEnvironment(this);
- createIfTrue();
- startUnwinding();
- }
-
- createIfFalse();
-
- const auto unwindHandlerOffset = env()->unwindHandlerOffset();
- const auto fallthroughSuccessor = nextInstructionOffset();
- auto nContinuations = m_func->unwindLabelOffsets().size() + 1;
- if (unwindHandlerOffset)
- ++nContinuations;
- Q_ASSERT(nContinuations <= std::numeric_limits<unsigned>::max());
- createNode(opBuilder()->getUnwindDispatch(unsigned(nContinuations), unwindHandlerOffset,
- fallthroughSuccessor));
-
- {
- InterpreterSubEnvironment fallthroughEnv(this);
- mergeIntoSuccessor(fallthroughSuccessor);
- }
-
- if (unwindHandlerOffset) {
- InterpreterSubEnvironment unwindHandlerEnv(this);
- createHandleUnwind(unwindHandlerOffset);
- mergeIntoSuccessor(unwindHandlerOffset);
- }
-
- for (int unwindLabelOffset : m_func->unwindLabelOffsets()) {
- if (unwindLabelOffset <= currentInstructionOffset())
- continue;
- InterpreterSubEnvironment unwindLabelEnv(this);
- createHandleUnwind(unwindLabelOffset);
- mergeIntoSuccessor(unwindLabelOffset);
- }
-
- setEnv(nullptr);
-}
-
-void GraphBuilder::generate_UnwindToLabel(int level, int offset)
-{
- //### For de-optimization, the relative offset probably also needs to be stored
- int unwinder = absoluteOffset(offset);
- createNode(opBuilder()->get<Meta::UnwindToLabel>(),
- createConstant(level),
- createConstant(unwinder));
- m_func->addUnwindLabelOffset(unwinder);
- startUnwinding();
-}
-
-void GraphBuilder::generate_DeadTemporalZoneCheck(int name)
-{
- Node *check = createNode(opBuilder()->get<Meta::IsEmpty>(), env()->accumulator());
- createNode(opBuilder()->get<Meta::Branch>(), check);
-
- { //### it's probably better to handle this by de-optimizing
- InterpreterSubEnvironment subEnvironment(this);
- createIfTrue();
- createNode(opBuilder()->get<Meta::ThrowReferenceError>(),
- createConstant(name));
- startUnwinding();
- }
-
- createIfFalse();
-}
-
-void GraphBuilder::generate_ThrowException()
-{
- createNode(opBuilder()->get<Meta::Throw>(), env()->accumulator());
- startUnwinding();
-}
-
-void GraphBuilder::generate_GetException()
-{
- bindAcc(createNode(opBuilder()->get<Meta::GetException>()));
-}
-
-void GraphBuilder::generate_SetException()
-{
- createNode(opBuilder()->get<Meta::SetException>(),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_CreateCallContext()
-{
- createNode(opBuilder()->get<Meta::JSCreateCallContext>());
-}
-
-void GraphBuilder::generate_PushCatchContext(int index, int name)
-{
- createNode(opBuilder()->get<Meta::JSCreateCatchContext>(),
- createConstant(index),
- createConstant(name));
-}
-
-void GraphBuilder::generate_PushWithContext()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSCreateWithContext>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_PushBlockContext(int index)
-{
- createNode(opBuilder()->get<Meta::JSCreateBlockContext>(),
- createConstant(index));
-}
-
-void GraphBuilder::generate_CloneBlockContext()
-{
- createNode(opBuilder()->get<Meta::JSCloneBlockContext>());
-}
-
-void GraphBuilder::generate_PushScriptContext(int index)
-{
- createNode(opBuilder()->get<Meta::JSCreateScriptContext>(), createConstant(index));
-}
-
-void GraphBuilder::generate_PopScriptContext()
-{
- createNode(opBuilder()->get<Meta::JSPopScriptContext>());
-}
-
-void GraphBuilder::generate_PopContext()
-{
- createNode(opBuilder()->get<Meta::PopContext>());
-}
-
-void GraphBuilder::generate_GetIterator(int iterator)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSGetIterator>(),
- env()->accumulator(),
- createConstant(iterator)));
-}
-
-void GraphBuilder::generate_IteratorNextAndFriends_TrailingStuff(Node *iterationNode,
- int resultSlot)
-{
- // See generate_IteratorNext for why this method exists.
-
- // check that no-one messed around with the operation and made it throwing
- Q_ASSERT(iterationNode->operation()->controlOutputCount() == 1);
-
- // check that it's in the effect chain, because HasException relies on that
- Q_ASSERT(iterationNode->operation()->effectOutputCount() == 1);
-
- env()->bindNodeToSlot(createNode(opBuilder()->get<Meta::SelectOutput>(),
- iterationNode,
- createConstant(1),
- graph()->undefinedNode()),
- resultSlot);
- // Note: the following will NOT set the accumulator, because it contains the return value of
- // the runtime call!
- Node *ehCheck = createNode(opBuilder()->get<Meta::HasException>(), graph()->engineNode());
- createNode(opBuilder()->get<Meta::Branch>(), ehCheck);
-
- { // EH path:
- InterpreterSubEnvironment subEnvironment(this);
- createIfTrue();
- if (auto ehOffset = env()->unwindHandlerOffset()) {
- // Ok, there is an exception handler, so go there:
- mergeIntoSuccessor(ehOffset);
- } else {
- // No Exception Handler, so keep the exception set in the engine, and leave the function
- // a.s.a.p.:
- bindAcc(graph()->undefinedNode());
- generate_Ret();
- }
- }
-
- // Normal control flow:
- createIfFalse();
-}
-
-void GraphBuilder::generate_IteratorNext(int value, int done)
-{
- // The way we model exceptions in the graph is that a runtime function will either succeed and
- // return a value, or it fails and throws an exception. If it throws, the return value is not
- // used because the method did not complete normally, and therefore it might be tainted.
- //
- // This is a problem for (and only for) IteratorNext and IteratorNextForYieldStart.
- //
- // What would happen in the normal case, is that the return value (done) is not used/assigned
- // when IteratorNext throws, because the exception handling path is chosen. However, the
- // interpreter *does* assign it, and will only check for an exception *after* that assignment.
- //
- // So, in order to work around this odd-duck behavior, we mark the operation as NoThrow,
- // override the runtime method and flag it to not throw, and insert extra exception check nodes
- // after the SelectOutput that follows the IteratorNext(ForYieldStar).
- //
- // Also note that the IteratorNext and IteratorNextForYieldStar are the only operations that
- // have an inout parameter, and thus require a SelectOutput node to retrieve this.
-
- Node *n = createNode(opBuilder()->get<Meta::JSIteratorNext>(),
- env()->accumulator(),
- graph()->undefinedNode());
- bindAcc(n);
- env()->bindNodeToSlot(n, done);
- generate_IteratorNextAndFriends_TrailingStuff(n, value);
-}
-
-void GraphBuilder::generate_IteratorNextForYieldStar(int iterator, int object)
-{
- // Please, PLEASE read the comment in generate_IteratorNext.
- Node *n = createNode(opBuilder()->get<Meta::JSIteratorNextForYieldStar>(),
- env()->accumulator(),
- env()->slot(iterator),
- graph()->undefinedNode());
- // Note: the following is a tiny bit different from what generate_IteratorNext does.
- bindAcc(n);
- generate_IteratorNextAndFriends_TrailingStuff(n, object);
-}
-
-void GraphBuilder::generate_IteratorClose(int done)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSIteratorClose>(),
- env()->accumulator(),
- env()->slot(done)));
-}
-
-void GraphBuilder::generate_DestructureRestElement()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSDestructureRestElement>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_DeleteProperty(int base, int index)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSDeleteProperty>(),
- env()->slot(base),
- env()->slot(index)));
-}
-
-void GraphBuilder::generate_DeleteName(int name)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSDeleteName>(),
- createConstant(name)));
-}
-
-void GraphBuilder::generate_TypeofName(int name)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSTypeofName>(),
- createConstant(name)));
-}
-
-void GraphBuilder::generate_TypeofValue()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSTypeofValue>(), env()->accumulator()));
-}
-
-void GraphBuilder::generate_DeclareVar(int varName, int isDeletable)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSDeclareVar>(),
- createConstant(isDeletable),
- createConstant(varName)));
-}
-
-void GraphBuilder::generate_DefineArray(int argc, int argv)
-{
- VarArgNodes args;
- finalizeCall(Meta::JSDefineArray, args, argc, argv);
-}
-
-void GraphBuilder::generate_DefineObjectLiteral(int internalClassId, int argc, int argv)
-{
- VarArgNodes args;
- args.append(createConstant(internalClassId));
- finalizeCall(Meta::JSDefineObjectLiteral, args, argc, argv);
-}
-
-void GraphBuilder::generate_CreateClass(int classIndex, int heritage, int computedNames)
-{
- int argc = 0;
- int argv = computedNames;
-
- const QV4::CompiledData::Class *cls = function()->v4Function()->compilationUnit->unitData()
- ->classAt(classIndex);
- const CompiledData::Method *methods = cls->methodTable();
- for (uint i = 0; i < cls->nStaticMethods + cls->nMethods; ++i) {
- if (methods[i].name == std::numeric_limits<unsigned>::max())
- ++argc;
- }
-
- VarArgNodes args;
- args.append(createConstant(classIndex));
- args.append(env()->slot(heritage));
- finalizeCall(Meta::JSCreateClass, args, argc, argv);
-}
-
-void GraphBuilder::generate_CreateMappedArgumentsObject()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSCreateMappedArgumentsObject>()));
-}
-
-void GraphBuilder::generate_CreateUnmappedArgumentsObject()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSCreateUnmappedArgumentsObject>()));
-}
-
-void GraphBuilder::generate_CreateRestParameter(int argIndex)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSCreateRestParameter>(),
- createConstant(argIndex)));
-}
-
-void GraphBuilder::generate_ConvertThisToObject()
-{
- Node* control = createNode(opBuilder()->get<Meta::JSThisToObject>(),
- env()->slot(CallData::This));
- env()->bindNodeToSlot(control, CallData::This);
-}
-
-void GraphBuilder::generate_LoadSuperConstructor()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSLoadSuperConstructor>(),
- env()->slot(CallData::Function)));
-}
-
-void GraphBuilder::generate_ToObject()
-{
- bindAcc(createNode(opBuilder()->get<Meta::ToObject>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CallWithSpread(int func, int thisObject, int argc, int argv,
- int /*traceSlot*/)
-{
- VarArgNodes args;
- args.append(env()->slot(func));
- args.append(env()->slot(thisObject));
- finalizeCall(Meta::JSCallWithSpread, args, argc, argv);
-}
-
-void GraphBuilder::generate_TailCall(int func, int thisObject, int argc, int argv)
-{
- VarArgNodes args;
- args.append(env()->slot(func));
- args.append(env()->slot(thisObject));
- populate(args, argc, argv);
- Node *n = createAndLinkNode(opBuilder()->getJSTailCall(uint16_t(args.size())), args.data(),
- size_t(args.size()));
- queueFunctionExit(n);
-}
-
-void GraphBuilder::generate_Construct(int func, int argc, int argv)
-{
- VarArgNodes args;
- args.append(env()->slot(func));
- args.append(env()->accumulator());
- finalizeCall(Meta::JSConstruct, args, argc, argv);
-}
-
-void GraphBuilder::generate_ConstructWithSpread(int func, int argc, int argv)
-{
- VarArgNodes args;
- args.append(env()->slot(func));
- args.append(env()->accumulator());
- finalizeCall(Meta::JSConstructWithSpread, args, argc, argv);
-}
-
-void GraphBuilder::generate_Jump(int offset)
-{
- auto jumpTarget = absoluteOffset(offset);
- mergeIntoSuccessor(jumpTarget);
-}
-
-void GraphBuilder::generate_JumpTrue(int /*traceSlot*/, int offset)
-{
- createNode(opBuilder()->get<Meta::Branch>(), createToBoolean(env()->accumulator()));
-
- {
- InterpreterSubEnvironment subEnvironment(this);
- auto jumpTarget = absoluteOffset(offset);
- createIfTrue();
- mergeIntoSuccessor(jumpTarget);
- }
-
- createIfFalse();
-}
-
-void GraphBuilder::generate_JumpFalse(int traceSlot, int offset)
-{
- generate_JumpFalse(env()->accumulator(), traceSlot, offset);
-}
-
-void GraphBuilder::generate_JumpFalse(Node *condition, int /*traceSlot*/, int offset)
-{
- createNode(opBuilder()->get<Meta::Branch>(), createToBoolean(condition));
-
- {
- InterpreterSubEnvironment subEnvironment(this);
- auto jumpTarget = absoluteOffset(offset);
- createIfFalse();
- mergeIntoSuccessor(jumpTarget);
- }
-
- createIfTrue();
-}
-
-void GraphBuilder::generate_JumpNoException(int offset)
-{
- auto e = createNode(opBuilder()->get<Meta::HasException>(), graph()->engineNode());
- createNode(opBuilder()->get<Meta::Branch>(), e);
-
- {
- InterpreterSubEnvironment subEnvironment(this);
- auto jumpTarget = absoluteOffset(offset);
- createIfFalse();
- mergeIntoSuccessor(jumpTarget);
- }
-
- createIfTrue();
-}
-
-void GraphBuilder::generate_JumpNotUndefined(int offset)
-{
- Node *condition = createNode(opBuilder()->get<Meta::JSStrictEqual>(),
- env()->accumulator(),
- graph()->undefinedNode());
- generate_JumpFalse(condition, NoTraceSlot, offset);
-}
-
-void GraphBuilder::generate_CmpEqNull()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSEqual>(),
- env()->accumulator(),
- graph()->nullNode()));
-}
-
-void GraphBuilder::generate_CmpNeNull()
-{
- generate_CmpEqNull();
- bindAcc(createNode(opBuilder()->get<Meta::BooleanNot>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CmpEqInt(int lhs)
-{
- auto left = createConstant(lhs);
- Node* control = createNode(opBuilder()->get<Meta::JSEqual>(),
- left,
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpNeInt(int lhs)
-{
- generate_CmpEqInt(lhs);
- bindAcc(createNode(opBuilder()->get<Meta::BooleanNot>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CmpEq(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSEqual>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpNe(int lhs)
-{
- generate_CmpEq(lhs);
- bindAcc(createNode(opBuilder()->get<Meta::BooleanNot>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CmpGt(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSGreaterThan>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpGe(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSGreaterEqual>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpLt(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSLessThan>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpLe(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSLessEqual>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpStrictEqual(int lhs)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSStrictEqual>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_CmpStrictNotEqual(int lhs)
-{
- generate_CmpStrictEqual(lhs);
- bindAcc(createNode(opBuilder()->get<Meta::BooleanNot>(),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CmpIn(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSIn>(), env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_CmpInstanceOf(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSInstanceOf>(), env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_UNot()
-{
- bindAcc(createNode(opBuilder()->get<Meta::BooleanNot>(),
- createToBoolean(env()->accumulator())));
-}
-
-void GraphBuilder::generate_UPlus(int /*traceSlot*/)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSToNumber>(),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_UMinus(int /*traceSlot*/)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSNegate>(),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_UCompl()
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitXor>(),
- env()->accumulator(),
- createConstant(-1)));
-}
-
-void GraphBuilder::generate_Increment(int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSAdd>(),
- env()->accumulator(),
- createConstant(1)));
-}
-
-
-void GraphBuilder::generate_Decrement(int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSSubtract>(),
- env()->accumulator(),
- createConstant(1)));
-}
-
-void GraphBuilder::generate_Add(int lhs, int /*traceSlot*/)
-{
- Node* control = createNode(opBuilder()->get<Meta::JSAdd>(),
- env()->slot(lhs),
- env()->accumulator());
- bindAcc(control);
-}
-
-void GraphBuilder::generate_BitAnd(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitAnd>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_BitOr(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitOr>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_BitXor(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitXor>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_UShr(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSUnsignedShiftRight>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Shr(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSShiftRight>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Shl(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSShiftLeft>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-
-void GraphBuilder::generate_BitAndConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitAnd>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_BitOrConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitOr>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_BitXorConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSBitXor>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_UShrConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSUnsignedShiftRight>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_ShrConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSShiftRight>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_ShlConst(int rhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSShiftLeft>(),
- env()->accumulator(),
- createConstant(rhs)));
-}
-
-void GraphBuilder::generate_Exp(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSExponentiate>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Mul(int lhs, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSMultiply>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Div(int lhs)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSDivide>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Mod(int lhs, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSModulo>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_Sub(int lhs, int /*traceSlot*/)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSSubtract>(),
- env()->slot(lhs),
- env()->accumulator()));
-}
-
-void GraphBuilder::generate_InitializeBlockDeadTemporalZone(int firstReg, int count)
-{
- for (int reg = firstReg; reg < firstReg + count; ++reg)
- env()->bindNodeToSlot(graph()->emptyNode(), reg);
-}
-
-void GraphBuilder::generate_ThrowOnNullOrUndefined()
-{
- createNode(opBuilder()->get<Meta::JSThrowOnNullOrUndefined>(),
- env()->accumulator());
-}
-
-void GraphBuilder::generate_GetTemplateObject(int index)
-{
- bindAcc(createNode(opBuilder()->get<Meta::JSGetTemplateObject>(),
- createConstant(index)));
-}
-
-GraphBuilder::Verdict GraphBuilder::startInstruction(Moth::Instr::Type /*instr*/)
-{
- // This handles a couple of cases on how flow control can end up at this instruction.
-
- const auto off = currentInstructionOffset();
- if (auto newEnv = m_envForOffset[off]) {
- // Ok, there was a jump from before to this point (which registered an environment), so we
- // have two options:
- if (env() != newEnv && env() != nullptr) {
- // There is a current environment different from the environment active when we took the
- // jump. This happens with e.g. an if-then-else:
- //
- // acc = condition
- // JumpFalse else-block
- // ... then block
- // Jump end-if
- // else-block:
- // ... else block
- // end-if:
- // .. some instruction <--- we're here
- //
- // in that case we merge the after-else environment into the after-then environment:
- newEnv->merge(env());
- } else {
- // There is not a current environment. This can happen with e.g. a loop:
- // loop-start:
- // acc = condition
- // JumpFalse loop-end
- // ... loop body
- // Jump loop-start
- // loop-end:
- // .... some instruction <--- we're here
- //
- // The last jump of the loop will clear the environment, so at this point we only have
- // the environment registered by the JumpFalse. This is the asy case: no merges, just
- // take the registered environment unchanged.
- }
-
- // Leave the merged environment as-is, and continue with a copy. We cannot change the
- // registered environment in case this point also happens to be a loop start.
- setEnv(newEnv->copy());
- }
-
- if (env() == nullptr) {
- // Ok, there is no environment, meaning nobody jumped to this instruction, and the previous
- // instruction doesn't let control flow end up here. So, this is dead code.
- // This can happen for JS like:
- //
- // if (condition) {
- // return something
- // } else {
- // return somethingElse
- // }
- // someCode <--- we're here
- return SkipInstruction;
- }
-
- const LabelInfo *info = isLoopStart(off);
- if (info && env()) {
- // Ok, this instruction is the start of a loop, meaning there will be a jump backwards to
- // this point. Make sure there is a Region node with Phi nodes here.
- handleLoopStart(*info);
- }
-
- return ProcessInstruction;
-}
-
-void GraphBuilder::endInstruction(Moth::Instr::Type /*instr*/) {}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4graphbuilder_p.h b/src/qml/jit/qv4graphbuilder_p.h
deleted file mode 100644
index 450d8640b7..0000000000
--- a/src/qml/jit/qv4graphbuilder_p.h
+++ /dev/null
@@ -1,298 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4GRAPHBUILDER_P_H
-#define QV4GRAPHBUILDER_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 <private/qv4global_p.h>
-#include <private/qv4bytecodehandler_p.h>
-#include <private/qv4ir_p.h>
-#include "qv4graph_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-// The graph builder walks the byte-code, and produces a graph. The graph is a digraph, where the
-// nodes have operations, and the edges are dependencies (or inputs).
-class GraphBuilder: protected Moth::ByteCodeHandler
-{
- Q_DISABLE_COPY_MOVE(GraphBuilder)
-
- enum { NoTraceSlot = -1 };
-
- struct LabelInfo { //### extend this to also capture the amount of slots that are live
- LabelInfo() = default;
- LabelInfo(unsigned label) : labelOffset(label) {}
- unsigned labelOffset = 0;
- };
-
-public:
- static void buildGraph(IR::Function *function);
-
- class InterpreterEnvironment;
-
- void setEnv(InterpreterEnvironment *newEnv)
- { m_currentEnv = newEnv; }
-
- InterpreterEnvironment *env() const
- { return m_currentEnv; }
-
-private:
- GraphBuilder(IR::Function *function);
- ~GraphBuilder() override = default;
-
- void startGraph();
- void endGraph();
-
- Node *bindAcc(Node *n);
- Node *createAndLinkNode(Operation *op, Node *operands[], size_t opCount, bool incomplete = false);
- Node *createNode(Operation *op, bool incomplete = false);
- Node *createNode(Operation *op, Node *n1);
- Node *createNode(Operation *op, Node *n1, Node *n2);
- Node *createNode(Operation *op, Node *n1, Node *n2, Node *n3);
- Node *createNode(Operation *op, Node *n1, Node *n2, Node *n3, Node *n4);
- Node *createRegion(unsigned nControlInputs);
- Node *createIfTrue();
- Node *createIfFalse();
- Node *createConstant(int v);
- Node *createPhi(unsigned nInputs, Node *input, Node *control);
- Node *createEffectPhi(unsigned nInputs, Node *input, Node *control);
- Node *createHandleUnwind(int offset);
- Node *mergeControl(Node *c1, Node *c2);
- Node *mergeEffect(Node *e1, Node *e2, Node *control);
- Node *mergeValue(Node *v1, Node *v2, Node *control);
-
- Node *createToBoolean(Node *input);
-
- using VarArgNodes = QVarLengthArray<Node *, 32>;
- void populate(VarArgNodes &args, int argc, int argv);
-
- void queueFunctionExit(Node *exitNode);
-
- Function *function() const
- { return m_func; }
-
- Graph *graph()
- { return m_graph; }
-
- Node *mergeIntoSuccessor(int offset);
-
- OperationBuilder *opBuilder() const
- { return m_graph->opBuilder(); }
-
- int absoluteOffset(int offset) const
- { return offset + nextInstructionOffset(); }
-
- const LabelInfo *labelInfoAt(unsigned offset) const;
- const LabelInfo *isLoopStart(unsigned offset) const;
- void handleLoopStart(const LabelInfo &labelInfo);
- void startUnwinding();
-
-protected: // ByteCodeHandler
- void generate_Ret() override;
- void generate_Debug() override;
- void generate_LoadConst(int index) override;
- void generate_LoadZero() override;
- void generate_LoadTrue() override;
- void generate_LoadFalse() override;
- void generate_LoadNull() override;
- void generate_LoadUndefined() override;
- void generate_LoadInt(int value) override;
- void generate_MoveConst(int constIndex, int destTemp) override;
- void generate_LoadReg(int reg) override;
- void generate_StoreReg(int reg) override;
- void generate_MoveReg(int srcReg, int destReg) override;
- void generate_LoadImport(int index) override;
- void generate_LoadLocal(int index, int traceSlot) override;
- void generate_StoreLocal(int index) override;
- void generate_LoadScopedLocal(int scope, int index, int traceSlot) override;
- void generate_StoreScopedLocal(int scope, int index) override;
- void generate_LoadRuntimeString(int stringId) override;
- void generate_MoveRegExp(int regExpId, int destReg) override;
- void generate_LoadClosure(int value) override;
- void generate_LoadName(int name, int traceSlot) override;
- void generate_LoadGlobalLookup(int index, int traceSlot) override;
- void generate_StoreNameSloppy(int name) override;
- void generate_StoreNameStrict(int name) override;
- void generate_LoadElement(int base, int traceSlot) override;
- void generate_StoreElement(int base, int index, int traceSlot) override;
- void generate_LoadProperty(int name, int traceSlot) override;
- void generate_GetLookup(int index, int traceSlot) override;
- void generate_StoreProperty(int name, int base) override;
- void generate_SetLookup(int index, int base) override;
- void generate_LoadSuperProperty(int property) override;
- void generate_StoreSuperProperty(int property) override;
- void generate_LoadQmlContextPropertyLookup(int property, int traceSlot) override;
- void generate_Yield() override;
- void generate_YieldStar() override;
- void generate_Resume(int offset) override;
- void finalizeCall(Operation::Kind kind, VarArgNodes &args, int argc, int argv);
- void generate_CallValue(int name, int argc, int argv, int traceSlot) override;
- void generate_CallWithReceiver(int name, int thisObject, int argc, int argv,
- int traceSlot) override;
- void generate_CallProperty(int name, int base, int argc, int argv, int traceSlot) override;
- void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv,
- int traceSlot) override;
- void generate_CallElement(int base, int index, int argc, int argv, int traceSlot) override;
- void generate_CallName(int name, int argc, int argv, int traceSlot) override;
- void generate_CallPossiblyDirectEval(int argc, int argv, int traceSlot) override;
- void generate_CallGlobalLookup(int index, int argc, int argv, int traceSlot) override;
- void generate_CallQmlContextPropertyLookup(int index, int argc, int argv, int traceSlot) override;
- void generate_SetUnwindHandler(int offset) override;
- void generate_UnwindDispatch() override;
- void generate_UnwindToLabel(int level, int offset) override;
- void generate_DeadTemporalZoneCheck(int name) override;
- void generate_ThrowException() override;
- void generate_GetException() override;
- void generate_SetException() override;
- void generate_CreateCallContext() override;
- void generate_PushCatchContext(int index, int name) override;
- void generate_PushWithContext() override;
- void generate_PushBlockContext(int index) override;
- void generate_CloneBlockContext() override;
- void generate_PushScriptContext(int index) override;
- void generate_PopScriptContext() override;
- void generate_PopContext() override;
- void generate_GetIterator(int iterator) override;
- void generate_IteratorNextAndFriends_TrailingStuff(Node *iterationNode, int resultSlot);
- void generate_IteratorNext(int value, int done) override;
- void generate_IteratorNextForYieldStar(int iterator, int object) override;
- void generate_IteratorClose(int done) override;
- void generate_DestructureRestElement() override;
- void generate_DeleteProperty(int base, int index) override;
- void generate_DeleteName(int name) override;
- void generate_TypeofName(int name) override;
- void generate_TypeofValue() override;
- void generate_DeclareVar(int varName, int isDeletable) override;
- void generate_DefineArray(int argc, int argv) override;
- void generate_DefineObjectLiteral(int internalClassId, int argc, int argv) override;
- void generate_CreateClass(int classIndex, int heritage, int computedNames) override;
- void generate_CreateMappedArgumentsObject() override;
- void generate_CreateUnmappedArgumentsObject() override;
- void generate_CreateRestParameter(int argIndex) override;
- void generate_ConvertThisToObject() override;
- void generate_LoadSuperConstructor() override;
- void generate_ToObject() override;
- void generate_CallWithSpread(int func, int thisObject, int argc, int argv,
- int traceSlot) override;
- void generate_TailCall(int func, int thisObject, int argc, int argv) override;
- void generate_Construct(int func, int argc, int argv) override;
- void generate_ConstructWithSpread(int func, int argc, int argv) override;
- void generate_Jump(int offset) override;
- void generate_JumpTrue(int traceSlot, int offset) override;
- void generate_JumpFalse(int traceSlot, int offset) override;
- void generate_JumpFalse(Node *condition, int traceSlot, int offset);
- void generate_JumpNoException(int offset) override;
- void generate_JumpNotUndefined(int offset) override;
- void generate_CmpEqNull() override;
- void generate_CmpNeNull() override;
- void generate_CmpEqInt(int lhs) override;
- void generate_CmpNeInt(int lhs) override;
- void generate_CmpEq(int lhs) override;
- void generate_CmpNe(int lhs) override;
- void generate_CmpGt(int lhs) override;
- void generate_CmpGe(int lhs) override;
- void generate_CmpLt(int lhs) override;
- void generate_CmpLe(int lhs) override;
- void generate_CmpStrictEqual(int lhs) override;
- void generate_CmpStrictNotEqual(int lhs) override;
- void generate_CmpIn(int lhs) override;
- void generate_CmpInstanceOf(int lhs) override;
- void generate_UNot() override;
- void generate_UPlus(int traceSlot) override;
- void generate_UMinus(int traceSlot) override;
- void generate_UCompl() override;
- void generate_Increment(int traceSlot) override;
- void generate_Decrement(int traceSlot) override;
- void generate_Add(int lhs, int traceSlot) override;
- void generate_BitAnd(int lhs) override;
- void generate_BitOr(int lhs) override;
- void generate_BitXor(int lhs) override;
- void generate_UShr(int lhs) override;
- void generate_Shr(int lhs) override;
- void generate_Shl(int lhs) override;
- void generate_BitAndConst(int rhs) override;
- void generate_BitOrConst(int rhs) override;
- void generate_BitXorConst(int rhs) override;
- void generate_UShrConst(int rhs) override;
- void generate_ShrConst(int rhs) override;
- void generate_ShlConst(int rhs) override;
- void generate_Exp(int lhs) override;
- void generate_Mul(int lhs, int traceSlot) override;
- void generate_Div(int lhs) override;
- void generate_Mod(int lhs, int traceSlot) override;
- void generate_Sub(int lhs, int traceSlot) override;
- void generate_InitializeBlockDeadTemporalZone(int firstReg, int count) override;
- void generate_ThrowOnNullOrUndefined() override;
- void generate_GetTemplateObject(int index) override;
-
- Verdict startInstruction(Moth::Instr::Type instr) override;
- void endInstruction(Moth::Instr::Type instr) override;
-
-private:
- IR::Function *m_func;
- Graph *m_graph;
- InterpreterEnvironment *m_currentEnv;
- std::vector<Node *> m_exitControls;
- QHash<int, InterpreterEnvironment *> m_envForOffset;
- std::vector<LabelInfo> m_labelInfos;
- int m_currentUnwindHandlerOffset = 0;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4GRAPHBUILDER_P_H
diff --git a/src/qml/jit/qv4ir.cpp b/src/qml/jit/qv4ir.cpp
deleted file mode 100644
index cb3eeeec60..0000000000
--- a/src/qml/jit/qv4ir.cpp
+++ /dev/null
@@ -1,382 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <private/qqmlglobal_p.h>
-#include "qv4ir_p.h"
-#include "qv4node_p.h"
-#include "qv4function_p.h"
-#include <qv4graph_p.h>
-#include "qv4stackframe_p.h"
-#include "qv4operation_p.h"
-#include "qv4util_p.h"
-
-#include <QtCore/qloggingcategory.h>
-#include <QtCore/qjsonobject.h>
-#include <QtCore/qjsonarray.h>
-#include <QtCore/qfile.h>
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcJsonIR, "qt.v4.ir.json");
-Q_LOGGING_CATEGORY(lcDotIR, "qt.v4.ir.dot");
-Q_LOGGING_CATEGORY(lcVerify, "qt.v4.ir.verify");
-
-Function::Function(QV4::Function *qv4Function)
- : qv4Function(qv4Function)
- , m_graph(Graph::create(this))
- , m_dumper(nullptr)
- , m_nodeInfo(128, nullptr)
-{
-}
-
-Function::~Function()
-{
- delete m_dumper;
-}
-
-QString Function::name() const
-{
- QString name;
- if (auto n = v4Function()->name())
- name = n->toQString();
- if (name.isEmpty())
- name = QString::asprintf("%p", v4Function());
- auto loc = v4Function()->sourceLocation();
- return name + QStringLiteral(" (%1:%2:%3)").arg(loc.sourceFile, QString::number(loc.line),
- QString::number(loc.column));
-}
-
-void Function::dump(const QString &description) const
-{
- Dumper::dump(this, description);
-}
-
-void Function::dump() const
-{
- dump(QStringLiteral("Debug:"));
-}
-
-Dumper *Function::dumper() const
-{
- if (!m_dumper)
- m_dumper = new Dumper(this);
- return m_dumper;
-}
-
-Function::StringId Function::addString(const QString &s)
-{
- m_stringPool.push_back(s);
- return m_stringPool.size() - 1;
-}
-
-NodeInfo *Function::nodeInfo(Node *n, bool createIfNecessary) const
-{
- if (n->id() >= m_nodeInfo.size())
- m_nodeInfo.resize(n->id() * 2, nullptr);
-
- NodeInfo *&info = m_nodeInfo[n->id()];
- if (info == nullptr && createIfNecessary) {
- info = m_pool.New<NodeInfo>();
- info->setType(n->operation()->type());
- }
- return info;
-}
-
-void Function::copyBytecodeOffsets(Node *from, Node *to)
-{
- auto toInfo = nodeInfo(to);
- if (auto fromInfo = nodeInfo(from)) {
- toInfo->setBytecodeOffsets(fromInfo->currentInstructionOffset(),
- fromInfo->nextInstructionOffset());
- }
-}
-
-Dumper::Dumper(const Function *f)
-{
- if (!f)
- return;
-}
-
-void Dumper::dump(const Function *f, const QString &description)
-{
- if (false && lcJsonIR().isDebugEnabled()) {
- Dumper *dumper = f->dumper();
-
- qCDebug(lcJsonIR).noquote().nospace() << description + QLatin1String(":\n");
- for (const auto &line : dumper->dump(f).split('\n'))
- qCDebug(lcJsonIR).noquote().nospace() << line;
- }
-
- if (lcDotIR().isDebugEnabled())
- dot(f, description);
-}
-
-QByteArray Dumper::dump(const Function *f)
-{
- QJsonObject fo;
-
- {
- QString name;
- if (auto n = f->v4Function()->name())
- name = n->toQString();
- fo[QLatin1String("_searchKey")] = QStringLiteral("function %1").arg(name);
- if (name.isEmpty())
- name = QString::asprintf("%p", f->v4Function());
- fo[QLatin1String("name")] = name;
- }
-
- auto loc = f->v4Function()->sourceLocation();
- fo[QLatin1String("source")] = loc.sourceFile;
- fo[QLatin1String("line")] = loc.line;
- fo[QLatin1String("column")] = loc.column;
-
- {
- QJsonArray gn;
- QJsonArray ge;
- NodeCollector nodes(f->graph(), /*collectUses =*/ true);
- nodes.sortById();
- for (Node *n : nodes.reachable()) {
- gn.append(dump(n, f));
- int inputIndex = 0;
- for (Node *input : n->inputs()) {
- QJsonObject edge;
- edge[QLatin1String("from")] = int(input->id());
- edge[QLatin1String("to")] = int(n->id());
- edge[QLatin1String("index")] = inputIndex;
- if (inputIndex < n->operation()->valueInputCount()) {
- edge[QLatin1String("type")] = QLatin1String("value");
- } else if (inputIndex < n->operation()->valueInputCount()
- + n->operation()->effectInputCount()) {
- edge[QLatin1String("type")] = QLatin1String("effect");
- } else {
- edge[QLatin1String("type")] = QLatin1String("control");
- }
- Q_ASSERT(inputIndex < n->operation()->valueInputCount()
- + n->operation()->effectInputCount()
- + n->operation()->controlInputCount());
- ge.append(edge);
- ++inputIndex;
- }
- }
- QJsonObject g;
- g[QLatin1String("nodes")] = gn;
- g[QLatin1String("edges")] = ge;
- fo[QLatin1String("graph")] = g;
- }
-
- m_doc.setObject(fo);
- return m_doc.toJson(QJsonDocument::Indented);
-}
-
-QJsonValue toJSonValue(QV4::Value v)
-{
- switch (v.type()) {
- case QV4::Value::Undefined_Type: return QJsonValue(QJsonValue::Undefined);
- case QV4::Value::Null_Type: return QJsonValue(QJsonValue::Null);
- case QV4::Value::Boolean_Type: return QJsonValue(v.booleanValue());
- case QV4::Value::Integer_Type: return QJsonValue(v.int_32());
- case QV4::Value::Managed_Type:
- if (String *s = v.stringValue())
- return QJsonValue(s->toQString());
- else
- return QJsonValue(QLatin1String("<managed>"));
- default: return QJsonValue(v.doubleValue());
- }
-}
-
-QJsonValue Dumper::dump(const Node * const node, const Function *f)
-{
- QJsonObject n;
- n[QLatin1String("id")] = int(node->id());
- n[QLatin1String("kind")] = node->operation()->debugString();
- switch (node->operation()->kind()) {
- case Meta::Parameter: {
- auto info = ParameterPayload::get(*node->operation());
- n[QLatin1String("name")] = f->string(info->stringId());
- n[QLatin1String("index")] = int(info->parameterIndex());
- break;
- }
- case Meta::Constant: {
- auto info = ConstantPayload::get(*node->operation());
- n[QLatin1String("value")] = toJSonValue(info->value());
- break;
- }
- default:
- break;
- }
- return n;
-}
-
-void Dumper::dot(const Function *f, const QString &description)
-{
- static const bool skipFramestate = qEnvironmentVariableIsSet("QV4_JIT_DOT_SKIP_FRAMESTATE");
-
- auto node = [](Node *n) {
- return QStringLiteral("n%1[label=\"%1: %2%3\"];\n").arg(QString::number(n->id()),
- n->operation()->debugString(),
- n->isDead() ? QStringLiteral(" (dead)")
- : QString());
- };
-
- Graph *g = f->graph();
- QString out;
- out += QLatin1Char('\n');
- out += QStringLiteral("digraph{root=\"n%1\" label=\"%2\";"
- "node[shape=rect];"
- "edge[dir=back fontsize=10];\n")
- .arg(g->startNode()->id())
- .arg(description);
- out += node(g->startNode());
- const bool dumpUses = false; // set to true to see all nodes
- NodeCollector nodes(g, dumpUses, skipFramestate);
- for (Node *n : nodes.reachable()) {
- if (n == g->startNode())
- continue;
-
- out += node(n);
-
- unsigned inputIndex = 0;
- for (Node *input : n->inputs()) {
- if (input == nullptr)
- continue;
- out += QStringLiteral("n%2->n%1[style=").arg(QString::number(n->id()),
- QString::number(input->id()));
- if (inputIndex < n->operation()->valueInputCount() ||
- inputIndex == n->operation()->indexOfFrameStateInput()) {
- out += QStringLiteral("solid headlabel=\"%1\"").arg(inputIndex);
- } else if (inputIndex < unsigned(n->operation()->valueInputCount()
- + n->operation()->effectInputCount())) {
- out += QStringLiteral("dotted headlabel=\"%1\"").arg(inputIndex);
- } else {
- out += QStringLiteral("dashed headlabel=\"%1\"").arg(inputIndex);
- }
- out += QStringLiteral("];\n");
- ++inputIndex;
- }
- }
- out += QStringLiteral("}\n");
- qCDebug(lcDotIR).nospace().noquote() << out;
-
- QFile of(description + QStringLiteral(".dot"));
- of.open(QIODevice::WriteOnly);
- of.write(out.toUtf8());
- of.close();
-}
-
-void Function::verify() const
-{
-#ifndef QT_NO_DEBUG
- unsigned problemsFound = 0;
-
- auto verifyNodeAgainstOperation = [&problemsFound](const Node *n) {
- const Operation *op = n->operation();
- if (op->totalInputCount() != n->inputCount()) {
- ++problemsFound;
- qCDebug(lcVerify()) << "Node" << n->id() << "has" << n->inputCount()
- << "inputs, but it's operation" << op->debugString()
- << "requires" << op->totalInputCount() << "inputs";
- }
-
- if (n->opcode() == Meta::Phi || n->opcode() == Meta::EffectPhi) {
- if (n->controlInput()->opcode() != Meta::Region) {
- ++problemsFound;
- qCDebug(lcVerify()) << "Control input of phi node" << n->id() << "is not a region";
- }
- if (n->controlInput()->inputCount() + 1 != n->inputCount()) {
- ++problemsFound;
- qCDebug(lcVerify()) << "Control input of phi node" << n->id()
- << "has" << n->controlInput()->inputCount()
- << "inputs while phi node has" << n->inputCount()
- << "inputs";
- }
- }
-
- //### todo: verify outputs: value outputs are allowed to be unused, but the effect and
- // control outputs have to be linked up, except:
- //### todo: verify if no use is a nullptr, except for operations that can throw, where the
- // last one is allowed to be a nullptr when an unwind handler is missing.
- };
-
- NodeWorkList todo(graph());
- todo.enqueue(graph()->endNode());
- while (Node *n = todo.dequeueNextNodeForVisiting()) {
- todo.enqueueAllInputs(n);
- todo.enqueueAllUses(n);
-
- verifyNodeAgainstOperation(n);
- }
- //### TODO:
- if (problemsFound != 0) {
- dump(QStringLiteral("Problematic graph"));
- qFatal("Found %u problems during graph verification!", problemsFound);
- }
-#endif // QT_NO_xDEBUG
-}
-
-QString Type::debugString() const
-{
- if (isNone())
- return QStringLiteral("none");
- if (isInvalid())
- return QStringLiteral("invalid");
-
- QStringList s;
- if (m_t & Bool)
- s += QStringLiteral("boolean");
- if (m_t & Int32)
- s += QStringLiteral("int32");
- if (m_t & Double)
- s += QStringLiteral("double");
- if (m_t & Undefined)
- s += QStringLiteral("undefined");
- if (m_t & Null)
- s += QStringLiteral("null");
- if (m_t & Empty)
- s += QStringLiteral("empty");
- if (m_t & RawPointer)
- s += QStringLiteral("raw pointer");
-
- return s.join(QLatin1String(" "));
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4ir_p.h b/src/qml/jit/qv4ir_p.h
deleted file mode 100644
index e21a80528d..0000000000
--- a/src/qml/jit/qv4ir_p.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4IR_P_H
-#define QV4IR_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 <private/qv4function_p.h>
-#include <QtCore/qjsondocument.h>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class Dumper;
-class Graph;
-
-class Node;
-class NodeInfo;
-
-class Function
-{
- Q_DISABLE_COPY_MOVE(Function)
-public:
- Function(QV4::Function *qv4Function);
- ~Function();
-
- void verify() const;
-
- QV4::Function *v4Function() const
- { return qv4Function; }
-
- QString name() const;
-
- QQmlJS::MemoryPool *pool()
- { return &m_pool; }
-
- Graph *graph() const
- { return m_graph; }
-
- void dump(const QString &description) const;
- void dump() const; // for calling in the debugger
- Dumper *dumper() const;
-
- using StringId = size_t;
- StringId addString(const QString &s);
- QString string(StringId id) const
- { return m_stringPool[id]; }
-
- NodeInfo *nodeInfo(Node *n, bool createIfNecessary = true) const;
- void copyBytecodeOffsets(Node *from, Node *to);
-
- void addUnwindLabelOffset(int absoluteOffset)
- { m_unwindLabelOffsets.push_back(absoluteOffset); }
-
- const std::vector<int> &unwindLabelOffsets() const
- { return m_unwindLabelOffsets; }
-
-private:
- QV4::Function *qv4Function;
- mutable QQmlJS::MemoryPool m_pool;
- Graph *m_graph;
- mutable Dumper *m_dumper;
- std::vector<QString> m_stringPool;
- mutable std::vector<NodeInfo *> m_nodeInfo; //### move the into the _pool
- std::vector<int> m_unwindLabelOffsets;
-};
-
-class Dumper
-{
- Q_DISABLE_COPY_MOVE(Dumper)
-
-public:
- Dumper(const Function *f);
- ~Dumper() = default;
-
- static void dump(const Function *f, const QString &description);
- static void dot(const Function *f, const QString &description);
-
-private:
- QByteArray dump(const Function *f);
- QJsonValue dump(const Node *node, const Function *f);
-
-private:
- QJsonDocument m_doc;
-};
-
-class Type
-{
- // None is for nodes with no type (e.g. a Return)
- // The others form a lattice:
- // Any -> Object -> Invalid
- // ^^^ -> Number -> Integral -> Int32 -> ^^^^^^^
- // ^^^ -> Number -> Integral -> UInt32 -> ^^^^^^^
- // ^^^ -> Number -> Integral -> Bool -> ^^^^^^^
- // ^^^ -> Number -> Double -> ^^^^^^^
- // ^^^ -> Undefined -> ^^^^^^^
- // ^^^ -> Null -> ^^^^^^^
- // ^^^ -> Empty -> ^^^^^^^
- enum InternalType: int16_t {
- None = 0,
-
- Object = 1 << 0,
- Bool = 1 << 1,
- Int32 = 1 << 2,
- UInt32 = 1 << 3,
- Double = 1 << 4,
- Undefined = 1 << 5,
- Null = 1 << 6,
- Empty = 1 << 7,
- RawPointer = 1 << 8,
- Invalid = -1,
-
- Integral = Int32 | UInt32 | Bool,
- Number = Integral | Double,
- Any = Object | Number | Undefined | Empty | Null,
- };
-
- Type(InternalType t) : m_t(t) {}
-
-public:
- Type() = default;
-
- bool operator==(const Type &other) const
- { return m_t == other.m_t; }
-
- static Type noneType() { return Type(None); }
- static Type anyType() { return Type(Any); }
- static Type undefinedType() { return Type(Undefined); }
- static Type emptyType() { return Type(Empty); }
- static Type booleanType() { return Type(Bool); }
- static Type int32Type() { return Type(Int32); }
- static Type doubleType() { return Type(Double); }
- static Type numberType() { return Type(Number); }
- static Type nullType() { return Type(Null); }
- static Type objectType() { return Type(Object); }
- static Type rawPointerType() { return Type(RawPointer); }
-
- bool isAny() const { return m_t == Any; }
- bool isBoolean() const { return m_t == Bool; }
- bool isInt32() const { return m_t == Int32; }
- bool isInvalid() const { return m_t == Invalid; }
- bool isNone() const { return m_t == None; }
- bool isDouble() const { return m_t == Double; }
- bool isUndefined() const { return m_t == Undefined; }
- bool isNull() const { return m_t == Null; }
- bool isEmpty() const { return m_t == Empty; }
- bool isObject() const { return m_t == Object; }
- bool isRawPointer() const { return m_t == RawPointer; }
- bool isIntegral() const { return matches(Integral); }
- bool isNumber() const { return matches(Number); }
-
- Type operator|(Type other) const
- { return Type(InternalType(int16_t(m_t) | int16_t(other.m_t))); }
-
- Type &operator|=(Type other)
- {
- m_t = (InternalType(int16_t(m_t) | int16_t(other.m_t)));
- return *this;
- }
-
- QString debugString() const;
-
-private:
- bool matches(InternalType it) const
- {
- return (m_t & ~it) == 0 && (m_t & it) != 0;
- }
-
-private:
- InternalType m_t = None;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4IR_P_H
diff --git a/src/qml/jit/qv4loopinfo.cpp b/src/qml/jit/qv4loopinfo.cpp
deleted file mode 100644
index 0366c49e30..0000000000
--- a/src/qml/jit/qv4loopinfo.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-
-#include "qv4loopinfo_p.h"
-#include "qv4domtree_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcLoopinfo, "qt.v4.ir.loopinfo")
-
-void LoopInfo::detectLoops()
-{
- blockInfos.resize(dt.function()->blockCount());
-
- std::vector<MIBlock *> backedges;
- backedges.reserve(4);
-
- const auto order = dt.calculateDFNodeIterOrder();
- for (MIBlock *bb : order) {
- if (bb->isDeoptBlock())
- continue;
-
- backedges.clear();
-
- for (MIBlock *pred : bb->inEdges()) {
- if (bb == pred || dt.dominates(bb->index(), pred->index()))
- backedges.push_back(pred);
- }
-
- if (!backedges.empty())
- subLoop(bb, backedges);
- }
-
- collectLoopExits();
-
- dump();
-}
-
-void LoopInfo::collectLoopExits()
-{
- for (MIBlock::Index i = 0, ei = MIBlock::Index(blockInfos.size()); i != ei; ++i) {
- BlockInfo &bi = blockInfos[i];
- MIBlock *currentBlock = dt.function()->block(i);
- if (bi.isLoopHeader) {
- for (MIBlock *outEdge : currentBlock->outEdges()) {
- if (outEdge != currentBlock && !inLoopOrSubLoop(outEdge, currentBlock))
- bi.loopExits.push_back(outEdge);
- }
- }
- if (MIBlock *containingLoop = bi.loopHeader) {
- BlockInfo &loopInfo = blockInfos[containingLoop->index()];
- for (MIBlock *outEdge : currentBlock->outEdges()) {
- if (outEdge != containingLoop && !inLoopOrSubLoop(outEdge, containingLoop))
- loopInfo.loopExits.push_back(outEdge);
- }
- }
- }
-}
-
-bool LoopInfo::inLoopOrSubLoop(MIBlock *block, MIBlock *loopHeader) const
-{
- const BlockInfo &bi = blockInfos[block->index()];
- MIBlock *loopHeaderForBlock = bi.loopHeader;
- if (loopHeaderForBlock == nullptr)
- return false; // block is not in any loop
-
- while (loopHeader) {
- if (loopHeader == loopHeaderForBlock)
- return true;
- // look into the parent loop of loopHeader to see if block is contained there
- loopHeader = blockInfos[loopHeader->index()].loopHeader;
- }
-
- return false;
-}
-
-void LoopInfo::subLoop(MIBlock *loopHead, const std::vector<MIBlock *> &backedges)
-{
- blockInfos[loopHead->index()].isLoopHeader = true;
-
- std::vector<MIBlock *> worklist;
- worklist.reserve(backedges.size() + 8);
- worklist.insert(worklist.end(), backedges.begin(), backedges.end());
- while (!worklist.empty()) {
- MIBlock *predIt = worklist.back();
- worklist.pop_back();
-
- MIBlock *subloop = blockInfos[predIt->index()].loopHeader;
- if (subloop) {
- // This is a discovered block. Find its outermost discovered loop.
- while (MIBlock *parentLoop = blockInfos[subloop->index()].loopHeader)
- subloop = parentLoop;
-
- // If it is already discovered to be a subloop of this loop, continue.
- if (subloop == loopHead)
- continue;
-
- // Yay, it's a subloop of this loop.
- blockInfos[subloop->index()].loopHeader = loopHead;
- predIt = subloop;
-
- // Add all predecessors of the subloop header to the worklist, as long as
- // those predecessors are not in the current subloop. It might be the case
- // that they are in other loops, which we will then add as a subloop to the
- // current loop.
- for (MIBlock *predIn : predIt->inEdges())
- if (blockInfos[predIn->index()].loopHeader != subloop)
- worklist.push_back(predIn);
- } else {
- if (predIt == loopHead)
- continue;
-
- // This is an undiscovered block. Map it to the current loop.
- blockInfos[predIt->index()].loopHeader = loopHead;
-
- // Add all incoming edges to the worklist.
- for (MIBlock *bb : predIt->inEdges())
- worklist.push_back(bb);
- }
- }
-}
-
-void LoopInfo::dump() const
-{
- if (!lcLoopinfo().isDebugEnabled())
- return;
-
- QString s = QStringLiteral("Loop information:\n");
- for (size_t i = 0, ei = blockInfos.size(); i != ei; ++i) {
- const BlockInfo &bi = blockInfos[i];
- s += QStringLiteral(" %1 : is loop header: %2, contained in loop header's loop: ")
- .arg(i).arg(bi.isLoopHeader ? QLatin1String("yes") : QLatin1String("no"));
- if (bi.loopHeader)
- s += QString::number(bi.loopHeader->index());
- else
- s += QLatin1String("<none>");
- if (bi.isLoopHeader) {
- s += QStringLiteral(", loop exits: ");
- if (bi.loopExits.empty()) {
- s += QLatin1String("<none>");
- } else {
- bool first = true;
- for (MIBlock *exit : bi.loopExits) {
- if (first)
- first = false;
- else
- s += QStringLiteral(", ");
- s += QString::number(exit->index());
- }
- }
- }
- s += QLatin1Char('\n');
- }
- qCDebug(lcLoopinfo).noquote().nospace() << s;
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4loopinfo_p.h b/src/qml/jit/qv4loopinfo_p.h
deleted file mode 100644
index 6a865e6dc6..0000000000
--- a/src/qml/jit/qv4loopinfo_p.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4LOOPINFO_P_H
-#define QV4LOOPINFO_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 "qv4mi_p.h"
-
-#include <QHash>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class DominatorTree;
-
-// Detect all (sub-)loops in a function.
-//
-// Doing loop detection on the CFG is better than relying on the statement information in
-// order to mark loops. Although JavaScript only has natural loops, it can still be the case
-// that something is not a loop even though a loop-like-statement is in the source. For
-// example:
-// while (true) {
-// if (i > 0)
-// break;
-// else
-// break;
-// }
-//
-// Algorithm:
-// - do a DFS on the dominator tree, where for each node:
-// - collect all back-edges
-// - if there are back-edges, the node is a loop-header for a new loop, so:
-// - walk the CFG is reverse-direction, and for every node:
-// - if the node already belongs to a loop, we've found a nested loop:
-// - get the loop-header for the (outermost) nested loop
-// - add that loop-header to the current loop
-// - continue by walking all incoming edges that do not yet belong to the current loop
-// - if the node does not belong to a loop yet, add it to the current loop, and
-// go on with all incoming edges
-//
-// Loop-header detection by checking for back-edges is very straight forward: a back-edge is
-// an incoming edge where the other node is dominated by the current node. Meaning: all
-// execution paths that reach that other node have to go through the current node, that other
-// node ends with a (conditional) jump back to the loop header.
-//
-// The exact order of the DFS on the dominator tree is not important. The only property has to
-// be that a node is only visited when all the nodes it dominates have been visited before.
-// The reason for the DFS is that for nested loops, the inner loop's loop-header is dominated
-// by the outer loop's header. So, by visiting depth-first, sub-loops are identified before
-// their containing loops, which makes nested-loop identification free. An added benefit is
-// that the nodes for those sub-loops are only processed once.
-//
-// Note: independent loops that share the same header are merged together. For example, in
-// the code snippet below, there are 2 back-edges into the loop-header, but only one single
-// loop will be detected.
-// while (a) {
-// if (b)
-// continue;
-// else
-// continue;
-// }
-class LoopInfo
-{
- Q_DISABLE_COPY_MOVE(LoopInfo)
-
- struct BlockInfo
- {
- MIBlock *loopHeader = nullptr;
- bool isLoopHeader = false;
- std::vector<MIBlock *> loopExits;
- };
-
-public:
- LoopInfo(const DominatorTree &dt)
- : dt(dt)
- {}
-
- ~LoopInfo() = default;
-
- void detectLoops();
-
- MIBlock *loopHeaderFor(MIBlock *bodyBlock) const
- { return blockInfos[bodyBlock->index()].loopHeader; }
-
- bool isLoopHeader(MIBlock *block) const
- { return blockInfos[block->index()].isLoopHeader; }
-
- const std::vector<MIBlock *> loopExitsForLoop(MIBlock *loopHeader) const
- { return blockInfos[loopHeader->index()].loopExits; }
-
-private:
- void subLoop(MIBlock *loopHead, const std::vector<MIBlock *> &backedges);
- void collectLoopExits();
- bool inLoopOrSubLoop(MIBlock *block, MIBlock *loopHeader) const;
-
- void dump() const;
-
-private:
- const DominatorTree &dt;
- std::vector<BlockInfo> blockInfos;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4LOOPINFO_P_H
diff --git a/src/qml/jit/qv4lowering.cpp b/src/qml/jit/qv4lowering.cpp
deleted file mode 100644
index 3b3711e7fa..0000000000
--- a/src/qml/jit/qv4lowering.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QLoggingCategory>
-
-#include "qv4lowering_p.h"
-#include "qv4graph_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcLower, "qt.v4.ir.lowering")
-
-GenericLowering::GenericLowering(Function &f)
- : m_function(f)
-{}
-
-void GenericLowering::lower()
-{
- NodeWorkList worklist(graph());
- // The order doesn't really matter for generic lowering, as long as it's done in 1 pass, and
- // have any clean-up done afterwards.
- worklist.enqueueAllInputs(graph()->endNode());
-
- while (Node *n = worklist.dequeueNextNodeForVisiting()) {
- worklist.enqueueAllInputs(n);
-
- if (!CallPayload::isRuntimeCall(n->opcode()))
- continue;
-
- if (CallPayload::isVarArgsCall(n->opcode()))
- replaceWithVarArgsCall(n);
- else
- replaceWithCall(n);
- }
-}
-
-void GenericLowering::replaceWithCall(Node *n)
-{
- auto newOp = opBuilder()->getCall(n->opcode());
-
- QVarLengthArray<Node *, 32> args;
- if (CallPayload::takesEngineAsArg(n->opcode(), 0))
- args.append(graph()->engineNode());
- if (CallPayload::takesFunctionAsArg(n->opcode(), args.size()))
- args.append(graph()->functionNode());
- if (CallPayload::takesFrameAsArg(n->opcode(), args.size()))
- args.append(graph()->cppFrameNode());
- const int extraLeadingArguments = args.size();
-
- for (unsigned arg = 0, earg = n->inputCount(); arg != earg; ++arg) {
- Node *input = n->input(arg);
- if (input->opcode() == Meta::FrameState)
- continue;
-
- if (arg >= n->operation()->valueInputCount()) {
- // effect or control input
- args.append(input);
- continue;
- }
-
- if (CallPayload::needsStorageOnJSStack(n->opcode(), args.size(), input->operation(),
- function().nodeInfo(input)->type()))
- input = graph()->createNode(opBuilder()->get<Meta::Alloca>(), input);
-
- args.append(input);
- }
-
- Node *newCall = graph()->createNode(newOp, args.data(), args.size());
-
- qCDebug(lcLower) << "replacing node" << n->id() << n->operation()->debugString()
- << "with node" << newCall->id() << newOp->debugString();
- qCDebug(lcLower) << "... old node #inputs:" << n->inputCount();
- qCDebug(lcLower) << "... old node #uses:" << n->useCount();
-
- function().nodeInfo(newCall)->setType(CallPayload::returnType(n->opcode()));
- n->replaceAllUsesWith(newCall);
- n->kill();
-
- qCDebug(lcLower) << "... new node #inputs:" << newCall->inputCount();
- qCDebug(lcLower) << "... new node #uses:" << newCall->useCount();
-
- for (Node *use : newCall->uses()) {
- // fix-up indices for SelectOutput:
- if (use->opcode() == Meta::SelectOutput) {
- const int oldIndex = ConstantPayload::get(*use->input(1)->operation())->value().int_32();
- const int newIndex = oldIndex + extraLeadingArguments;
- use->replaceInput(1, graph()->createConstantIntNode(newIndex));
- use->replaceInput(2, newCall->input(newIndex));
- break;
- }
- }
-}
-
-void GenericLowering::replaceWithVarArgsCall(Node *n)
-{
- const bool isTailCall = n->opcode() == Meta::JSTailCall;
- Operation *newOp = isTailCall ? opBuilder()->getTailCall()
- : opBuilder()->getCall(n->opcode());
-
- //### optimize this for 0 and 1 argument: we don't need to create a VarArgs array for these cases
-
- const unsigned varArgsStart = CallPayload::varArgsStart(n->opcode()) - 1; // subtract 1 because the runtime calls all take the engine argument as arg0, which isn't in the graph before lowering.
- Node *vaAlloc = graph()->createNode(
- opBuilder()->get<Meta::VAAlloc>(),
- graph()->createConstantIntNode(n->operation()->valueInputCount() - varArgsStart),
- n->effectInput());
- QVarLengthArray<Node *, 32> vaSealIn;
- vaSealIn.append(vaAlloc);
- for (unsigned i = varArgsStart, ei = n->operation()->valueInputCount(); i != ei; ++i) {
- vaSealIn.append(graph()->createNode(opBuilder()->get<Meta::VAStore>(), vaAlloc,
- graph()->createConstantIntNode(vaSealIn.size() - 1),
- n->input(i)));
- }
- vaSealIn.append(vaAlloc);
- Node *vaSeal = graph()->createNode(opBuilder()->getVASeal(vaSealIn.size() - 2),
- vaSealIn.data(),
- vaSealIn.size());
- QVarLengthArray<Node *, 8> callArgs;
- if (isTailCall)
- callArgs.append(graph()->cppFrameNode());
- callArgs.append(graph()->engineNode());
- for (unsigned i = 0; i != varArgsStart; ++i) {
- Node *input = n->input(i);
- if (CallPayload::needsStorageOnJSStack(n->opcode(), callArgs.size(), input->operation(),
- function().nodeInfo(input)->type()))
- input = graph()->createNode(opBuilder()->get<Meta::Alloca>(), input);
- callArgs.append(input);
- }
- callArgs.append(vaSeal); // args
- if (n->opcode() != Meta::JSCreateClass) // JSCreateClass is the odd duck
- callArgs.append(graph()->createConstantIntNode(vaSealIn.size() - 2)); // argc
- callArgs.append(vaSeal); // effect
- callArgs.append(n->controlInput(0)); // control flow
- Node *newCall = graph()->createNode(newOp, callArgs.data(), unsigned(callArgs.size()));
-
- qCDebug(lcLower) << "replacing node" << n->id() << n->operation()->debugString()
- << "with node" << newCall->id() << newOp->debugString();
- qCDebug(lcLower) << "... old node #inputs:" << n->inputCount();
- qCDebug(lcLower) << "... old node #uses:" << n->useCount();
-
- n->replaceAllUsesWith(newCall);
- n->kill();
-
- qCDebug(lcLower) << "... new node #inputs:" << newCall->inputCount();
- qCDebug(lcLower) << "... new node #uses:" << newCall->useCount();
-}
-
-bool GenericLowering::allUsesAsUnboxedBool(Node *n)
-{
- for (Node *use : n->uses()) {
- if (use->operation()->kind() != Meta::Branch)
- return false;
- }
-
- return true;
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4lowering_p.h b/src/qml/jit/qv4lowering_p.h
deleted file mode 100644
index 0b482bc9f0..0000000000
--- a/src/qml/jit/qv4lowering_p.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4LOWERING_P_H
-#define QV4LOWERING_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 <private/qqmljsmemorypool_p.h>
-#include <private/qv4global_p.h>
-#include <private/qv4ir_p.h>
-#include <private/qv4util_p.h>
-#include <private/qv4node_p.h>
-#include <private/qv4graph_p.h>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-// Lowering replaces JS level operations with lower level ones. E.g. a JSAdd is lowered to an AddI32
-// if both inputs and the output are 32bit integers, or to a runtime call in all other cases. This
-// transforms the graph into something that is closer to actual executable code.
-
-
-// Last lowering phase: replace all JSOperations that are left with runtime calls. There is nothing
-// smart here, all that should have been done before this phase.
-class GenericLowering final
-{
- Q_DISABLE_COPY(GenericLowering)
-
-public:
- GenericLowering(Function &f);
-
- void lower();
-
-private:
- void replaceWithCall(Node *n);
- void replaceWithVarArgsCall(Node *n);
- static bool allUsesAsUnboxedBool(Node *n);
-
- Function &function()
- { return m_function; }
-
- Graph *graph()
- { return function().graph(); }
-
- OperationBuilder *opBuilder()
- { return graph()->opBuilder(); }
-
-private:
- Function &m_function;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4LOWERING_P_H
diff --git a/src/qml/jit/qv4mi.cpp b/src/qml/jit/qv4mi.cpp
deleted file mode 100644
index f0b172243d..0000000000
--- a/src/qml/jit/qv4mi.cpp
+++ /dev/null
@@ -1,251 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-#include <private/qqmlglobal_p.h>
-
-#include "qv4mi_p.h"
-#include "qv4node_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcMI, "qt.v4.ir.mi")
-
-QString MIOperand::debugString() const
-{
- switch (kind()) {
- case Invalid: return QStringLiteral("<<INVALID>>");
- case Constant: return ConstantPayload::debugString(constantValue());
- case VirtualRegister: return QStringLiteral("vreg%1").arg(virtualRegister());
- case EngineRegister: return QStringLiteral("engine");
- case CppFrameRegister: return QStringLiteral("cppFrame");
- case Function: return QStringLiteral("function");
- case JSStackSlot: return QStringLiteral("jsstack[%1]").arg(stackSlot());
- case BoolStackSlot: return QStringLiteral("bstack[%1]").arg(stackSlot());
- case JumpTarget: return targetBlock() ? QStringLiteral("L%1").arg(targetBlock()->index())
- : QStringLiteral("<<INVALID BLOCK>>");
- default: Q_UNREACHABLE();
- }
-}
-
-MIInstr *MIInstr::create(QQmlJS::MemoryPool *pool, Node *irNode, unsigned nOperands)
-{
- return pool->New<MIInstr>(irNode, pool, nOperands);
-}
-
-static QString commentIndent(const QString &line)
-{
- int spacing = std::max(70 - line.length(), 1);
- return line + QString(spacing, QLatin1Char(' '));
-}
-
-static QString indent(int nr)
-{
- QString s = nr == -1 ? QString() : QString::number(nr);
- int padding = 6 - s.size();
- if (padding > 0)
- s = QString(padding, QLatin1Char(' ')) + s;
- return s;
-}
-
-MIFunction::MIFunction(Function *irFunction)
- : m_irFunction(irFunction)
-{}
-
-void MIFunction::renumberBlocks()
-{
- for (size_t i = 0, ei = m_blocks.size(); i != ei; ++i) {
- MIBlock *b = m_blocks[i];
- b->setIndex(unsigned(i));
- }
-}
-
-void MIFunction::renumberInstructions()
-{
- int pos = 0;
- for (MIBlock *b : m_blocks) {
- for (MIInstr &instr : b->instructions()) {
- pos += 2;
- instr.setPosition(pos);
- }
- }
-}
-
-void MIFunction::dump(const QString &description) const
-{
- if (!lcMI().isDebugEnabled())
- return;
-
- QString s = description + QLatin1String(":\n");
- QString name;
- if (auto n = irFunction()->v4Function()->name())
- name = n->toQString();
- if (name.isEmpty())
- QString::asprintf("%p", static_cast<void *>(irFunction()->v4Function()));
- QString line = QStringLiteral("function %1 {").arg(name);
- auto loc = irFunction()->v4Function()->sourceLocation();
- s += commentIndent(line) + QStringLiteral("; %1:%2:%3\n").arg(loc.sourceFile,
- QString::number(loc.line),
- QString::number(loc.column));
- for (const MIBlock *b : blocks()) {
- line = QStringLiteral("L%1").arg(b->index());
- bool first = true;
- if (!b->arguments().empty()) {
- line += QLatin1Char('(');
- for (const MIOperand &arg : b->arguments()) {
- if (first)
- first = false;
- else
- line += QStringLiteral(", ");
- line += arg.debugString();
- }
- line += QLatin1Char(')');
- }
- line += QLatin1Char(':');
- line = commentIndent(line) + QStringLiteral("; preds: ");
- if (b->inEdges().isEmpty()) {
- line += QStringLiteral("<none>");
- } else {
- bool first = true;
- for (MIBlock *in : b->inEdges()) {
- if (first)
- first = false;
- else
- line += QStringLiteral(", ");
- line += QStringLiteral("L%1").arg(in->index());
- }
- }
- s += line + QLatin1Char('\n');
- for (const MIInstr &i : b->instructions()) {
- line = indent(i.position()) + QLatin1String(": ");
- if (i.hasDestination())
- line += i.destination().debugString() + QStringLiteral(" = ");
- line += i.irNode()->operation()->debugString();
- bool first = true;
- for (const MIOperand &op : i.operands()) {
- if (first)
- first = false;
- else
- line += QLatin1Char(',');
- line += QLatin1Char(' ') + op.debugString();
- }
- line = commentIndent(line) + QStringLiteral("; node-id: %1").arg(i.irNode()->id());
- if (i.irNode()->operation()->needsBytecodeOffsets())
- line += QStringLiteral(", bytecode-offset: %1").arg(irFunction()->nodeInfo(i.irNode())->currentInstructionOffset());
- s += line + QLatin1Char('\n');
- }
- s += commentIndent(QString()) + QStringLiteral("; succs: ");
- if (b->outEdges().isEmpty()) {
- s += QStringLiteral("<none>");
- } else {
- bool first = true;
- for (MIBlock *succ : b->outEdges()) {
- if (first)
- first = false;
- else
- s += QStringLiteral(", ");
- s += QStringLiteral("L%1").arg(succ->index());
- }
- }
- s += QLatin1Char('\n');
- }
- s += QLatin1Char('}');
-
- for (const QStringRef &line : s.splitRef('\n'))
- qCDebug(lcMI).noquote().nospace() << line;
-}
-
-unsigned MIFunction::extraJSSlots() const
-{
- uint interpreterFrameSize = CppStackFrame::requiredJSStackFrameSize(irFunction()->v4Function());
- if (m_jsSlotCount <= interpreterFrameSize)
- return 0;
- return m_jsSlotCount - interpreterFrameSize;
-}
-
-void MIFunction::setStartBlock(MIBlock *newStartBlock)
-{
- auto it = std::find(m_blocks.begin(), m_blocks.end(), newStartBlock);
- Q_ASSERT(it != m_blocks.end());
- std::swap(*m_blocks.begin(), *it);
-}
-
-void MIFunction::setStackSlotCounts(unsigned dword, unsigned qword, unsigned js)
-{
- m_vregCount = 0;
- m_dwordSlotCount = dword;
- m_qwordSlotCount = qword;
- m_jsSlotCount = js;
-}
-
-void MIFunction::verifyCFG() const
-{
- if (block(MIFunction::StartBlockIndex)->instructions().front().opcode() != Meta::Start)
- qFatal("MIFunction block 0 is not the start block");
-
- for (MIBlock *b : m_blocks) {
- for (MIBlock *in : b->inEdges()) {
- if (!in->outEdges().contains(b))
- qFatal("block %u has incoming edge from block %u, "
- "but does not appear in that block's outgoing edges",
- b->index(), in->index());
- }
- for (MIBlock *out : b->outEdges()) {
- if (!out->inEdges().contains(b))
- qFatal("block %u has outgoing edge from block %u, "
- "but does not appear in that block's incoming edges",
- b->index(), out->index());
- }
- }
-}
-
-MIBlock *MIBlock::findEdgeTo(Operation::Kind target) const
-{
- for (MIBlock *outEdge : outEdges()) {
- if (outEdge->instructions().front().opcode() == target)
- return outEdge;
- }
- return nullptr;
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4mi_p.h b/src/qml/jit/qv4mi_p.h
deleted file mode 100644
index f976d1dc94..0000000000
--- a/src/qml/jit/qv4mi_p.h
+++ /dev/null
@@ -1,627 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4MI_P_H
-#define QV4MI_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 <private/qv4global_p.h>
-#include <private/qv4ir_p.h>
-#include <private/qv4node_p.h>
-#include <private/qv4operation_p.h>
-
-#include <llvm/ADT/iterator.h>
-#include <llvm/ADT/iterator_range.h>
-#include <llvm/ADT/ilist.h>
-#include <llvm/ADT/ilist_node.h>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-// This file contains the Machine Interface (MI) data structures, on which ultimately the assembler
-// will operate:
-
-class MIFunction; // containing all basic blocks, and a reference to the IR function
-
-class MIBlock; // containing an ordered sequence of instructions
-
-class MIInstr; // containing operands, and a reference to the IR node, that indicates which
- // operation is represented by an instruction
-
-class MIOperand; // contains a description of where to get/put the input/result of an operation
-
-// A detail about the stack slots: there two stacks, the JS stack and the native stack. A frame on
-// the native stack is divided in two parts: the quad-word part and the double-word part. The
-// qword part holds 64bit values, like doubles, and pointers on 64bit architectures. The dword part
-// holds 32bit values, like int32s, booleans, and pointers on 32bit architectures. We need to know
-// the type of value a slot holds, because if we have to move it to the JS stack, we have to box it
-// correctly.
-class MIOperand final
-{
-public:
- enum Kind {
- Invalid = 0,
- Constant,
- VirtualRegister,
-
- EngineRegister,
- CppFrameRegister,
- Function,
-
- JSStackSlot,
- BoolStackSlot,
-
- JumpTarget,
- };
-
- using List = QQmlJS::FixedPoolArray<MIOperand>;
-
-public:
- MIOperand() = default;
-
- static MIOperand createConstant(Node *irNode)
- {
- MIOperand op;
- op.m_kind = Constant;
- op.m_irNode = irNode;
- return op;
- }
-
- static MIOperand createVirtualRegister(Node *irNode, unsigned vreg)
- {
- MIOperand op;
- op.m_kind = VirtualRegister;
- op.m_irNode = irNode;
- op.m_vreg = vreg;
- return op;
- }
-
- static MIOperand createEngineRegister(Node *irNode)
- {
- MIOperand op;
- op.m_kind = EngineRegister;
- op.m_irNode = irNode;
- return op;
- }
-
- static MIOperand createCppFrameRegister(Node *irNode)
- {
- MIOperand op;
- op.m_kind = CppFrameRegister;
- op.m_irNode = irNode;
- return op;
- }
-
- static MIOperand createFunction(Node *irNode)
- {
- MIOperand op;
- op.m_kind = Function;
- op.m_irNode = irNode;
- return op;
- }
-
- static MIOperand createJSStackSlot(Node *irNode, unsigned slot)
- {
- MIOperand op;
- op.m_kind = JSStackSlot;
- op.m_irNode = irNode;
- op.m_slot = slot;
- return op;
- }
-
- static MIOperand createBoolStackSlot(Node *irNode, unsigned slot)
- {
- MIOperand op;
- op.m_kind = BoolStackSlot;
- op.m_irNode = irNode;
- op.m_slot = slot;
- return op;
- }
-
- //### or name this createDeoptBlock?
- static MIOperand createJumpTarget(Node *irNode, MIBlock *targetBlock)
- {
- MIOperand op;
- op.m_kind = JumpTarget;
- op.m_irNode = irNode;
- op.m_targetBlock = targetBlock;
- return op;
- }
-
- Kind kind() const
- { return m_kind; }
-
- bool isValid() const
- { return m_kind != Invalid; }
-
- bool isConstant() const
- { return m_kind == Constant; }
-
- bool isVirtualRegister() const
- { return kind() == VirtualRegister; }
-
- bool isEngineRegister() const
- { return kind() == EngineRegister; }
-
- bool isCppFrameRegister() const
- { return kind() == CppFrameRegister; }
-
- bool isFunction() const
- { return kind() == Function; }
-
- bool isJSStackSlot() const
- { return kind() == JSStackSlot; }
-
- bool isBoolStackSlot() const
- { return kind() == BoolStackSlot; }
-
- bool isStackSlot() const
- { return isJSStackSlot() || isDWordSlot() || isQWordSlot(); }
-
- bool isJumpTarget() const
- { return kind() == JumpTarget; }
-
- Node *irNode() const
- { return m_irNode; }
-
- inline Type nodeType(MIFunction *f) const;
-
- QString debugString() const;
-
- QV4::Value constantValue() const
- {
- Q_ASSERT(isConstant());
- if (irNode()->opcode() == Meta::Undefined)
- return QV4::Value::undefinedValue();
- if (irNode()->opcode() == Meta::Empty)
- return QV4::Value::emptyValue();
- return ConstantPayload::get(*irNode()->operation())->value();
- }
-
- unsigned virtualRegister() const
- { Q_ASSERT(isVirtualRegister()); return m_vreg; }
-
- unsigned stackSlot() const
- { Q_ASSERT(isStackSlot()); return m_slot; }
-
- MIBlock *targetBlock() const
- { Q_ASSERT(isJumpTarget()); return m_targetBlock; }
-
- inline bool operator==(const MIOperand &other) const
- {
- if (kind() != other.kind())
- return false;
-
- if (isStackSlot())
- return stackSlot() == other.stackSlot();
-
- switch (kind()) {
- case MIOperand::Invalid:
- return !other.isValid();
- case MIOperand::Constant:
- return constantValue().asReturnedValue() == other.constantValue().asReturnedValue();
- case MIOperand::VirtualRegister:
- return virtualRegister() == other.virtualRegister();
- case MIOperand::JumpTarget:
- return targetBlock() == other.targetBlock();
- default:
- Q_UNREACHABLE();
- return false;
- }
- }
-
- bool isDWordSlot() const
- {
- switch (kind()) {
- case BoolStackSlot:
- return true;
- default:
- return false;
- }
- }
-
- bool isQWordSlot() const
- {
- switch (kind()) {
- //### TODO: double slots
- default:
- return false;
- }
- }
-
- bool overlaps(const MIOperand &other) const
- {
- if ((isDWordSlot() && other.isDWordSlot()) || (isQWordSlot() && other.isQWordSlot()))
- ; // fine, these are the same
- else if (kind() != other.kind())
- return false;
-
- if (isStackSlot())
- return stackSlot() == other.stackSlot();
-
- return false;
- }
-
-private:
- Node *m_irNode = nullptr;
- union {
- unsigned m_vreg;
- unsigned m_slot;
- MIBlock *m_targetBlock = nullptr;
- };
- Kind m_kind = Invalid;
-};
-
-template <typename NodeTy> struct MIInstrListParentType {};
-template <> struct MIInstrListParentType<MIInstr> { using type = MIBlock; };
-
-template <typename NodeTy> class MIInstrList;
-
-template <typename MISubClass>
-class MIInstrListTraits : public llvm::ilist_noalloc_traits<MISubClass>
-{
-protected:
- using ListTy = MIInstrList<MISubClass>;
- using iterator = typename llvm::simple_ilist<MISubClass>::iterator;
- using ItemParentClass = typename MIInstrListParentType<MISubClass>::type;
-
-public:
- MIInstrListTraits() = default;
-
-protected:
- void setListOwner(ItemParentClass *listOwner)
- { m_owner = listOwner; }
-
-private:
- ItemParentClass *m_owner = nullptr;
-
- /// getListOwner - Return the object that owns this list. If this is a list
- /// of instructions, it returns the BasicBlock that owns them.
- ItemParentClass *getListOwner() const {
- return m_owner;
- }
-
- static ListTy &getList(ItemParentClass *Par) {
- return Par->*(Par->getSublistAccess());
- }
-
- static MIInstrListTraits<MISubClass> *getSymTab(ItemParentClass *Par) {
- return Par ? toPtr(Par->getValueSymbolTable()) : nullptr;
- }
-
-public:
- void addNodeToList(MISubClass *V) { V->setParent(getListOwner()); }
- void removeNodeFromList(MISubClass *V) { V->setParent(nullptr); }
- void transferNodesFromList(MIInstrListTraits &L2, iterator first,
- iterator last);
-};
-
-template <class T>
-class MIInstrList: public llvm::iplist_impl<llvm::simple_ilist<T>, MIInstrListTraits<T>>
-{
-public:
- MIInstrList(typename MIInstrListTraits<T>::ItemParentClass *owner)
- { this->setListOwner(owner); }
-};
-
-class MIInstr final : public llvm::ilist_node_with_parent<MIInstr, MIBlock>
-{
- Q_DISABLE_COPY_MOVE(MIInstr) // heap use only!
-
-protected:
- friend class QQmlJS::MemoryPool;
- MIInstr() : m_operands(nullptr, 0) {}
-
- explicit MIInstr(Node *irNode, QQmlJS::MemoryPool *pool, unsigned nOperands)
- : m_irNode(irNode)
- , m_operands(pool, nOperands)
- {}
-
- ~MIInstr() = default;
-
-public:
- static MIInstr *create(QQmlJS::MemoryPool *pool, Node *irNode, unsigned nOperands);
-
- MIBlock *parent() const
- { return m_parent; }
-
- MIBlock *getParent() const // for ilist_node_with_parent
- { return parent(); }
-
- void setParent(MIBlock *parent)
- { m_parent = parent; }
-
- Node *irNode() const
- { return m_irNode; }
-
- Operation::Kind opcode() const
- { return m_irNode->opcode(); }
-
- int position() const
- { return m_position; }
-
- inline void insertBefore(MIInstr *insertPos);
- inline void insertAfter(MIInstr *insertPos);
- inline MIInstrList<MIInstr>::iterator eraseFromParent();
-
- bool hasDestination() const
- { return m_destination.isValid(); }
-
- MIOperand destination() const
- { return m_destination; }
-
- void setDestination(const MIOperand &dest)
- { m_destination = dest; }
-
- const MIOperand &operand(unsigned index) const
- { return m_operands.at(index); }
-
- void setOperand(unsigned index, const MIOperand &op)
- { m_operands.at(index) = op; }
-
- MIOperand &operand(unsigned index)
- { return m_operands.at(index); }
-
- const MIOperand::List &operands() const
- { return m_operands; }
-
- MIOperand::List &operands()
- { return m_operands; }
-
-private:
- friend MIFunction;
- void setPosition(int newPosition)
- { m_position = newPosition; }
-
-private:
- MIBlock *m_parent = nullptr;
- Node *m_irNode = nullptr;
- int m_position = -1;
- MIOperand m_destination;
- MIOperand::List m_operands;
-};
-
-class MIBlock final
-{
- Q_DISABLE_COPY_MOVE(MIBlock)
-
-public:
- using Index = unsigned;
- enum : Index { InvalidIndex = std::numeric_limits<Index>::max() };
-
- using MIInstructionList = MIInstrList<MIInstr>;
-
- using InEdges = QVarLengthArray<MIBlock *, 4>;
- using OutEdges = QVarLengthArray<MIBlock *, 2>;
-
-protected:
- friend MIFunction;
- explicit MIBlock(Index index)
- : m_instructions(this),
- m_index(index)
- {}
-
- void setIndex(Index newIndex)
- { m_index = newIndex; }
-
-public:
- ~MIBlock() = default;
-
- const MIInstructionList &instructions() const
- { return m_instructions; }
-
- MIInstructionList &instructions()
- { return m_instructions; }
-
- static MIInstructionList MIBlock::*getSublistAccess(MIInstr * = nullptr)
- { return &MIBlock::m_instructions; }
-
- void addArgument(MIOperand &&arg)
- { m_arguments.push_back(arg); }
-
- const std::vector<MIOperand> &arguments() const
- { return m_arguments; }
-
- std::vector<MIOperand> &arguments()
- { return m_arguments; }
-
- void clearArguments()
- { m_arguments.resize(0); }
-
- const InEdges &inEdges() const
- { return m_inEdges; }
-
- void addInEdge(MIBlock *edge)
- { m_inEdges.append(edge); }
-
- const OutEdges &outEdges() const
- { return m_outEdges; }
-
- void addOutEdge(MIBlock *edge)
- { m_outEdges.append(edge); }
-
- Index index() const
- { return m_index; }
-
- MIBlock *findEdgeTo(Operation::Kind target) const;
-
- bool isDeoptBlock() const
- { return m_isDeoptBlock; }
-
- void markAsDeoptBlock()
- { m_isDeoptBlock = true; }
-
-private:
- std::vector<MIOperand> m_arguments;
- MIInstructionList m_instructions;
- InEdges m_inEdges;
- OutEdges m_outEdges;
- Index m_index;
- bool m_isDeoptBlock = false;
-};
-
-class MIFunction final
-{
- Q_DISABLE_COPY_MOVE(MIFunction)
-
-public:
- static constexpr MIBlock::Index StartBlockIndex = 0;
-
-public:
- MIFunction(Function *irFunction);
- ~MIFunction()
- { qDeleteAll(m_blocks); }
-
- Function *irFunction() const
- { return m_irFunction; }
-
- void setStartBlock(MIBlock *newStartBlock);
- void renumberBlocks();
- void renumberInstructions();
-
- void dump(const QString &description) const;
-
- size_t blockCount() const
- { return blocks().size(); }
-
- MIBlock *block(MIBlock::Index index) const
- { return m_blocks[index]; }
-
- const std::vector<MIBlock *> &blocks() const
- { return m_blocks; }
-
- MIBlock *addBlock()
- {
- auto *b = new MIBlock(unsigned(m_blocks.size()));
- m_blocks.push_back(b);
- return b;
- }
-
- void setBlockOrder(const std::vector<MIBlock *> &newSequence)
- { m_blocks = newSequence; }
-
- unsigned vregCount() const
- { return m_vregCount; }
-
- void setVregCount(unsigned vregCount)
- { m_vregCount = vregCount; }
-
- unsigned dwordSlotCount() const
- { return m_dwordSlotCount; }
-
- unsigned qwordSlotCount() const
- { return m_qwordSlotCount; }
-
- unsigned jsSlotCount() const
- { return m_jsSlotCount; }
-
- unsigned extraJSSlots() const;
-
- void setStackSlotCounts(unsigned dword, unsigned qword, unsigned js);
-
- void verifyCFG() const;
-
-private:
- Function *m_irFunction = nullptr;
- std::vector<MIBlock *> m_blocks;
- unsigned m_vregCount = 0;
- unsigned m_dwordSlotCount = 0;
- unsigned m_qwordSlotCount = 0;
- unsigned m_jsSlotCount = 0;
-};
-
-Type MIOperand::nodeType(MIFunction *f) const
-{
- return f->irFunction()->nodeInfo(irNode())->type();
-}
-
-inline uint qHash(const MIOperand &key, uint seed)
-{
- uint h = ::qHash(key.kind(), seed);
- switch (key.kind()) {
- case MIOperand::VirtualRegister:
- h ^= key.virtualRegister();
- break;
- case MIOperand::BoolStackSlot: Q_FALLTHROUGH();
- case MIOperand::JSStackSlot:
- h ^= key.stackSlot();
- break;
- default:
- qFatal("%s: cannot hash %s", Q_FUNC_INFO, key.debugString().toUtf8().constData());
- }
- return h;
-}
-
-void MIInstr::insertBefore(MIInstr *insertPos)
-{
- insertPos->parent()->instructions().insert(insertPos->getIterator(), this);
-}
-
-void MIInstr::insertAfter(MIInstr *insertPos)
-{
- insertPos->parent()->instructions().insert(++insertPos->getIterator(), this);
-}
-
-MIInstrList<MIInstr>::iterator MIInstr::eraseFromParent()
-{
- auto p = parent();
- setParent(nullptr);
- return p->instructions().erase(getIterator());
-}
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4MI_P_H
diff --git a/src/qml/jit/qv4miblockset_p.h b/src/qml/jit/qv4miblockset_p.h
deleted file mode 100644
index 5f814b99e0..0000000000
--- a/src/qml/jit/qv4miblockset_p.h
+++ /dev/null
@@ -1,291 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4MIBLOCKSET_P_H
-#define QV4MIBLOCKSET_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 "qv4mi_p.h"
-#include "qv4util_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class MIBlockSet
-{
- using Flags = BitVector;
-
- QVarLengthArray<MIBlock::Index, 8> blockNumbers;
- Flags *blockFlags = nullptr;
- MIFunction *function = nullptr;
- enum { MaxVectorCapacity = 8 };
-
-public:
- class const_iterator;
- friend class const_iterator;
-
-public:
- MIBlockSet(MIFunction *f = nullptr)
- {
- if (f)
- init(f);
- }
-
- MIBlockSet(MIBlockSet &&other) noexcept
- {
- std::swap(blockNumbers, other.blockNumbers);
- std::swap(blockFlags, other.blockFlags);
- std::swap(function, other.function);
- }
-
- MIBlockSet(const MIBlockSet &other)
- : function(other.function)
- {
- if (other.blockFlags)
- blockFlags = new Flags(*other.blockFlags);
- blockNumbers = other.blockNumbers;
- }
-
- MIBlockSet &operator=(const MIBlockSet &other)
- {
- if (blockFlags) {
- delete blockFlags;
- blockFlags = nullptr;
- }
- function = other.function;
- if (other.blockFlags)
- blockFlags = new Flags(*other.blockFlags);
- blockNumbers = other.blockNumbers;
- return *this;
- }
-
- MIBlockSet &operator=(MIBlockSet &&other) noexcept
- {
- if (&other != this) {
- std::swap(blockNumbers, other.blockNumbers);
-
- delete blockFlags;
- blockFlags = other.blockFlags;
- other.blockFlags = nullptr;
-
- function = other.function;
- }
- return *this;
- }
-
- ~MIBlockSet()
- {
- delete blockFlags;
- }
-
- void init(MIFunction *f)
- {
- Q_ASSERT(!function);
- Q_ASSERT(f);
- function = f;
- }
-
- bool empty() const;
-
- void insert(MIBlock *bb)
- {
- Q_ASSERT(function);
-
- if (blockFlags) {
- blockFlags->setBit(bb->index());
- return;
- }
-
- for (unsigned int blockNumber : qAsConst(blockNumbers)) {
- if (blockNumber == bb->index())
- return;
- }
-
- if (blockNumbers.size() == MaxVectorCapacity) {
- blockFlags = new Flags(int(function->blockCount()), false);
- for (unsigned int blockNumber : qAsConst(blockNumbers)) {
- blockFlags->setBit(int(blockNumber));
- }
- blockNumbers.clear();
- blockFlags->setBit(int(bb->index()));
- } else {
- blockNumbers.append(bb->index());
- }
- }
-
- void remove(MIBlock *bb)
- {
- Q_ASSERT(function);
-
- if (blockFlags) {
- blockFlags->clearBit(bb->index());
- return;
- }
-
- for (int i = 0; i < blockNumbers.size(); ++i) {
- if (blockNumbers[i] == bb->index()) {
- blockNumbers.remove(i);
- return;
- }
- }
- }
-
- const_iterator begin() const;
- const_iterator end() const;
-
- void collectValues(std::vector<MIBlock *> &bbs) const;
-
- bool contains(MIBlock *bb) const
- {
- Q_ASSERT(function);
-
- if (blockFlags)
- return blockFlags->at(bb->index());
-
- for (unsigned int blockNumber : blockNumbers) {
- if (blockNumber == bb->index())
- return true;
- }
-
- return false;
- }
-};
-
-class MIBlockSet::const_iterator
-{
- const MIBlockSet &set;
- // ### These two members could go into a union, but clang won't compile
- // (https://codereview.qt-project.org/#change,74259)
- QVarLengthArray<MIBlock::Index, 8>::const_iterator numberIt;
- MIBlock::Index flagIt;
-
- friend class MIBlockSet;
- const_iterator(const MIBlockSet &set, bool end)
- : set(set)
- {
- if (end || !set.function) {
- if (!set.blockFlags)
- numberIt = set.blockNumbers.end();
- else
- flagIt = set.blockFlags->size();
- } else {
- if (!set.blockFlags)
- numberIt = set.blockNumbers.begin();
- else
- findNextWithFlags(0);
- }
- }
-
- void findNextWithFlags(int start)
- {
- flagIt = MIBlock::Index(set.blockFlags->findNext(start, true, /*wrapAround = */false));
- Q_ASSERT(flagIt <= MIBlock::Index(set.blockFlags->size()));
- }
-
-public:
- MIBlock *operator*() const
- {
- if (!set.blockFlags)
- return set.function->block(*numberIt);
-
- Q_ASSERT(flagIt <= set.function->blockCount());
- return set.function->block(flagIt);
-
- }
-
- bool operator==(const const_iterator &other) const
- {
- if (&set != &other.set)
- return false;
- if (!set.blockFlags)
- return numberIt == other.numberIt;
- return flagIt == other.flagIt;
- }
-
- bool operator!=(const const_iterator &other) const
- { return !(*this == other); }
-
- const_iterator &operator++()
- {
- if (!set.blockFlags)
- ++numberIt;
- else
- findNextWithFlags(flagIt + 1);
-
- return *this;
- }
-};
-
-inline bool MIBlockSet::empty() const
-{ return begin() == end(); }
-
-inline MIBlockSet::const_iterator MIBlockSet::begin() const
-{ return const_iterator(*this, false); }
-
-inline MIBlockSet::const_iterator MIBlockSet::end() const
-{ return const_iterator(*this, true); }
-
-inline void MIBlockSet::collectValues(std::vector<MIBlock *> &bbs) const
-{
- Q_ASSERT(function);
-
- for (auto it : *this)
- bbs.push_back(it);
-}
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4MIBLOCKSET_P_H
diff --git a/src/qml/jit/qv4node.cpp b/src/qml/jit/qv4node.cpp
deleted file mode 100644
index e059e9fef6..0000000000
--- a/src/qml/jit/qv4node.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4node_p.h"
-#include "qv4graph_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Node *Node::create(Node::MemoryPool *pool, Node::Id id, const Operation *op, size_t nInputs,
- Node *const *inputs, bool inputsAreExtensible)
-{
- size_t capacity = nInputs;
- if (inputsAreExtensible)
- capacity += 3;
-
- Node *node = new (pool->allocate(sizeof(Node))) Node(pool, id, op, unsigned(nInputs),
- int(capacity));
- for (uint i = 0; i < capacity; ++i)
- new (&node->m_inputs[int(i)]) Use(node);
- for (size_t i = 0; i < nInputs; ++i) {
- Q_ASSERT(inputs[i] != nullptr);
- node->replaceInput(unsigned(i), inputs[i]);
- }
-
- return node;
-}
-
-void Node::addInput(MemoryPool *pool, Node *in)
-{
- Q_ASSERT(in);
- ++m_nInputs;
- if (m_nInputs >= unsigned(m_inputs.size())) {
- QQmlJS::FixedPoolArray<Use> oldInputs = m_inputs;
- m_inputs = QQmlJS::FixedPoolArray<Use>(pool, int(m_nInputs + 3));
- for (Use &input : m_inputs)
- new (&input) Use(this);
- for (int i = 0, ei = oldInputs.size(); i != ei; ++i) {
- Node *in = oldInputs[i].m_input;
- oldInputs[i].set(nullptr);
- m_inputs[i].set(in);
- }
- }
- m_inputs.at(int(m_nInputs - 1)).set(in);
-}
-
-void Node::removeInput(unsigned index)
-{
- Q_ASSERT(index < inputCount());
- for (unsigned i = index, ei = inputCount(); i < ei - 1; ++i)
- replaceInput(i, input(i + 1));
- trimInputCount(inputCount() - 1);
-}
-
-void Node::removeInputs(unsigned start, unsigned count)
-{
- for (unsigned idx = start; idx < start + count; ++idx)
- m_inputs.at(int(idx)).set(nullptr);
-}
-
-void Node::removeAllInputs()
-{
- removeInputs(0, inputCount());
-}
-
-void Node::trimInputCount(unsigned newCount)
-{
- unsigned currentCount = inputCount();
- if (newCount == currentCount)
- return;
- Q_ASSERT(newCount < currentCount);
- removeInputs(newCount, currentCount - newCount);
- m_nInputs = newCount;
-}
-
-void Node::removeExceptionHandlerUse()
-{
- for (Use* use = m_firstUse; use; use = use->m_next) {
- if (use->m_input->opcode() == Meta::OnException) {
- use->set(nullptr);
- break;
- }
- }
-}
-
-void Node::insertInput(Node::MemoryPool *pool, unsigned index, Node *newInput)
-{
- Q_ASSERT(index < inputCount());
- addInput(pool, input(inputCount() - 1));
- for (unsigned i = inputCount() - 1; i > index; --i)
- replaceInput(i, input(i - 1));
- replaceInput(index, newInput);
-}
-
-void Node::replaceAllUsesWith(Node *replacement)
-{
- for (Use *use = m_firstUse; use; ) {
- Use *next = use->m_next;
- const unsigned inIdx = use->inputIndex();
- use->user()->replaceInput(inIdx, replacement);
- use = next;
- }
-}
-
-void Node::replaceUses(Node *newValueInput, Node *newEffectInput, Node *newControlInput)
-{
- for (Use *use = m_firstUse; use; ) {
- Use *next = use->m_next;
- const Operation *inOp = use->user()->operation();
- const unsigned inIdx = use->inputIndex();
- if (inIdx < inOp->valueInputCount())
- use->user()->replaceInput(inIdx, newValueInput);
- else if (inIdx < inOp->indexOfFirstControl())
- use->user()->replaceInput(inIdx, newEffectInput);
- else
- use->user()->replaceInput(inIdx, newControlInput);
- use = next;
- }
-}
-
-Node *Node::firstValueUse()
-{
- for (auto it = uses().begin(), eit = uses().end(); it != eit; ++it) {
- if (it.isUsedAsValue())
- return *it;
- }
- return nullptr;
-}
-
-Node::Node(MemoryPool *pool, Node::Id id, const Operation *op, unsigned nInputs, int capacity)
- : m_op(op)
- , m_inputs(pool, capacity)
- , m_nInputs(nInputs)
- , m_id(id)
-{
-}
-
-NodeWorkList::NodeWorkList(const Graph *g)
- : m_nodeState(g->nodeCount(), Unvisited)
-{ m_worklist.reserve(64); }
-
-void NodeWorkList::reset()
-{
- std::fill(m_nodeState.begin(), m_nodeState.end(), Unvisited);
- m_worklist.clear();
- if (m_worklist.capacity() < 64)
- m_worklist.reserve(64);
-}
-
-NodeCollector::NodeCollector(const Graph *g, bool collectUses, bool skipFramestate)
-{
- markReachable(g->endNode());
- for (size_t i = 0; i < m_reachable.size(); ++i) { // _reachable.size() is on purpose!
- Node *n = m_reachable.at(i);
- for (auto input : n->inputs()) {
- if (input == nullptr)
- continue;
- if (isReachable(input->id()))
- continue;
- if (skipFramestate && input->opcode() == Meta::FrameState)
- continue;
- markReachable(input);
- }
-
- if (collectUses) {
- for (Node *use : n->uses()) {
- if (use && !isReachable(use->id()))
- markReachable(use);
- }
- }
- }
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4node_p.h b/src/qml/jit/qv4node_p.h
deleted file mode 100644
index 76065fb1bc..0000000000
--- a/src/qml/jit/qv4node_p.h
+++ /dev/null
@@ -1,626 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4NODE_P_H
-#define QV4NODE_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 <private/qqmljsmemorypool_p.h>
-#include <private/qv4global_p.h>
-#include <private/qv4operation_p.h>
-#include "qv4util_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-class Use
-{
- Q_DISABLE_COPY_MOVE(Use)
-
-public:
- Use(Node *user)
- : m_user(user)
- {}
-
- ~Use()
- {
- if (m_input)
- removeFromList();
- }
-
- operator Node *() const { return m_input; }
- Node *input() const { return m_input; }
- Node *user() const { return m_user; }
-
- inline void set(Node *newInput);
-
- void validate() const
- {
- Q_ASSERT(m_user);
- if (m_input) {
- if (m_prev != nullptr)
- Q_ASSERT(*m_prev == this);
- if (m_next) {
- Q_ASSERT(m_next->m_input == m_input);
- Q_ASSERT(m_next->m_prev == &m_next);
- m_next->validate();
- }
- }
- }
-
- inline int inputIndex() const;
-
-protected:
- friend class Node;
-
- void addToList(Use **list) {
- validate();
- m_next = *list;
- if (m_next)
- m_next->m_prev = &m_next;
- m_prev = list;
- *list = this;
- validate();
- }
-
- void removeFromList() {
- validate();
- Use **newPrev = m_prev;
- *newPrev = m_next;
- m_prev = nullptr;
- if (m_next)
- m_next->m_prev = newPrev;
- m_next = nullptr;
- m_input = nullptr;
- validate();
- }
-
-private:
- Node *m_input = nullptr;
- Node *m_user = nullptr;
- Use *m_next = nullptr;
- Use **m_prev = nullptr;
-};
-
-// A node represents an calculation, action, or marker in the graph. Each node has an operation,
-// input dependencies and uses. The operation indicates what kind of node it is, e.g.: JSAdd,
-// Constant, Region, and so on. Two nodes can have the same operation, but different inputs.
-// For example, the expressions 1 + 2 and 3 + 4 will each have a node with an JSAdd operation
-// (which is exactly the same operation for both nodes), but the nodes have different inputs (1, and
-// 2 in the first expression, while the second operation has 3 and 4 as inputs).
-class Node final
-{
- Q_DISABLE_COPY_MOVE(Node)
-
-public:
- using Id = uint32_t;
- using MemoryPool = QQmlJS::MemoryPool;
- class Inputs;
-
-public:
- static Node *create(MemoryPool *pool, Id id, const Operation *op, size_t nInputs,
- Node * const *inputs, bool inputsAreExtensible = false);
- ~Node() = delete;
-
- inline bool isDead() const;
- inline void kill();
-
- Id id() const { return m_id; }
-
- const Operation *operation() const
- { return m_op; }
-
- void setOperation(const Operation *op)
- { m_op = op; }
-
- Operation::Kind opcode() const
- { return operation()->kind(); }
-
- inline Inputs inputs() const;
- void addInput(MemoryPool *pool, Node *in);
- void removeInput(unsigned index);
- void removeInputs(unsigned start, unsigned count);
- void removeAllInputs();
- uint32_t inputCount() const
- { return m_nInputs; }
- void trimInputCount(unsigned newCount);
-
- void removeExceptionHandlerUse();
-
- Node *input(unsigned idx) const
- {
- Q_ASSERT(idx < inputCount());
- return m_inputs.at(idx);
- }
-
- Node *effectInput(unsigned effectIndex = 0) const
- {
- if (operation()->effectInputCount() == 0)
- return nullptr;
- Q_ASSERT(effectIndex < operation()->effectInputCount());
- return input(operation()->indexOfFirstEffect() + effectIndex);
- }
-
- Node *controlInput(unsigned controlIndex = 0) const
- {
- if (operation()->controlInputCount() == 0)
- return nullptr;
- Q_ASSERT(controlIndex < operation()->controlInputCount());
- return input(operation()->indexOfFirstControl() + controlIndex);
- }
-
- Node *frameStateInput() const
- {
- if (operation()->hasFrameStateInput())
- return input(operation()->indexOfFrameStateInput());
- return nullptr;
- }
-
- void setFrameStateInput(Node *newFramestate)
- {
- if (operation()->hasFrameStateInput())
- replaceInput(operation()->indexOfFrameStateInput(), newFramestate);
- }
-
- void insertInput(MemoryPool *pool, unsigned index, Node *newInput);
-
- void replaceInput(Node *oldIn, Node *newIn)
- {
- for (unsigned i = 0, ei = inputCount(); i != ei; ++i) {
- if (input(i) == oldIn)
- replaceInput(i, newIn);
- }
- }
-
- void replaceInput(unsigned idx, Node *newIn)
- {
- m_inputs[idx].set(newIn);
- }
-
- class Uses
- {
- public:
- explicit Uses(Node *node)
- : m_node(node)
- {}
-
- class const_iterator;
- inline const_iterator begin() const;
- inline const_iterator end() const;
-
- bool isEmpty() const;
-
- private:
- Node *m_node;
- };
-
- Uses uses() { return Uses(this); }
- bool hasUses() const { return m_firstUse != nullptr; }
- unsigned useCount() const
- {
- unsigned cnt = 0;
- for (Use *it = m_firstUse; it; it = it->m_next)
- ++cnt;
- return cnt;
- }
- void replaceAllUsesWith(Node *replacement);
- void replaceUses(Node *newValueInput, Node *newEffectInput, Node *newControlInput);
-
- Node *firstValueUse();
-
-private: // types and utility methods
- friend class Use;
- Node(MemoryPool *pool, Id id, const Operation *op, unsigned nInputs, int capacity);
-
-private: // fields
- Use *m_firstUse = nullptr;
- const Operation *m_op = nullptr;
- QQmlJS::FixedPoolArray<Use> m_inputs;
- unsigned m_nInputs = 0;
- Id m_id = 0;
-};
-
-void Use::set(Node *newInput)
-{
- if (m_input)
- removeFromList();
- m_input = newInput;
- if (newInput)
- addToList(&newInput->m_firstUse);
-}
-
-class Node::Inputs final
-{
-public:
- using value_type = Node *;
-
- class const_iterator;
- inline const_iterator begin() const;
- inline const_iterator end() const;
-
- bool empty() const
- { return m_nInputs == 0; }
-
- unsigned count() const
- { return m_nInputs; }
-
- explicit Inputs(const Use *inputs, unsigned nInputs)
- : m_inputs(inputs), m_nInputs(nInputs)
- {}
-
-private:
- const Use *m_inputs = nullptr;
- unsigned m_nInputs = 0;
-};
-
-class Node::Inputs::const_iterator final
-{
-public:
- using iterator_category = std::forward_iterator_tag;
- using difference_type = std::ptrdiff_t;
- using value_type = Node *;
- using pointer = const value_type *;
- using reference = value_type &;
-
- Node *operator*() const
- { return m_inputs->m_input; }
-
- bool operator==(const const_iterator &other) const
- { return m_inputs == other.m_inputs; }
-
- bool operator!=(const const_iterator &other) const
- { return !(*this == other); }
-
- const_iterator &operator++()
- { ++m_inputs; return *this; }
-
- const_iterator& operator+=(difference_type offset)
- { m_inputs += offset; return *this; }
-
- const_iterator operator+(difference_type offset) const
- { return const_iterator(m_inputs + offset); }
-
- difference_type operator-(const const_iterator &other) const
- { return m_inputs - other.m_inputs; }
-
-private:
- friend class Node::Inputs;
-
- explicit const_iterator(const Use *inputs)
- : m_inputs(inputs)
- {}
-
- const Use *m_inputs;
-};
-
-Node::Inputs::const_iterator Node::Inputs::begin() const
-{ return const_iterator(m_inputs); }
-
-Node::Inputs::const_iterator Node::Inputs::end() const
-{ return const_iterator(m_inputs + m_nInputs); }
-
-Node::Inputs Node::inputs() const
-{
- return Inputs(m_inputs.begin(), m_nInputs);
-}
-
-class Node::Uses::const_iterator final
-{
-public:
- using iterator_category = std::forward_iterator_tag;
- using difference_type = int;
- using value_type = Node *;
- using pointer = Node **;
- using reference = Node *&;
-
- Node *operator*() const
- { return m_current->user(); }
-
- bool operator==(const const_iterator &other) const
- { return other.m_current == m_current; }
-
- bool operator!=(const const_iterator &other) const
- { return other.m_current != m_current; }
-
- const_iterator &operator++()
- { m_current = m_next; setNext(); return *this; }
-
- unsigned inputIndex() const
- { return m_current->inputIndex(); }
-
- bool isUsedAsValue() const
- { return inputIndex() < operator*()->operation()->valueInputCount(); }
-
- bool isUsedAsControl() const
- { return operator*()->operation()->indexOfFirstControl() <= inputIndex(); }
-
-private:
- friend class Node::Uses;
-
- const_iterator() = default;
-
- explicit const_iterator(Node* node)
- : m_current(node->m_firstUse)
- { setNext(); }
-
- void setNext()
- {
- if (m_current)
- m_next = m_current->m_next;
- else
- m_next = nullptr;
- }
-
-private:
- Use *m_current = nullptr;
- Use *m_next = nullptr;
-};
-
-Node::Uses::const_iterator Node::Uses::begin() const
-{ return const_iterator(this->m_node); }
-
-Node::Uses::const_iterator Node::Uses::end() const
-{ return const_iterator(); }
-
-int Use::inputIndex() const
-{
- if (!m_user)
- return -1;
- return int(this - m_user->m_inputs.begin());
-}
-
-bool Node::isDead() const
-{
- Inputs in = inputs();
- return !in.empty() && *in.begin() == nullptr;
-}
-
-void Node::kill()
-{
- removeAllInputs();
-}
-
-class NodeWorkList final
-{
- enum State: uint8_t {
- Unvisited = 0,
- Queued,
- Visited,
- };
-
-public:
- NodeWorkList(const Graph *g);
-
- void reset();
-
- bool enqueue(Node *n)
- {
- State &s = nodeState(n);
- if (s == Queued || s == Visited)
- return false;
-
- m_worklist.push_back(n);
- s = Queued;
- return true;
- }
-
- void enqueue(const std::vector<Node *> &nodes)
- {
- m_worklist.insert(m_worklist.end(), nodes.begin(), nodes.end());
- for (Node *n : nodes)
- nodeState(n) = Queued;
- }
-
- void reEnqueue(Node *n)
- {
- if (!n)
- return;
- State &s = nodeState(n);
- if (s == Queued)
- return;
- s = Queued;
- m_worklist.push_back(n);
- }
-
- void enqueueAllInputs(Node *n)
- {
- for (Node *input : n->inputs())
- enqueue(input);
- }
-
- void reEnqueueAllInputs(Node *n)
- {
- for (Node *input : n->inputs())
- reEnqueue(input);
- }
-
- void enqueueValueInputs(Node *n)
- {
- for (unsigned i = 0, ei = n->operation()->valueInputCount(); i != ei; ++i)
- enqueue(n->input(i));
- }
-
- void enqueueEffectInputs(Node *n)
- {
- for (unsigned i = n->operation()->indexOfFirstEffect(), ei = n->operation()->effectInputCount(); i != ei; ++i)
- enqueue(n->input(i));
- }
-
- void enqueueAllUses(Node *n)
- {
- for (Node *use : n->uses())
- enqueue(use);
- }
-
- Node *dequeueNextNodeForVisiting()
- {
- while (!m_worklist.empty()) {
- Node *n = m_worklist.back();
- m_worklist.pop_back();
- State &s = nodeState(n);
- Q_ASSERT(s == Queued);
- s = Visited;
- return n;
- }
-
- return nullptr;
- }
-
- bool isVisited(Node *n) const
- { return nodeState(n) == Visited; }
-
- bool isEmpty() const
- { return m_worklist.empty(); }
-
- QString status(Node *n) const
- {
- QString s = QStringLiteral("status for node %1: ").arg(n->id());
- switch (nodeState(n)) {
- case Queued: s += QLatin1String("queued"); break;
- case Visited: s += QLatin1String("visited"); break;
- case Unvisited: s += QLatin1String("unvisited"); break;
- }
- return s;
- }
-
-private:
- State &nodeState(Node *n)
- {
- const unsigned position(n->id());
- if (position >= m_nodeState.size())
- m_nodeState.resize(position + 1, Unvisited);
-
- return m_nodeState[position];
- }
-
- State nodeState(Node *n) const
- { return m_nodeState[unsigned(n->id())]; }
-
-private:
- std::vector<Node *> m_worklist;
- std::vector<State> m_nodeState;
-};
-
-class NodeInfo
-{
-public:
- enum { NoInstructionOffset = -1 };
-
-public:
- NodeInfo() = default;
-
- Type type() const { return m_type; }
- void setType(Type t) { m_type = t; }
-
- int currentInstructionOffset() const
- { return m_currentInstructionOffset; }
-
- int nextInstructionOffset() const
- { return m_nextInstructionOffset; }
-
- void setBytecodeOffsets(int current, int next)
- {
- Q_ASSERT(current != NoInstructionOffset);
- Q_ASSERT(next != NoInstructionOffset);
- m_currentInstructionOffset = current;
- m_nextInstructionOffset = next;
- }
-
-private:
- Type m_type;
- int m_currentInstructionOffset = NoInstructionOffset;
- int m_nextInstructionOffset = NoInstructionOffset;
-};
-
-class NodeCollector
-{
-public:
- NodeCollector(const Graph *g, bool collectUses = false, bool skipFramestate = false);
-
- const std::vector<Node *> &reachable() const
- { return m_reachable; }
-
- void sortById()
- {
- std::sort(m_reachable.begin(), m_reachable.end(), [](Node *n1, Node *n2) {
- return n1->id() < n2->id();
- });
- }
-
- bool isReachable(Node::Id nodeId) const
- {
- if (nodeId >= Node::Id(m_isReachable.size()))
- return false;
- return m_isReachable.at(int(nodeId));
- }
-
- void markReachable(Node *node)
- {
- auto nodeId = node->id();
- m_reachable.push_back(node);
- if (nodeId >= Node::Id(m_isReachable.size()))
- m_isReachable.resize(int(nodeId + 1), false);
- m_isReachable.setBit(int(nodeId));
- }
-
-private:
- std::vector<Node *> m_reachable;
- BitVector m_isReachable;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4NODE_P_H
diff --git a/src/qml/jit/qv4operation.cpp b/src/qml/jit/qv4operation.cpp
deleted file mode 100644
index acd5328fd0..0000000000
--- a/src/qml/jit/qv4operation.cpp
+++ /dev/null
@@ -1,770 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4operation_p.h"
-#include "qv4runtimesupport_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-OperationBuilder::OperationBuilder(QQmlJS::MemoryPool *graphPool)
- : m_graphPool(graphPool)
-{}
-
-OperationBuilder *OperationBuilder::create(QQmlJS::MemoryPool *pool)
-{
- return pool->New<OperationBuilder>(pool);
-}
-
-Operation *OperationBuilder::getConstant(Value v)
-{
- Type t;
- switch (v.type()) {
- case Value::Undefined_Type: t = Type::undefinedType(); break;
- case Value::Integer_Type: t = Type::int32Type(); break;
- case Value::Boolean_Type: t = Type::booleanType(); break;
- case Value::Null_Type: t = Type::nullType(); break;
- case Value::Double_Type: t = Type::doubleType(); break;
- case Value::Managed_Type: t = Type::objectType(); break;
- default:
- if (v.isEmpty())
- t = Type::emptyType();
- else
- Q_UNREACHABLE();
- }
- return OperationWithPayload<ConstantPayload>::create(
- m_graphPool, Meta::Constant, 0, 0, 0, 1, 0, 0, t, Operation::NoFlags,
- ConstantPayload(v));
-}
-
-Operation *OperationBuilder::getParam(unsigned index, const Function::StringId name)
-{
- return OperationWithPayload<ParameterPayload>::create(m_graphPool, Meta::Parameter,
- 1, 0, 0,
- 1, 0, 0,
- Type::anyType(), Operation::NoFlags,
- ParameterPayload(index, name));
-}
-
-Operation *OperationBuilder::getRegion(unsigned nControlInputs) //### cache common operands in the static pool
-{
- return Operation::create(m_graphPool, Meta::Region,
- 0, 0, uint16_t(nControlInputs),
- 0, 0, 1,
- Type(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getPhi(unsigned nValueInputs) //### cache common operands in the static pool
-{
- return Operation::create(m_graphPool, Meta::Phi,
- uint16_t(nValueInputs), 0, 1,
- 1, 0, 0,
- Type::anyType(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getEffectPhi(unsigned nEffectInputs) //### cache common operands in the static pool
-{
- return Operation::create(m_graphPool, Meta::EffectPhi,
- 0, uint16_t(nEffectInputs), 1,
- 0, 1, 0,
- Type(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getUnwindDispatch(unsigned nContinuations, int unwindHandlerOffset,
- int fallthroughSuccessor)
-{
- return OperationWithPayload<UnwindDispatchPayload>::create(
- m_graphPool, Meta::UnwindDispatch,
- 0, 1, 1, 0, nContinuations, nContinuations,
- Type(), Operation::NoFlags,
- UnwindDispatchPayload(unwindHandlerOffset,
- fallthroughSuccessor));
-}
-
-Operation *OperationBuilder::getHandleUnwind(int unwindHandlerOffset)
-{
- return OperationWithPayload<HandleUnwindPayload>::create(m_graphPool, Meta::HandleUnwind,
- 0, 1, 1, 0, 1, 1,
- Type(), Operation::NoFlags,
- HandleUnwindPayload(unwindHandlerOffset));
-}
-
-Operation *OperationBuilder::getFrameState(uint16_t frameSize)
-{
- if (m_opFrameState == nullptr)
- m_opFrameState = Operation::create(m_graphPool, Meta::FrameState,
- frameSize, 0, 0, 0, 0, 1,
- Type(), Operation::NoFlags);
- else
- Q_ASSERT(frameSize == m_opFrameState->valueInputCount());
-
- return m_opFrameState;
-}
-
-Operation *OperationBuilder::getStart(uint16_t outputCount)
-{
- return Operation::create(m_graphPool, Meta::Start,
- 0, 0, 0,
- outputCount, 1, 1,
- Type(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getEnd(uint16_t controlInputCount)
-{
- return Operation::create(m_graphPool, Meta::End,
- 0, 0, controlInputCount,
- 0, 0, 0,
- Type(), Operation::NoFlags);
-}
-
-inline Operation *createOperation(Operation::Kind kind, QQmlJS::MemoryPool *staticPool)
-{
- auto get = [&](uint16_t inValueCount, uint16_t inEffectCount, uint16_t inControlCount,
- uint16_t outValueCount, uint16_t outEffectCount, uint16_t outControlCount,
- Type (*typeCreator)(), uint8_t flags) {
- return Operation::create(staticPool, kind, inValueCount, inEffectCount, inControlCount,
- outValueCount, outEffectCount, outControlCount, typeCreator(),
- flags);
- };
-
- using K = Operation::Kind;
- using F = Operation::Flags;
- const auto none = &Type::noneType;
- const auto any = &Type::anyType;
- const auto number = &Type::numberType;
- const auto boolean = &Type::booleanType;
-
- switch (kind) {
- case K::Undefined:
- return OperationWithPayload<ConstantPayload>::create(
- staticPool, K::Undefined, 0, 0, 0, 1, 0, 0, Type::undefinedType(), F::NoFlags,
- ConstantPayload(Primitive::undefinedValue()));
- case K::Empty:
- return OperationWithPayload<ConstantPayload>::create(
- staticPool, K::Constant, 0, 0, 0, 1, 0, 0, Type::emptyType(), Operation::NoFlags,
- ConstantPayload(Primitive::emptyValue()));
- case K::Engine: return get(1, 0, 0, 1, 0, 0, none, F::NoFlags);
- case K::CppFrame: return get(1, 0, 0, 1, 0, 0, none, F::NoFlags);
- case K::Function: return get(1, 0, 0, 1, 0, 0, none, F::NoFlags);
- case K::Jump: return get(0, 0, 1, 0, 0, 1, none, F::NoFlags);
- case K::Return: return get(1, 1, 1, 0, 0, 1, none, F::NoFlags);
- case K::Branch: return get(1, 0, 1, 0, 0, 2, none, F::HasFrameStateInput | F::NeedsBytecodeOffsets);
- case K::IfTrue: return get(0, 0, 1, 0, 0, 1, none, F::NoFlags);
- case K::IfFalse: return get(0, 0, 1, 0, 0, 1, none, F::NoFlags);
- case K::SelectOutput: return get(3, 1, 1, 1, 1, 1, any, F::NoFlags);
- case K::Throw: return get(1, 1, 1, 0, 1, 1, any, F::NeedsBytecodeOffsets);
- case K::OnException: return get(0, 0, 1, 0, 0, 1, none, F::NoFlags);
- case K::ThrowReferenceError: return get(1, 1, 1, 0, 1, 1, any, F::NeedsBytecodeOffsets);
- case K::UnwindToLabel: return get(2, 1, 1, 0, 1, 1, none, F::NoFlags);
- case K::LoadRegExp: return get(1, 0, 0, 1, 0, 0, any, F::NoFlags);
- case K::ScopedLoad: return get(2, 1, 0, 1, 1, 0, any, F::NoFlags);
- case K::ScopedStore: return get(3, 1, 0, 0, 1, 0, none, F::NoFlags);
- case K::JSLoadElement: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSGetLookup: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSLoadProperty: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSStoreElement: return get(3, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSSetLookupStrict: return get(3, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSSetLookupSloppy: return get(3, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSStoreProperty: return get(3, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSLoadName: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSLoadGlobalLookup: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSStoreNameSloppy: return get(2, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSStoreNameStrict: return get(2, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSLoadSuperProperty: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSStoreSuperProperty: return get(2, 1, 1, 0, 1, 2, any, F::CanThrow);
- case K::JSLoadClosure: return get(1, 1, 0, 1, 1, 0, any, F::Pure);
- case K::JSGetIterator: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
-
- // special case: see GraphBuilder::generate_IteratorNext
- case K::JSIteratorNext: return get(2, 1, 1, 2, 1, 1, any, F::NoFlags);
-
- // special case: see GraphBuilder::generate_IteratorNext
- case K::JSIteratorNextForYieldStar: return get(3, 1, 1, 2, 1, 1, any, F::NoFlags);
-
- case K::JSIteratorClose: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSDeleteProperty: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSDeleteName: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSIn: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSInstanceOf: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::QMLLoadQmlContextPropertyLookup: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
-
- case K::JSEqual: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
- case K::JSGreaterThan: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
- case K::JSGreaterEqual: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
- case K::JSLessThan: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
- case K::JSLessEqual: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
- case K::JSStrictEqual: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
-
- case K::JSAdd: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSSubtract: return get(2, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::JSMultiply: return get(2, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::JSDivide: return get(2, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::JSModulo: return get(2, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::JSExponentiate: return get(2, 1, 1, 1, 1, 2, number, F::CanThrow);
-
- case K::JSBitAnd: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSBitOr: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSBitXor: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSUnsignedShiftRight: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSShiftRight: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSShiftLeft: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
-
- case K::JSNegate: return get(1, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::JSToNumber: return get(1, 1, 1, 1, 1, 2, number, F::CanThrow);
- case K::Alloca: return get(1, 0, 0, 1, 0, 0, none, F::NoFlags);
-
- //### it is questionable if VAAlloc/VASeal need effect edges
- case K::VAAlloc: return get(1, 1, 0, 1, 1, 0, none, F::NoFlags);
-
- case K::VAStore: return get(3, 0, 0, 1, 0, 0, none, F::NoFlags);
-
- case K::JSTypeofName: return get(1, 1, 0, 1, 1, 0, any, F::NoFlags);
- case K::JSTypeofValue: return get(1, 0, 0, 1, 0, 0, any, F::Pure);
- case K::JSDeclareVar: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::JSDestructureRestElement: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
-
- case K::JSCreateCallContext: return get(0, 1, 1, 0, 1, 1, none, F::NoFlags);
- case K::JSCreateCatchContext: return get(2, 1, 1, 1, 1, 1, none, F::NoFlags);
- case K::JSCreateWithContext: return get(1, 1, 1, 1, 1, 1, any, F::NoFlags);
- case K::JSCreateBlockContext: return get(1, 1, 1, 1, 1, 1, none, F::NoFlags);
- case K::JSCloneBlockContext: return get(0, 1, 1, 0, 1, 1, none, F::NoFlags);
- case K::JSCreateScriptContext: return get(1, 1, 1, 1, 1, 1, none, F::NoFlags);
- case K::JSPopScriptContext: return get(0, 1, 1, 1, 1, 1, none, F::NoFlags);
- case K::PopContext: return get(0, 1, 1, 0, 1, 1, none, F::NoFlags);
-
- case K::JSThisToObject: return get(1, 1, 1, 0, 1, 2, any, F::NoFlags);
- case K::JSCreateMappedArgumentsObject: return get(0, 1, 0, 1, 1, 0, any, F::NoFlags);
- case K::JSCreateUnmappedArgumentsObject: return get(0, 1, 0, 1, 1, 0, any, F::NoFlags);
- case K::JSCreateRestParameter: return get(1, 0, 0, 1, 0, 0, any, F::NoFlags);
- case K::JSLoadSuperConstructor: return get(1, 1, 1, 1, 1, 2, any, F::NoFlags);
- case K::JSThrowOnNullOrUndefined: return get(1, 1, 1, 0, 1, 2, none, F::CanThrow);
- case K::JSGetTemplateObject: return get(1, 0, 0, 1, 0, 0, any, F::NoFlags);
- case K::StoreThis: return get(1, 1, 0, 1, 1, 0, any, F::NoFlags);
-
- case K::GetException: return get(0, 1, 0, 1, 1, 0, any, F::NoFlags);
- case K::SetException: return get(1, 1, 0, 0, 1, 0, any, F::NoFlags);
-
- case K::ToObject: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
- case K::ToBoolean: return get(1, 0, 0, 1, 0, 0, boolean, F::Pure);
-
- case K::IsEmpty: return get(1, 0, 0, 1, 0, 0, boolean, F::Pure);
-
- case K::BooleanNot: return get(1, 0, 0, 1, 0, 0, boolean, F::NoFlags);
- case K::HasException: return get(1, 1, 0, 1, 1, 0, boolean, F::NoFlags);
-
- case K::Swap: return get(0, 0, 0, 0, 0, 0, none, F::NoFlags);
- case K::Move: return get(1, 0, 0, 1, 0, 0, none, F::NoFlags);
-
- default: // Non-static operations:
- return nullptr;
- }
-}
-
-Operation *OperationBuilder::staticOperation(Operation::Kind kind)
-{
- static QAtomicPointer<Operation *> ops;
- if (Operation **staticOps = ops.load())
- return staticOps[kind];
-
- static QAtomicInt initializing = 0;
- if (initializing.testAndSetOrdered(0, 1)) {
- // This is safe now, because we can only run this piece of code once during the life time
- // of the application as we can only change initializing from 0 to 1 once.
- Operation **staticOps = new Operation *[Meta::KindsEnd];
- static QQmlJS::MemoryPool pool;
- for (int i = 0; i < Meta::KindsEnd; ++i)
- staticOps[i] = createOperation(Operation::Kind(i), &pool);
- bool success = ops.testAndSetOrdered(nullptr, staticOps);
- Q_ASSERT(success);
- } else {
- // Unfortunately we need to busy wait now until the other thread finishes the static
- // initialization;
- while (!ops.load()) {}
- }
-
- return ops.load()[kind];
-}
-
-Operation *OperationBuilder::getJSVarArgsCall(Operation::Kind kind, uint16_t argc)
-{
- return Operation::create(m_graphPool, kind,
- argc, 1, 1, 1, 1, 2,
- Type::anyType(), Operation::CanThrow);
-}
-
-Operation *OperationBuilder::getJSTailCall(uint16_t argc)
-{
- return Operation::create(m_graphPool, Meta::JSTailCall,
- argc, 1, 1, 0, 0, 1,
- Type(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getTailCall()
-{
- // special varargs call, takes cppframe, engine, func, thisObject, argv, argc
- return Operation::create(m_graphPool, Meta::TailCall,
- 6, 1, 1, 0, 0, 1,
- Type(), Operation::NoFlags);
-}
-
-Operation *OperationBuilder::getCall(Operation::Kind callee)
-{
- const bool canThrow = CallPayload::canThrow(callee);
- const Type retTy = CallPayload::returnType(callee);
- uint16_t nControlInputs = 0;
- uint16_t nControlOutputs = 0;
- if (canThrow) {
- nControlInputs = 1;
- nControlOutputs += 2;
- }
- if (CallPayload::changesContext(callee)) {
- nControlInputs = 1;
- nControlOutputs = std::max<uint16_t>(nControlInputs, 1);
- }
- if (callee == Meta::Throw || callee == Meta::ThrowReferenceError ||
- callee == Meta::JSIteratorNext || callee == Meta::JSIteratorNextForYieldStar) {
- nControlInputs = 1;
- nControlOutputs = 1;
- }
- Operation::Flags flags = Operation::NoFlags;
- if (canThrow)
- flags = Operation::Flags(flags | Operation::CanThrow);
- if (CallPayload::isPure(callee))
- flags = Operation::Flags(flags | Operation::Pure);
- const uint16_t nEffects = (flags & Operation::Pure) ? 0 : 1;
- const uint16_t nValueOutputs = retTy.isNone() ? 0 : 1;
- const uint16_t nValueInputs = CallPayload::argc(callee);
-
- return OperationWithPayload<CallPayload>::create(
- m_graphPool, Meta::Call,
- nValueInputs, nEffects, nControlInputs,
- nValueOutputs, nEffects, nControlOutputs,
- retTy, flags,
- CallPayload(callee));
-}
-
-Operation *OperationBuilder::getVASeal(uint16_t nElements)
-{
- return Operation::create(m_graphPool, Meta::VASeal,
- nElements + 1, 1, 0, 1, 1, 0,
- Type::anyType(), Operation::NoFlags);
-}
-
-QString Operation::debugString() const
-{
- switch (kind()) {
-
- case Meta::Constant:
- return QStringLiteral("Constant[%1]").arg(ConstantPayload::get(*this)->debugString());
- case Meta::Parameter:
- return QStringLiteral("Parameter[%1]").arg(ParameterPayload::get(*this)->debugString());
- case Meta::Call:
- return QStringLiteral("Call[%1]").arg(CallPayload::get(*this)->debugString());
- case Meta::UnwindDispatch:
- return QStringLiteral("UnwindDispatch[%1]").arg(UnwindDispatchPayload::get(*this)
- ->debugString());
- case Meta::HandleUnwind:
- return QStringLiteral("HandleUnwind[%1]").arg(HandleUnwindPayload::get(*this)
- ->debugString());
-
- default:
- return QString::fromLatin1(QMetaEnum::fromType<Meta::OpKind>().valueToKey(kind()));
- }
-}
-
-QString ConstantPayload::debugString() const
-{
- return debugString(m_value);
-}
-
-QString ConstantPayload::debugString(QV4::Value v)
-{
- if (v.isManaged())
- return QString::asprintf("Ptr: %p", v.heapObject());
- if (v.isEmpty())
- return QStringLiteral("empty");
- return v.toQStringNoThrow();
-}
-
-QString ParameterPayload::debugString() const
-{
- return QStringLiteral("%1").arg(m_index);
-}
-
-QString UnwindDispatchPayload::debugString() const
-{
- return QStringLiteral("%1, %2").arg(QString::number(m_fallthroughSuccessor),
- QString::number(m_unwindHandlerOffset));
-}
-
-QString HandleUnwindPayload::debugString() const
-{
- return QStringLiteral("%1").arg(m_unwindHandlerOffset);
-}
-
-static Type translateType(RuntimeSupport::ArgumentType t)
-{
- switch (t) {
- case RuntimeSupport::ArgumentType::Int: return Type::int32Type();
- case RuntimeSupport::ArgumentType::Bool: return Type::booleanType();
- case RuntimeSupport::ArgumentType::Void: return Type();
- case RuntimeSupport::ArgumentType::Engine: return Type::rawPointerType();
- case RuntimeSupport::ArgumentType::ValueRef: return Type::anyType();
- case RuntimeSupport::ArgumentType::ValueArray: return Type::anyType();
- case RuntimeSupport::ArgumentType::ReturnedValue: return Type::anyType();
- default: Q_UNREACHABLE();
- }
-}
-
-template<template<typename Operation> class M /* MetaOperation */, typename ReturnValue>
-static ReturnValue operateOnRuntimeCall(Operation::Kind kind, bool abortOnMissingCall = true)
-{
- using K = Operation::Kind;
- using R = Runtime;
-
- switch (kind) {
- case K::Throw: return M<R::ThrowException>::doIt();
- case K::ThrowReferenceError: return M<R::ThrowReferenceError>::doIt();
-
- case K::JSEqual: return M<R::CompareEqual>::doIt();
- case K::JSGreaterThan: return M<R::CompareGreaterThan>::doIt();
- case K::JSGreaterEqual: return M<R::CompareGreaterEqual>::doIt();
- case K::JSLessThan: return M<R::CompareLessThan>::doIt();
- case K::JSLessEqual: return M<R::CompareLessEqual>::doIt();
- case K::JSStrictEqual: return M<R::CompareStrictEqual>::doIt();
-
- case K::JSBitAnd: return M<R::BitAnd>::doIt();
- case K::JSBitOr: return M<R::BitOr>::doIt();
- case K::JSBitXor: return M<R::BitXor>::doIt();
- case K::JSUnsignedShiftRight: return M<R::UShr>::doIt();
- case K::JSShiftRight: return M<R::Shr>::doIt();
- case K::JSShiftLeft: return M<R::Shl>::doIt();
-
- case K::JSAdd: return M<R::Add>::doIt();
- case K::JSSubtract: return M<R::Sub>::doIt();
- case K::JSMultiply: return M<R::Mul>::doIt();
- case K::JSDivide: return M<R::Div>::doIt();
- case K::JSModulo: return M<R::Mod>::doIt();
- case K::JSExponentiate: return M<R::Exp>::doIt();
-
- case K::ToBoolean: return M<R::ToBoolean>::doIt();
- case K::ToObject: return M<R::ToObject>::doIt();
-
- case K::JSNegate: return M<R::UMinus>::doIt();
- case K::JSToNumber: return M<R::ToNumber>::doIt();
-
- case K::JSLoadName: return M<R::LoadName>::doIt();
- case K::JSLoadElement: return M<R::LoadElement>::doIt();
- case K::JSStoreElement: return M<R::StoreElement>::doIt();
- case K::JSGetLookup: return M<R::GetLookup>::doIt();
- case K::JSSetLookupStrict: return M<R::SetLookupStrict>::doIt();
- case K::JSSetLookupSloppy: return M<R::SetLookupSloppy>::doIt();
- case K::JSLoadProperty: return M<R::LoadProperty>::doIt();
- case K::JSStoreProperty: return M<R::StoreProperty>::doIt();
- case K::JSLoadGlobalLookup: return M<R::LoadGlobalLookup>::doIt();
- case K::JSStoreNameSloppy: return M<R::StoreNameSloppy>::doIt();
- case K::JSStoreNameStrict: return M<R::StoreNameStrict>::doIt();
- case K::JSLoadSuperProperty: return M<R::LoadSuperProperty>::doIt();
- case K::JSStoreSuperProperty: return M<R::StoreSuperProperty>::doIt();
- case K::JSLoadClosure: return M<R::Closure>::doIt();
- case K::JSGetIterator: return M<R::GetIterator>::doIt();
- case K::JSIteratorNext: return M<R::IteratorNext>::doIt();
- case K::JSIteratorNextForYieldStar: return M<R::IteratorNextForYieldStar>::doIt();
- case K::JSIteratorClose: return M<R::IteratorClose>::doIt();
- case K::JSDeleteProperty: return M<R::DeleteProperty>::doIt();
- case K::JSDeleteName: return M<R::DeleteName>::doIt();
- case K::JSIn: return M<R::In>::doIt();
- case K::JSInstanceOf: return M<R::Instanceof>::doIt();
- case K::QMLLoadQmlContextPropertyLookup: return M<R::LoadQmlContextPropertyLookup>::doIt();
-
- case K::JSTypeofName: return M<R::TypeofName>::doIt();
- case K::JSTypeofValue: return M<R::TypeofValue>::doIt();
- case K::JSDeclareVar: return M<R::DeclareVar>::doIt();
- case K::JSDestructureRestElement: return M<R::DestructureRestElement>::doIt();
- case K::JSThisToObject: return M<R::ConvertThisToObject>::doIt();
- case K::JSCreateMappedArgumentsObject: return M<R::CreateMappedArgumentsObject>::doIt();
- case K::JSCreateUnmappedArgumentsObject: return M<R::CreateUnmappedArgumentsObject>::doIt();
- case K::JSCreateRestParameter: return M<R::CreateRestParameter>::doIt();
- case K::JSLoadSuperConstructor: return M<R::LoadSuperConstructor>::doIt();
- case K::JSThrowOnNullOrUndefined: return M<R::ThrowOnNullOrUndefined>::doIt();
-
- case K::JSCreateCallContext: return M<R::PushCallContext>::doIt();
- case K::JSCreateCatchContext: return M<R::PushCatchContext>::doIt();
- case K::JSCreateWithContext: return M<R::PushWithContext>::doIt();
- case K::JSCreateBlockContext: return M<R::PushBlockContext>::doIt();
- case K::JSCloneBlockContext: return M<R::CloneBlockContext>::doIt();
- case K::JSCreateScriptContext: return M<R::PushScriptContext>::doIt();
- case K::JSPopScriptContext: return M<R::PopScriptContext>::doIt();
-
- case K::LoadRegExp: return M<R::RegexpLiteral>::doIt();
- case K::JSGetTemplateObject: return M<R::GetTemplateObject>::doIt();
-
- case K::JSCallName: return M<R::CallName>::doIt();
- case K::JSCallValue: return M<R::CallValue>::doIt();
- case K::JSCallElement: return M<R::CallElement>::doIt();
- case K::JSCallLookup: return M<R::CallPropertyLookup>::doIt();
- case K::JSCallProperty: return M<R::CallProperty>::doIt();
- case K::JSCallGlobalLookup: return M<R::CallGlobalLookup>::doIt();
- case K::JSCallPossiblyDirectEval: return M<R::CallPossiblyDirectEval>::doIt();
- case K::JSCallWithReceiver: return M<R::CallWithReceiver>::doIt();
- case K::JSDefineObjectLiteral: return M<R::ObjectLiteral>::doIt();
- case K::JSDefineArray: return M<R::ArrayLiteral>::doIt();
- case K::JSCallWithSpread: return M<R::CallWithSpread>::doIt();
- case K::JSConstruct: return M<R::Construct>::doIt();
- case K::JSConstructWithSpread: return M<R::ConstructWithSpread>::doIt();
- case K::JSTailCall: return M<R::TailCall>::doIt();
- case K::JSCreateClass: return M<R::CreateClass>::doIt();
- default:
- if (abortOnMissingCall)
- Q_UNREACHABLE();
- else
- return ReturnValue();
- }
-}
-
-template<typename Method>
-struct IsRuntimeMethodOperation
-{
- static constexpr bool doIt() { return true; }
-};
-
-bool CallPayload::isRuntimeCall(Operation::Kind m)
-{
- return operateOnRuntimeCall<IsRuntimeMethodOperation, bool>(m, false);
-}
-
-QString CallPayload::debugString() const
-{
- return QString::fromLatin1(QMetaEnum::fromType<Meta::OpKind>().valueToKey(m_callee));
-}
-
-template<typename Method>
-struct MethodArgcOperation
-{
- static constexpr unsigned doIt() { return RuntimeSupport::argumentCount<Method>(); }
-};
-
-unsigned CallPayload::argc(Operation::Kind callee)
-{
- return operateOnRuntimeCall<MethodArgcOperation, unsigned>(callee);
-}
-
-template<typename Method> struct MethodArg1TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg1Type<Method>(); } };
-template<typename Method> struct MethodArg2TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg2Type<Method>(); } };
-template<typename Method> struct MethodArg3TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg3Type<Method>(); } };
-template<typename Method> struct MethodArg4TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg4Type<Method>(); } };
-template<typename Method> struct MethodArg5TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg5Type<Method>(); } };
-template<typename Method> struct MethodArg6TyOperation { static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::arg6Type<Method>(); } };
-
-static RuntimeSupport::ArgumentType untranslatedArgumentType(Operation::Kind m, unsigned arg)
-{
- if (m == Meta::JSTailCall) {
- if (arg < 4)
- return RuntimeSupport::ArgumentType::ValueRef;
- else
- return RuntimeSupport::ArgumentType::Invalid;
- }
-
- switch (arg) {
- case 0: return operateOnRuntimeCall<MethodArg1TyOperation, RuntimeSupport::ArgumentType>(m);
- case 1: return operateOnRuntimeCall<MethodArg2TyOperation, RuntimeSupport::ArgumentType>(m);
- case 2: return operateOnRuntimeCall<MethodArg3TyOperation, RuntimeSupport::ArgumentType>(m);
- case 3: return operateOnRuntimeCall<MethodArg4TyOperation, RuntimeSupport::ArgumentType>(m);
- case 4: return operateOnRuntimeCall<MethodArg5TyOperation, RuntimeSupport::ArgumentType>(m);
- case 5: return operateOnRuntimeCall<MethodArg6TyOperation, RuntimeSupport::ArgumentType>(m);
- default: return RuntimeSupport::ArgumentType::Invalid;
- }
-}
-
-bool CallPayload::needsStorageOnJSStack(Operation::Kind m, unsigned arg, const Operation *op,
- Type nodeType)
-{
- auto argTy = untranslatedArgumentType(m, arg);
- if (argTy == RuntimeSupport::ArgumentType::ValueArray)
- return true;
- if (argTy != RuntimeSupport::ArgumentType::ValueRef)
- return false;
-
- if (op->kind() == Meta::Constant)
- return true;
-
- return !nodeType.isObject() && !nodeType.isRawPointer() && !nodeType.isAny();
-}
-
-template<typename Method>
-struct MethodRetTyOperation
-{
- static constexpr RuntimeSupport::ArgumentType doIt() { return RuntimeSupport::retType<Method>(); }
-};
-
-Type CallPayload::returnType(Operation::Kind m)
-{
- if (m == Meta::JSTailCall)
- return Type();
-
- auto t = operateOnRuntimeCall<MethodRetTyOperation, RuntimeSupport::ArgumentType>(m);
- return translateType(t);
-}
-
-static int firstArgumentPositionForType(Operation::Kind m, RuntimeSupport::ArgumentType type)
-{
- if (operateOnRuntimeCall<MethodArg1TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 1;
- if (operateOnRuntimeCall<MethodArg2TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 2;
- if (operateOnRuntimeCall<MethodArg3TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 3;
- if (operateOnRuntimeCall<MethodArg4TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 4;
- if (operateOnRuntimeCall<MethodArg5TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 5;
- if (operateOnRuntimeCall<MethodArg6TyOperation, RuntimeSupport::ArgumentType>(m) == type)
- return 6;
- return -1;
-}
-
-unsigned CallPayload::varArgsStart(Operation::Kind m)
-{
- if (m == Meta::JSTailCall)
- return 4 - 1;
-
- int pos = firstArgumentPositionForType(m, RuntimeSupport::ArgumentType::ValueArray) - 1;
- Q_ASSERT(pos >= 0);
- return pos;
-}
-
-bool CallPayload::isVarArgsCall(Operation::Kind m)
-{
- if (m == Meta::JSTailCall)
- return true;
- if (lastArgumentIsOutputValue(m))
- return false;
- return firstArgumentPositionForType(m, RuntimeSupport::ArgumentType::ValueArray) != -1;
-}
-
-bool CallPayload::isVarArgsCall() const
-{
- return isVarArgsCall(m_callee);
-}
-
-template<typename Method>
-struct MethodsLastArgumentIsOutputValue
-{
- static constexpr bool doIt() { return Method::lastArgumentIsOutputValue; }
-};
-
-bool CallPayload::lastArgumentIsOutputValue(Operation::Kind m)
-{
- return operateOnRuntimeCall<MethodsLastArgumentIsOutputValue, bool>(m);
-}
-
-template<typename Method>
-struct MethodChangesContext
-{
- static constexpr bool doIt() { return Method::changesContext; }
-};
-
-bool CallPayload::changesContext(Operation::Kind m)
-{
- return operateOnRuntimeCall<MethodChangesContext, bool>(m);
-}
-
-template<typename Method>
-struct MethodIsPure
-{
- static constexpr bool doIt() { return Method::pure; }
-};
-
-bool CallPayload::isPure(Operation::Kind m)
-{
- return operateOnRuntimeCall<MethodIsPure, bool>(m);
-}
-
-template<typename Method>
-struct MethodCanThrow
-{
- static constexpr bool doIt() { return Method::throws; }
-};
-
-bool CallPayload::canThrow(Operation::Kind m)
-{
- switch (m) {
- case Meta::Throw: Q_FALLTHROUGH();
- case Meta::ThrowReferenceError:
- // the execution path following these instructions is already linked up to the exception handler
- return false;
- case Meta::JSIteratorNext: Q_FALLTHROUGH();
- case Meta::JSIteratorNextForYieldStar:
- // special case: see GraphBuilder::generate_IteratorNext
- return false;
- default:
- return operateOnRuntimeCall<MethodCanThrow, bool>(m);
- }
-}
-
-bool CallPayload::takesEngineAsArg(Operation::Kind m, int arg)
-{
- return untranslatedArgumentType(m, arg) == RuntimeSupport::ArgumentType::Engine;
-}
-
-bool CallPayload::takesFunctionAsArg(Operation::Kind m, int arg)
-{
- return untranslatedArgumentType(m, arg) == RuntimeSupport::ArgumentType::Function;
-}
-
-bool CallPayload::takesFrameAsArg(Operation::Kind m, int arg)
-{
- return untranslatedArgumentType(m, arg) == RuntimeSupport::ArgumentType::Frame;
-}
-
-template<typename Method>
-struct GetMethodPtr
-{
- static constexpr void *doIt() { return reinterpret_cast<void *>(&Method::call); }
-};
-
-void *CallPayload::getMethodPtr(Operation::Kind m)
-{
- return operateOnRuntimeCall<GetMethodPtr, void *>(m);
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4operation_p.h b/src/qml/jit/qv4operation_p.h
deleted file mode 100644
index 43214023e8..0000000000
--- a/src/qml/jit/qv4operation_p.h
+++ /dev/null
@@ -1,567 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4OPERATION_P_H
-#define QV4OPERATION_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 <private/qv4ir_p.h>
-#include <private/qqmljsmemorypool_p.h>
-
-#include <QtCore/qatomic.h>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-namespace Meta {
-enum OpKind: uint16_t {
- FrameState,
- Start,
- End,
-
- Undefined,
- Constant,
- Parameter,
- Empty,
- Engine,
- CppFrame,
- Function,
-
- Jump,
- Return,
- JSTailCall,
- TailCall,
- Branch,
- IfTrue,
- IfFalse,
- Region,
- OnException,
- Phi,
- EffectPhi,
- SelectOutput,
- UnwindDispatch,
- UnwindToLabel,
- HandleUnwind,
- Throw,
- ThrowReferenceError,
-
- Call,
-
- LoadRegExp,
- ScopedLoad,
- ScopedStore,
-
- JSLoadElement,
- JSStoreElement,
- JSGetLookup,
- JSSetLookupStrict,
- JSSetLookupSloppy,
- JSLoadProperty,
- JSStoreProperty,
- JSLoadName,
- JSLoadGlobalLookup,
- JSStoreNameSloppy,
- JSStoreNameStrict,
- JSLoadSuperProperty,
- JSStoreSuperProperty,
- JSLoadClosure,
- JSGetIterator,
- JSIteratorNext,
- JSIteratorNextForYieldStar,
- JSIteratorClose,
- JSDeleteProperty,
- JSDeleteName,
- JSIn,
- JSInstanceOf,
-
- /* ok, these are qml object ops, but we don't care for now and treat them as JS */
- QMLLoadQmlContextPropertyLookup,
- QMLCallQmlContextPropertyLookup,
-
- JSEqual,
- JSGreaterThan,
- JSGreaterEqual,
- JSLessThan,
- JSLessEqual,
- JSStrictEqual,
-
- JSAdd,
- JSSubtract,
- JSMultiply,
- JSDivide,
- JSModulo,
- JSExponentiate,
-
- JSBitAnd,
- JSBitOr,
- JSBitXor,
- JSUnsignedShiftRight,
- JSShiftRight,
- JSShiftLeft,
-
- JSNegate,
- JSToNumber,
-
- JSCallName,
- JSCallValue,
- JSCallElement,
- JSCallProperty,
- JSCallLookup,
- JSCallGlobalLookup,
- JSCallPossiblyDirectEval,
- JSCallWithReceiver,
- JSCallWithSpread,
- JSDefineObjectLiteral,
- JSDefineArray,
- JSCreateClass,
- JSConstruct,
- JSConstructWithSpread,
-
- JSTypeofName,
- JSTypeofValue,
- JSDeclareVar,
- JSDestructureRestElement,
- JSThisToObject,
- JSCreateMappedArgumentsObject,
- JSCreateUnmappedArgumentsObject,
- JSCreateRestParameter,
- JSLoadSuperConstructor,
- JSThrowOnNullOrUndefined,
- JSGetTemplateObject,
- StoreThis,
-
- JSCreateCallContext,
- JSCreateCatchContext,
- JSCreateWithContext,
- JSCreateBlockContext,
- JSCloneBlockContext,
- JSCreateScriptContext,
- JSPopScriptContext,
- PopContext,
-
- GetException,
- SetException,
-
- ToObject,
- ToBoolean,
-
- //### do we need this? Or should a later phase generate JumpIsEmpty?
- IsEmpty,
-
- Alloca,
- VAAlloc,
- VAStore,
- VASeal,
-
- BooleanNot,
- HasException,
-
- // Low level, used by the register allocator and stack allocator:
- Swap,
- Move,
- KindsEnd
-};
-Q_NAMESPACE
-Q_ENUM_NS(OpKind)
-} // namespace Ops
-
-class Operation
-{
- Q_DISABLE_COPY_MOVE(Operation)
-
-public:
- using Kind = Meta::OpKind;
-
- enum Flags: uint8_t {
- NoFlags = 0,
- ThrowsFlag = 1 << 0,
- Pure = 1 << 1, // no read/write side effect, cannot throw, cannot deopt, and is idempotent
- NeedsBytecodeOffsets = 1 << 2,
-
- CanThrow = ThrowsFlag | NeedsBytecodeOffsets,
-
- HasFrameStateInput = 1 << 3,
- };
-
-public:
- static Operation *create(QQmlJS::MemoryPool *pool, Kind kind, uint16_t inValueCount,
- uint16_t inEffectCount, uint16_t inControlCount,
- uint16_t outValueCount, uint16_t outEffectCount,
- uint16_t outControlCount, Type type, uint8_t flags)
- {
- return pool->New<Operation>(kind, inValueCount, inEffectCount, inControlCount,
- outValueCount, outEffectCount, outControlCount,
- type, Flags(flags));
- }
-
- Kind kind() const
- { return m_kind; }
-
- bool isConstant() const
- {
- switch (kind()) {
- case Meta::Undefined: Q_FALLTHROUGH();
- case Meta::Constant:
- case Meta::Empty:
- return true;
- default:
- return false;
- }
- }
-
- QString debugString() const;
-
- uint16_t valueInputCount() const { return m_inValueCount; }
- uint16_t effectInputCount() const { return m_inEffectCount; }
- uint16_t controlInputCount() const { return m_inControlCount; }
- uint16_t valueOutputCount() const { return m_outValueCount; }
- uint16_t effectOutputCount() const { return m_outEffectCount; }
- uint16_t controlOutputCount() const { return m_outControlCount; }
-
- unsigned indexOfFirstEffect() const { return m_inValueCount; }
- unsigned indexOfFirstControl() const { return m_inValueCount + m_inEffectCount; }
- unsigned indexOfFrameStateInput() const
- {
- return hasFrameStateInput() ? indexOfFirstControl() + m_inControlCount
- : std::numeric_limits<unsigned>::max();
- }
-
- Type type() const
- { return m_type; }
-
- bool canThrow() const
- { return m_flags & ThrowsFlag; }
-
- bool isPure() const
- { return m_flags & Pure; }
-
- bool needsBytecodeOffsets() const
- { return m_flags & NeedsBytecodeOffsets; }
-
- bool hasFrameStateInput() const
- { return m_flags & HasFrameStateInput; }
-
- unsigned totalInputCount() const
- {
- return valueInputCount() + effectInputCount() + controlInputCount() +
- (hasFrameStateInput() ? 1 : 0);
- }
- unsigned totalOutputCount() const { return valueOutputCount() + effectOutputCount() + controlOutputCount(); }
-
-protected:
- friend class QQmlJS::MemoryPool;
- Operation(Kind kind,
- uint16_t inValueCount, uint16_t inEffectCount, uint16_t inControlCount,
- uint16_t outValueCount, uint16_t outEffectCount, uint16_t outControlCount,
- Type type, uint8_t flags)
- : m_kind(kind)
- , m_inValueCount(inValueCount)
- , m_inEffectCount(inEffectCount)
- , m_inControlCount(inControlCount)
- , m_outValueCount(outValueCount)
- , m_outEffectCount(outEffectCount)
- , m_outControlCount(outControlCount)
- , m_type(type)
- , m_flags(Flags(flags))
- {
- }
-
- ~Operation() = default;
-
-private:
- Kind m_kind;
- uint16_t m_inValueCount;
- uint16_t m_inEffectCount;
- uint16_t m_inControlCount;
- uint16_t m_outValueCount;
- uint16_t m_outEffectCount;
- uint16_t m_outControlCount;
- Type m_type;
- Flags m_flags;
-};
-
-template <typename Payload>
-class OperationWithPayload: public Operation
-{
-public:
- static OperationWithPayload *create(QQmlJS::MemoryPool *pool, Kind kind,
- uint16_t inValueCount, uint16_t inEffectCount, uint16_t inControlCount,
- uint16_t outValueCount, uint16_t outEffectCount, uint16_t outControlCount,
- Type type, Flags flags, Payload payload)
- {
- return pool->New<OperationWithPayload>(kind, inValueCount, inEffectCount, inControlCount,
- outValueCount, outEffectCount, outControlCount,
- type, flags, payload);
- }
-
- const Payload &payload() const
- { return m_payload; }
-
-protected:
- friend class QQmlJS::MemoryPool;
- OperationWithPayload(Kind kind,
- uint16_t inValueCount, uint16_t inEffectCount, uint16_t inControlCount,
- uint16_t outValueCount, uint16_t outEffectCount, uint16_t outControlCount,
- Type type, Flags flags, Payload payload)
- : Operation(kind,
- inValueCount, inEffectCount, inControlCount,
- outValueCount, outEffectCount, outControlCount,
- type, flags)
- , m_payload(payload)
- {}
-
- ~OperationWithPayload() = default;
-
-private:
- Payload m_payload;
-};
-
-class ConstantPayload
-{
-public:
- explicit ConstantPayload(QV4::Value v)
- : m_value(v)
- {}
-
- QV4::Value value() const
- { return m_value; }
-
- static const ConstantPayload *get(const Operation &op)
- {
- if (op.kind() != Meta::Constant)
- return nullptr;
-
- return &static_cast<const OperationWithPayload<ConstantPayload>&>(op).payload();
- }
-
- QString debugString() const;
- static QString debugString(QV4::Value v);
-
-private:
- QV4::Value m_value;
-};
-
-class ParameterPayload
-{
-public:
- ParameterPayload(size_t index, Function::StringId stringId)
- : m_index(index)
- , m_stringId(stringId)
- {}
-
- size_t parameterIndex() const
- { return m_index; }
-
- Function::StringId stringId() const
- { return m_stringId; }
-
- static const ParameterPayload *get(const Operation &op)
- {
- if (op.kind() != Meta::Parameter)
- return nullptr;
-
- return &static_cast<const OperationWithPayload<ParameterPayload>&>(op).payload();
- }
-
- QString debugString() const;
-
-private:
- size_t m_index;
- Function::StringId m_stringId;
-};
-
-class CallPayload
-{
-public:
- CallPayload(Operation::Kind callee)
- : m_callee(callee)
- {}
-
- static const CallPayload *get(const Operation &op)
- {
- if (op.kind() != Meta::Call)
- return nullptr;
-
- return &static_cast<const OperationWithPayload<CallPayload>&>(op).payload();
- }
-
- static bool isRuntimeCall(Operation::Kind m);
-
- Operation::Kind callee() const { return m_callee; }
- QString debugString() const;
-
- unsigned argc() const { return argc(m_callee); }
- static unsigned argc(Operation::Kind callee);
- static bool needsStorageOnJSStack(Operation::Kind m, unsigned arg, const Operation *op,
- Type nodeType);
- static Type returnType(Operation::Kind m);
- static int engineArgumentPosition(Operation::Kind m);
- static int functionArgumentPosition(Operation::Kind m);
-
- static constexpr unsigned NoVarArgs = std::numeric_limits<unsigned>::max();
- static unsigned varArgsStart(Operation::Kind m);
- static bool isVarArgsCall(Operation::Kind m);
- bool isVarArgsCall() const;
- static bool lastArgumentIsOutputValue(Operation::Kind m);
- static bool changesContext(Operation::Kind m);
- static bool isPure(Operation::Kind m);
- static bool canThrow(Operation::Kind m);
- static bool takesEngineAsArg(Operation::Kind m, int arg);
- static bool takesFunctionAsArg(Operation::Kind m, int arg);
- static bool takesFrameAsArg(Operation::Kind m, int arg);
- static void *getMethodPtr(Operation::Kind m);
-
-private:
- Operation::Kind m_callee;
-};
-
-class UnwindDispatchPayload
-{
-public:
- UnwindDispatchPayload(int unwindHandlerOffset, int fallthroughSuccessor)
- : m_unwindHandlerOffset(unwindHandlerOffset)
- , m_fallthroughSuccessor(fallthroughSuccessor)
- {}
-
- int unwindHandlerOffset() const
- { return m_unwindHandlerOffset; }
-
- int fallthroughSuccessor() const //### unused...
- { return m_fallthroughSuccessor; }
-
- static const UnwindDispatchPayload *get(const Operation &op)
- {
- if (op.kind() != Meta::UnwindDispatch)
- return nullptr;
-
- return &static_cast<const OperationWithPayload<UnwindDispatchPayload>&>(op).payload();
- }
-
- QString debugString() const;
-
-private:
- int m_unwindHandlerOffset;
- int m_fallthroughSuccessor;
-};
-
-class HandleUnwindPayload
-{
-public:
- HandleUnwindPayload(int unwindHandlerOffset)
- : m_unwindHandlerOffset(unwindHandlerOffset)
- {}
-
- int unwindHandlerOffset() const
- { return m_unwindHandlerOffset; }
-
- static const HandleUnwindPayload *get(const Operation &op)
- {
- if (op.kind() != Meta::HandleUnwind)
- return nullptr;
-
- return &static_cast<const OperationWithPayload<HandleUnwindPayload>&>(op).payload();
- }
-
- QString debugString() const;
-
-private:
- int m_unwindHandlerOffset;
-};
-
-class OperationBuilder
-{
- Q_DISABLE_COPY_MOVE(OperationBuilder)
-
- friend class QQmlJS::MemoryPool;
- OperationBuilder(QQmlJS::MemoryPool *graphPool);
-
-public:
- static OperationBuilder *create(QQmlJS::MemoryPool *pool);
- ~OperationBuilder() = delete;
-
- Operation *getConstant(QV4::Value v);
- Operation *getFrameState(uint16_t frameSize);
- Operation *getStart(uint16_t outputCount);
- Operation *getEnd(uint16_t controlInputCount);
- Operation *getParam(unsigned index, Function::StringId name);
- Operation *getRegion(unsigned nControlInputs);
- Operation *getPhi(unsigned nValueInputs);
- Operation *getEffectPhi(unsigned nEffectInputs);
- Operation *getUnwindDispatch(unsigned nControlOutputs, int unwindHandlerOffset, int fallthroughSuccessor);
- Operation *getHandleUnwind(int unwindHandlerOffset);
-
- template<Operation::Kind kind>
- Operation *get() {
- return staticOperation(kind);
- }
-
- Operation *getVASeal(uint16_t nElements);
-
- Operation *getJSVarArgsCall(Operation::Kind kind, uint16_t argc);
- Operation *getJSTailCall(uint16_t argc);
- Operation *getTailCall();
-
- Operation *getCall(Operation::Kind callee);
-
-private:
- QQmlJS::MemoryPool *m_graphPool; // used to store per-graph nodes
- Operation *m_opFrameState = nullptr;
- static Operation *staticOperation(Operation::Kind kind);
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4OPERATION_P_H
diff --git a/src/qml/jit/qv4runtimesupport_p.h b/src/qml/jit/qv4runtimesupport_p.h
deleted file mode 100644
index 0dc6022331..0000000000
--- a/src/qml/jit/qv4runtimesupport_p.h
+++ /dev/null
@@ -1,255 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4RUNTIMESUPPORT_P_H
-#define QV4RUNTIMESUPPORT_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 <qv4runtimeapi_p.h>
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-namespace RuntimeSupport {
-
-template <typename T>
-struct CountArguments {
- static constexpr unsigned count = 0;
-};
-template <typename RetTy, typename... Args>
-struct CountArguments<RetTy (*)(Args... args)> {
- static constexpr unsigned count = sizeof...(Args) ;
-};
-
-template<typename M>
-static constexpr unsigned argumentCount() {
- using type = decltype(&M::call);
- return CountArguments<type>::count;
-}
-
-enum class ArgumentType {
- Invalid,
- Engine,
- Frame,
- Function,
- ValueRef,
- ValueArray,
- ReturnedValue,
- Int,
- Bool,
- Void,
-};
-
-
-template <typename T>
-struct JavaScriptType
-{
- // No default type. We want to make sure everything we do is actually recognized.
-};
-
-template <typename T>
-struct ReturnValue
-{
- // No default type.
-};
-
-template <int I, typename T>
-struct Argument
-{
- // For simplicity, we add a default here. Otherwise we would need to spell out more
- // combinations of I and number of arguments of T.
- static constexpr ArgumentType type = ArgumentType::Invalid;
-};
-
-template <typename RetTy, typename T, typename... Args>
-struct Argument<1, RetTy (*)(T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename Arg1, typename T, typename... Args>
-struct Argument<2, RetTy (*)(Arg1, T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename Arg1, typename Arg2, typename T,
- typename... Args>
-struct Argument<3, RetTy (*)(Arg1, Arg2, T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename Arg1, typename Arg2,
- typename Arg3, typename T, typename... Args>
-struct Argument<4, RetTy (*)(Arg1, Arg2, Arg3, T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename Arg1, typename Arg2,
- typename Arg3, typename Arg4, typename T, typename... Args>
-struct Argument<5, RetTy (*)(Arg1, Arg2, Arg3, Arg4, T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename Arg1, typename Arg2,
- typename Arg3, typename Arg4, typename Arg5, typename T, typename... Args>
-struct Argument<6, RetTy (*)(Arg1, Arg2, Arg3, Arg4, Arg5, T, Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<T>::type;
-};
-
-template <typename RetTy, typename... Args>
-struct ReturnValue<RetTy (*)(Args... args)> {
- static constexpr ArgumentType type = JavaScriptType<RetTy>::type;
-};
-
-template<>
-struct JavaScriptType<QV4::ExecutionEngine *>
-{
- static constexpr ArgumentType type = ArgumentType::Engine;
-};
-
-template<>
-struct JavaScriptType<QV4::CppStackFrame *>
-{
- static constexpr ArgumentType type = ArgumentType::Frame;
-};
-
-template<>
-struct JavaScriptType<QV4::Function *>
-{
- static constexpr ArgumentType type = ArgumentType::Function;
-};
-
-template<>
-struct JavaScriptType<const QV4::Value &>
-{
- static constexpr ArgumentType type = ArgumentType::ValueRef;
-};
-
-template<>
-// We need to pass Value * in order to match a parmeter Value[].
-struct JavaScriptType<QV4::Value *>
-{
- static constexpr ArgumentType type = ArgumentType::ValueArray;
-};
-
-template<>
-struct JavaScriptType<int>
-{
- static constexpr ArgumentType type = ArgumentType::Int;
-};
-
-template<>
-struct JavaScriptType<QV4::Bool>
-{
- static constexpr ArgumentType type = ArgumentType::Bool;
-};
-
-template<>
-struct JavaScriptType<QV4::ReturnedValue>
-{
- static constexpr ArgumentType type = ArgumentType::ReturnedValue;
-};
-
-template<>
-struct JavaScriptType<void>
-{
- static constexpr ArgumentType type = ArgumentType::Void;
-};
-
-template<typename M>
-static constexpr ArgumentType retType() {
- using Type = decltype(&M::call);
- return ReturnValue<Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg1Type() {
- using Type = decltype(&M::call);
- return Argument<1, Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg2Type() {
- using Type = decltype(&M::call);
- return Argument<2, Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg3Type() {
- using Type = decltype(&M::call);
- return Argument<3, Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg4Type() {
- using Type = decltype(&M::call);
- return Argument<4, Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg5Type() {
- using Type = decltype(&M::call);
- return Argument<5, Type>::type;
-}
-
-template<typename M>
-static constexpr ArgumentType arg6Type() {
- using Type = decltype(&M::call);
- return Argument<6, Type>::type;
-}
-
-} // namespace RuntimeSupport
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4RUNTIMESUPPORT_P_H
diff --git a/src/qml/jit/qv4schedulers.cpp b/src/qml/jit/qv4schedulers.cpp
deleted file mode 100644
index 0dffefa951..0000000000
--- a/src/qml/jit/qv4schedulers.cpp
+++ /dev/null
@@ -1,912 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-
-#include "qv4schedulers_p.h"
-#include "qv4util_p.h"
-#include "qv4graph_p.h"
-#include "qv4blockscheduler_p.h"
-#include "qv4stackframe_p.h"
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace IR {
-
-Q_LOGGING_CATEGORY(lcSched, "qt.v4.ir.scheduling")
-Q_LOGGING_CATEGORY(lcDotCFG, "qt.v4.ir.scheduling.cfg")
-
-static bool needsScheduling(Node *n)
-{
- if (n->operation()->isConstant())
- return false;
- switch (n->opcode()) {
- case Meta::Function: Q_FALLTHROUGH();
- case Meta::CppFrame:
- case Meta::Phi:
- case Meta::EffectPhi:
- return false;
- default:
- return true;
- }
-}
-
-bool NodeScheduler::canStartBlock(Node *node) const
-{
- switch (node->operation()->kind()) {
- case Meta::Start: Q_FALLTHROUGH();
- case Meta::IfTrue:
- case Meta::IfFalse:
- case Meta::Region:
- case Meta::HandleUnwind:
- case Meta::OnException:
- return true;
-
- default:
- return false;
- }
-}
-
-bool NodeScheduler::isControlFlowSplit(Node *node) const
-{
- int nOutputs = node->operation()->controlOutputCount();
- if (nOutputs == 2) {
- // if there is a "missing" control output, it's for exception flow without unwinder
- int controlUses = 0;
- auto uses = node->uses();
- for (auto it = uses.begin(), eit = uses.end(); it != eit; ++it) {
- if (isLive(*it) && it.isUsedAsControl())
- ++controlUses;
- }
- return controlUses == 2;
- }
- return nOutputs > 2;
-}
-
-bool NodeScheduler::isBlockTerminator(Node *node) const
-{
- switch (node->operation()->kind()) {
- case Meta::Branch: Q_FALLTHROUGH();
- case Meta::Jump:
- case Meta::Return:
- case Meta::TailCall:
- case Meta::UnwindDispatch:
- case Meta::End:
- return true;
- case Meta::Call:
- return isControlFlowSplit(node);
- default:
- return false;
- }
-}
-
-MIBlock *NodeScheduler::getCommonDominator(MIBlock *one, MIBlock *other) const
-{
- MIBlock::Index a = one->index();
- MIBlock::Index b = other->index();
-
- while (a != b) {
- if (m_dominatorDepthForBlock[a] < m_dominatorDepthForBlock[b])
- b = m_domTree->immediateDominator(b);
- else
- a = m_domTree->immediateDominator(a);
- }
-
- return m_miFunction->block(a);
-}
-
-// For Nodes that end up inside loops, it'd be great if we can move (hoist) them out of the loop.
-// To do that, we need a block that preceeds the loop. (So the block before the loop header.)
-// This function calculates that hoist block if the original block is in a loop.
-MIBlock *NodeScheduler::getHoistBlock(MIBlock *block) const
-{
- if (m_loopInfo->isLoopHeader(block))
- return m_miFunction->block(m_domTree->immediateDominator(block->index()));
-
- // make the loop header a candidate:
- MIBlock *loopHeader = m_loopInfo->loopHeaderFor(block);
- if (loopHeader == nullptr)
- return nullptr; // block is not in a loop
-
- // And now the tricky part: block has to dominate all exits from the loop. If it does not do
- // that, it meanse that there is an exit from the loop that can be reached before block. In
- // that case, hoisting from "block" to "loopHeader" would mean there now is an extra calculation
- // that is not needed for a certain loop exit.
- for (MIBlock *outEdge : m_loopInfo->loopExitsForLoop(loopHeader)) {
- if (getCommonDominator(block, outEdge) != block)
- return nullptr;
- }
-
- return m_miFunction->block(m_domTree->immediateDominator(loopHeader->index()));
-}
-
-NodeScheduler::NodeScheduler(Function *irFunction)
- : m_irFunction(irFunction)
- , m_vregs(irFunction->graph()->nodeCount(), std::numeric_limits<unsigned>::max())
- , m_live(irFunction->graph(), /*collectUses =*/ false /* do explicitly NOT collect uses! */)
-{
-}
-
-MIFunction *NodeScheduler::buildMIFunction()
-{
- m_miFunction = new MIFunction(m_irFunction);
-
- // step 1: build the CFG
- auto roots = buildCFG();
- m_miFunction->renumberBlocks();
- m_miFunction->dump(QStringLiteral("CFG after renumbering"));
-
- Q_ASSERT(m_miFunction->block(MIFunction::StartBlockIndex)->index()
- == MIFunction::StartBlockIndex);
- Q_ASSERT(m_miFunction->block(MIFunction::StartBlockIndex)->instructions().front().opcode()
- == Meta::Start);
-
- // step 2: build the dominator tree
- if (lcDotCFG().isDebugEnabled())
- dumpDotCFG();
- m_domTree.reset(new DominatorTree(m_miFunction));
- m_dominatorDepthForBlock = m_domTree->calculateNodeDepths();
-
- // step 3: find loops
- m_loopInfo.reset(new LoopInfo(*m_domTree.data()));
- m_loopInfo->detectLoops();
-
- // step 4: schedule early
- scheduleEarly(roots);
- showNodesByBlock(QStringLiteral("nodes per block after early scheduling"));
-
- // step 5: schedule late
- scheduleLate(roots);
- showNodesByBlock(QStringLiteral("nodes per block after late scheduling"));
-
- // step 6: schedule instructions in each block
- scheduleNodesInBlock();
-
- m_miFunction->dump(QStringLiteral("MI before block scheduling"));
-
- // step 7: order the basic blocks in the CFG
- BlockScheduler blockScheduler(*m_domTree.data(), *m_loopInfo.data());
- m_miFunction->setBlockOrder(blockScheduler.scheduledBlockSequence());
-
- // we're done
- m_miFunction->renumberInstructions();
- m_miFunction->setVregCount(m_nextVReg);
- m_miFunction->dump(QStringLiteral("MI after scheduling"));
- return m_miFunction;
-}
-
-static Node *splitEdge(Function *irFunction, Node *node, unsigned inputIndex)
-{
- Graph *g = irFunction->graph();
- Node *in = node->input(inputIndex);
- Node *region = g->createNode(g->opBuilder()->getRegion(1), &in, 1);
- Node *jump = g->createNode(g->opBuilder()->get<Meta::Jump>(), &region, 1);
-
- qCDebug(lcSched) << "splitting critical edge from node" << node->id()
- << "to node" << node->input(inputIndex)->id()
- << "by inserting jump node" << jump->id()
- << "and region node" << region->id();
-
- node->replaceInput(inputIndex, jump);
- return jump;
-}
-
-// See Chapter 6.3.1 of https://scholarship.rice.edu/bitstream/handle/1911/96451/TR95-252.pdf for
-// a description of the algorithm.
-std::vector<Node *> NodeScheduler::buildCFG()
-{
- std::vector<Node *> roots;
- roots.reserve(32);
- NodeWorkList todo(m_irFunction->graph());
-
- auto enqueueControlInputs = [this, &todo](Node *node) {
- for (unsigned i = 0, ei = node->operation()->controlInputCount(); i != ei; ++i) {
- const auto inputIndex = node->operation()->indexOfFirstControl() + i;
- Node *input = node->input(inputIndex);
- Q_ASSERT(input);
- if (node->operation()->kind() == Meta::Region
- && node->operation()->controlInputCount() > 1
- && isControlFlowSplit(input)) {
- // critical edge!
- input = splitEdge(m_irFunction, node, inputIndex);
- m_live.markReachable(input);
- m_live.markReachable(input->controlInput(0));
- }
- if (!isBlockTerminator(input)) {
- auto g = m_irFunction->graph();
- Node *jump = g->createNode(g->opBuilder()->get<Meta::Jump>(), &input, 1);
- node->replaceInput(inputIndex, jump);
- m_live.markReachable(jump);
- qCDebug(lcSched) << "inserting jump node" << jump->id()
- << "between node" << node->id()
- << "and node" << input->id();
- input = jump;
- }
- todo.enqueue(input);
- }
- };
-
- // create the CFG by scheduling control dependencies that start/end blocks:
- todo.enqueue(m_irFunction->graph()->endNode());
- while (Node *node = todo.dequeueNextNodeForVisiting()) {
- Q_ASSERT(isBlockTerminator(node));
-
- if (schedulerData(node)->minimumBlock)
- continue;
-
- MIBlock *b = m_miFunction->addBlock();
-
- qCDebug(lcSched) << "scheduling node" << node->id() << "as terminator for new block"
- << b->index();
- b->instructions().push_front(createMIInstruction(node));
- placeFixed(node, b, Schedule);
- roots.push_back(node);
-
- if (Node *framestate = node->frameStateInput()) {
- placeFixed(framestate, b, DontSchedule);
- qCDebug(lcSched) << ".. also scheduling framestate dependency node" << node->id()
- << "in block" << b->index();
- }
-
- if (node->opcode() == Meta::End) {
- enqueueControlInputs(node);
- continue;
- }
-
- while (true) {
- Node *controlDependency = node->controlInput(0);
- if (!controlDependency)
- break;
- if (todo.isVisited(controlDependency))
- break;
- if (schedulerData(controlDependency)->isFixed)
- break;
-
- if (controlDependency->opcode() == Meta::Start) {
- qCDebug(lcSched) << "placing start node" << controlDependency->id()
- << "in block" << b->index();
- handleStartNode(controlDependency, b);
- placeFixed(controlDependency, b, Schedule);
- roots.push_back(controlDependency);
- break; // we're done with this block
- }
- if (isBlockTerminator(controlDependency)) {
- qCDebug(lcSched) << "found terminator node" << controlDependency->id()
- << "for another block, so finish block" << b->index();
- Node *merge = m_irFunction->graph()->createNode(
- m_irFunction->graph()->opBuilder()->getRegion(1), &controlDependency, 1);
- node->replaceInput(node->operation()->indexOfFirstControl(), merge);
- addBlockStart(roots, merge, b);
- placeFixed(merge, b, Schedule);
- m_live.markReachable(merge);
- todo.enqueue(controlDependency);
- break; // we're done with this block
- }
- if (canStartBlock(controlDependency)
- || schedulerData(controlDependency->controlInput())->isFixed) {
- qCDebug(lcSched) << "found block start node" << controlDependency->id()
- << "for this block, so finish block" << b->index();
- addBlockStart(roots, controlDependency, b);
- placeFixed(controlDependency, b, Schedule);
- roots.push_back(controlDependency);
- enqueueControlInputs(controlDependency);
- break; // we're done with this block
- }
- qCDebug(lcSched) << "skipping node" << controlDependency->id();
- node = controlDependency;
- }
- }
-
- // link the edges of the MIBlocks, and add basic-block arguments:
- for (MIBlock *toBlock : m_miFunction->blocks()) {
- Q_ASSERT(!toBlock->instructions().empty());
- MIInstr &instr = toBlock->instructions().front();
- Node *toNode = instr.irNode();
- const auto opcode = toNode->operation()->kind();
- if (opcode == Meta::Region) {
- unsigned inputNr = 0;
- for (Node *input : toNode->inputs()) {
- MIBlock *fromBlock = schedulerData(input)->minimumBlock;
- fromBlock->addOutEdge(toBlock);
- toBlock->addInEdge(fromBlock);
- MIInstr &fromTerminator = fromBlock->instructions().back();
- if (fromTerminator.irNode()->opcode() == Meta::Jump ||
- fromTerminator.irNode()->opcode() == Meta::UnwindDispatch) {
- unsigned arg = 0;
- for (const MIOperand &bbArg : toBlock->arguments()) {
- fromTerminator.setOperand(arg++,
- createMIOperand(bbArg.irNode()->input(inputNr)));
- }
- }
- ++inputNr;
- }
- } else if (opcode == Meta::End) {
- for (Node *input : toNode->inputs()) {
- MIBlock *fromBlock = schedulerData(input)->minimumBlock;
- fromBlock->addOutEdge(toBlock);
- toBlock->addInEdge(fromBlock);
- }
- } else if (Node *fromNode = toNode->controlInput()) {
- MIBlock *fromBlock = schedulerData(fromNode)->minimumBlock;
- fromBlock->addOutEdge(toBlock);
- toBlock->addInEdge(fromBlock);
- }
- }
-
- m_irFunction->dump(QStringLiteral("graph after building CFG"));
-
- auto startBlock = schedulerData(m_irFunction->graph()->startNode())->minimumBlock;
- m_miFunction->setStartBlock(startBlock);
-
- if (lcSched().isDebugEnabled())
- m_miFunction->dump(QStringLiteral("control flow graph before renumbering"));
- m_miFunction->verifyCFG();
-
- return roots;
-}
-
-// See Chapter 6.3.3 of https://scholarship.rice.edu/bitstream/handle/1911/96451/TR95-252.pdf for
-// a description of the algorithm.
-void NodeScheduler::scheduleEarly(const std::vector<Node *> &roots)
-{
- // scheduling one node might have the effect of queueing its dependencies
- NodeWorkList todo(m_irFunction->graph());
- for (Node *root : roots) {
- todo.enqueue(root);
- while (Node *node = todo.dequeueNextNodeForVisiting())
- scheduleEarly(node, todo);
- }
-}
-
-void NodeScheduler::scheduleEarly(Node *node, NodeWorkList &todo)
-{
- qCDebug(lcSched) << "Scheduling node" << node->id() << "early...";
-
- SchedulerData *sd = schedulerData(node);
-
- if (sd->isFixed) {
- // Fixed nodes already know their schedule early position.
- qCDebug(lcSched) << ".. Fixed node" << node->id() << "is on minimum block"
- << sd->minimumBlock->index()
- << "which has dominator depth"
- << m_dominatorDepthForBlock[sd->minimumBlock->index()];
- }
-
- for (Node *use : node->uses()) {
- if (isLive(use))
- propagateMinimumPosition(sd->minimumBlock, use, todo);
- else
- qCDebug(lcSched) << ".. Skipping node" << use->id() << "as it's not live";
- }
-}
-
-void NodeScheduler::propagateMinimumPosition(MIBlock *newMinimumPosition, Node *toNode,
- NodeWorkList &todo)
-{
- Q_ASSERT(newMinimumPosition);
-
- SchedulerData *sd = schedulerData(toNode);
- if (sd->isFixed) // nothing to do
- return;
-
- MIBlock::Index minimumBlockIndex = sd->minimumBlock
- ? sd->minimumBlock->index()
- : MIFunction::StartBlockIndex;
- Q_ASSERT(m_domTree->insideSameDominatorChain(newMinimumPosition->index(), minimumBlockIndex));
- if (sd->minimumBlock == nullptr
- || m_dominatorDepthForBlock[newMinimumPosition->index()]
- > m_dominatorDepthForBlock[minimumBlockIndex]) {
- // ok, some input for toNode is scheduled *after* our current minimum depth, so we need
- // to adjust out minimal position. (This might involve rescheduling toNode's uses.)
- place(toNode, newMinimumPosition);
- todo.reEnqueue(toNode);
- qCDebug(lcSched) << ".. Propagating minimum block" << sd->minimumBlock->index()
- << "which has dominator depth"
- << m_dominatorDepthForBlock[newMinimumPosition->index()]
- << "to use node" << toNode->id();
- } else {
- qCDebug(lcSched) << ".. Minimum position" << newMinimumPosition->index()
- << "is not better than" << minimumBlockIndex
- << "for node" << toNode->id();
- }
-}
-
-// See Chapter 6.3.4 of https://scholarship.rice.edu/bitstream/handle/1911/96451/TR95-252.pdf for
-// a description of the algorithm.
-//
-// There is one extra detail not described in the thesis mentioned above: loop hoisting. Before we
-// place a node in the latest block that dominates all uses, we check if we accidentally sink it
-// *into* a loop (meaning the latest block is inside a loop, where it is not if the earliest
-// possible block would be chosen). If we detect that a nodes is going to sink into a loop, we walk
-// the dominator path from the latest block up to the earliest block, and pick the first block that
-// is in the same loop (if any) as the earlieast block.
-//
-// As noted in the thesis, this strategy might enlongen life times, which could be harmful for
-// values that are simple to re-materialized or re-calculate.
-void NodeScheduler::scheduleLate(const std::vector<Node *> &roots)
-{
- NodeWorkList todo(m_irFunction->graph());
- for (Node *root : roots)
- todo.enqueue(root);
-
- while (Node *node = todo.dequeueNextNodeForVisiting())
- scheduleNodeLate(node, todo);
-}
-
-void NodeScheduler::scheduleNodeLate(Node *node, NodeWorkList &todo)
-{
- if (!needsScheduling(node))
- return;
- qCDebug(lcSched) << "Scheduling node" << node->id() << "late...";
-
- auto sd = schedulerData(node);
- if (sd->unscheduledUses == SchedulerData::NotYetCalculated) {
- sd->unscheduledUses = 0;
- for (Node *use : node->uses()) {
- if (!isLive(use))
- continue;
- if (!needsScheduling(use))
- continue;
- if (schedulerData(use)->isFixed)
- continue;
- todo.enqueue(use);
- ++sd->unscheduledUses;
- }
- }
-
- if (sd->isFixed) {
- qCDebug(lcSched) << ".. it's fixed";
- enqueueInputs(node, todo);
- return;
- }
-
- if (sd->unscheduledUses) {
- qCDebug(lcSched).noquote() << ".. not all uses are fixed, postpone it."<< todo.status(node);
- return;
- }
-
- MIBlock *&minBlock = sd->minimumBlock;
- if (minBlock == nullptr)
- minBlock = m_miFunction->block(MIFunction::StartBlockIndex);
- MIBlock *commonUseDominator = commonDominatorOfUses(node);
- qCDebug(lcSched) << ".. common use dominator: block" << commonUseDominator->index();
-
- // the minBlock has to dominate the uses, *and* the common dominator of the uses.
- Q_ASSERT(minBlock->index() == commonUseDominator->index() ||
- m_domTree->dominates(minBlock->index(), commonUseDominator->index()));
-
- // we now found the deepest block, so use it as the target block:
- MIBlock *targetBlock = commonUseDominator;
-
- if (node->opcode() == Meta::FrameState) {
- // never hoist framestates: they're used (among other things) to keep their inputs alive, so
- // hoisting them out would end the life-time of those inputs prematurely
- } else {
- // but we want to prevent blocks sinking into loops unnecessary
- MIBlock *hoistBlock = getHoistBlock(targetBlock);
- while (hoistBlock
- && m_dominatorDepthForBlock[hoistBlock->index()]
- >= m_dominatorDepthForBlock[minBlock->index()]) {
- qCDebug(lcSched) << ".. hoisting node" << node->id() << "from block"
- << targetBlock->index() << "to block" << hoistBlock->index();
- // ok, so there a) is a hoist block and b) it's deeper than the minimum block,
- // so lift it up one level ...
- targetBlock = hoistBlock;
- // ... and see if we can lift it one more level
- hoistBlock = getHoistBlock(targetBlock);
- }
- }
-
- qCDebug(lcSched) << ".. fixating it in block" << targetBlock->index()
- << "where the minimum block was" << minBlock->index();
-
- placeFixed(node, targetBlock, DontSchedule);
- enqueueInputs(node, todo);
-}
-
-void NodeScheduler::enqueueInputs(Node *node, NodeWorkList &todo)
-{
- for (Node *input : node->inputs()) {
- if (!input)
- continue;
- if (!needsScheduling(input))
- continue;
- if (!isLive(input))
- continue;
- auto sd = schedulerData(input);
- if (sd->isFixed)
- continue;
- qCDebug(lcSched).noquote() << "... enqueueing input node" << input->id()
- << todo.status(input);
- if (sd->unscheduledUses != SchedulerData::NotYetCalculated) {
- if (sd->unscheduledUses > 0)
- --sd->unscheduledUses;
- if (sd->unscheduledUses == 0)
- todo.reEnqueue(input);
- } else {
- todo.reEnqueue(input);
- }
- }
-}
-
-Node *NodeScheduler::firstNotFixedUse(Node *node)
-{
- for (Node *use : node->uses()) {
- if (!isLive(use))
- continue;
- if (!schedulerData(use)->isFixed)
- return use;
- }
- return nullptr;
-}
-
-MIBlock *NodeScheduler::commonDominatorOfUses(Node *node)
-{
- MIBlock *commonDominator = nullptr;
- for (auto useIt = node->uses().begin(), useEIt = node->uses().end(); useIt != useEIt; ++useIt) {
- Node *use = *useIt;
- if (!isLive(use))
- continue;
- // region nodes use other nodes through their control dependency. But those nodes should
- // already have been placed as block terminators before.
- Q_ASSERT(use->opcode() != Meta::Region);
- if (use->opcode() == Meta::Phi || use->opcode() == Meta::EffectPhi) {
- // find the predecessor block defining this input
- Node *region = use->controlInput(0);
- Node *input = region->controlInput(useIt.inputIndex());
- use = input;
- }
- auto minBlock = schedulerData(use)->minimumBlock;
- if (commonDominator == nullptr)
- commonDominator = minBlock;
- else
- commonDominator = getCommonDominator(commonDominator, minBlock);
- }
- return commonDominator;
-}
-
-void NodeScheduler::scheduleNodesInBlock()
-{
- auto startBlock = m_miFunction->block(MIFunction::StartBlockIndex);
- for (Node *n : m_live.reachable()) {
- auto sd = schedulerData(n);
- if (!sd->minimumBlock)
- sd->minimumBlock = startBlock;
- }
-
- std::vector<std::vector<SchedulerData *>> nodesForBlock;
- nodesForBlock.resize(m_miFunction->blockCount());
-
- for (auto sd : m_schedulerData) {
- if (sd == nullptr)
- continue;
- if (!isLive(sd->node))
- continue;
- sd->unscheduledUses = 0;
- for (Node *use : sd->node->uses()) {
- if (!needsScheduling(use))
- continue;
- if (schedulerData(use)->isScheduledInBlock)
- continue;
- if (schedulerData(use)->minimumBlock == sd->minimumBlock)
- ++sd->unscheduledUses;
- }
- if (sd->unscheduledUses == 0)
- nodesForBlock[sd->minimumBlock->index()].push_back(sd);
- }
-
- NodeWorkList todo(m_irFunction->graph());
- for (MIBlock *b : m_miFunction->blocks()) {
- qCDebug(lcSched) << "Scheduling inside block" << b->index();
- MIInstr *insertionPoint = &b->instructions().back();
- todo.enqueue(insertionPoint->irNode());
- scheduleNodesInBlock(insertionPoint, b, todo);
- Q_ASSERT(todo.isEmpty());
- for (auto sd : nodesForBlock[b->index()]) {
- if (!sd->isScheduledInBlock)
- todo.enqueue(sd->node);
- }
- scheduleNodesInBlock(insertionPoint, b, todo);
- Q_ASSERT(todo.isEmpty());
- todo.reset();
- }
-}
-
-void NodeScheduler::scheduleNodesInBlock(MIInstr *&insertionPoint, MIBlock *b, NodeWorkList &todo)
-{
- while (Node *n = todo.dequeueNextNodeForVisiting())
- scheduleNodeInBlock(n, insertionPoint, b, todo);
-}
-
-void NodeScheduler::scheduleNodeInBlock(Node *node, MIInstr *&insertionPoint, MIBlock *b,
- NodeWorkList &todo)
-{
- Q_ASSERT(!node->isDead());
-
- if (!isLive(node))
- return;
-
- if (!needsScheduling(node))
- return;
-
- auto nodeData = schedulerData(node);
- if (nodeData->minimumBlock != b)
- return;
-
- const bool wasAlreadyScheduled = nodeData->isScheduledInBlock;
- if (!wasAlreadyScheduled) {
- if (nodeData->unscheduledUses)
- return;
-
- scheduleNodeNow(node, insertionPoint);
- }
-
- if (Node *framestate = node->frameStateInput())
- scheduleNodeInBlock(framestate, insertionPoint, b, todo);
-
- for (Node *input : node->inputs()) {
- if (!input)
- continue;
- if (!needsScheduling(input))
- continue;
- if (!isLive(input))
- continue;
- auto inputInfo = schedulerData(input);
- if (inputInfo->isScheduledInBlock)
- continue;
- Q_ASSERT(inputInfo->minimumBlock != nullptr);
- if (inputInfo->minimumBlock != b)
- continue;
- Q_ASSERT(!input->isDead());
- Q_ASSERT(inputInfo->unscheduledUses != SchedulerData::NotYetCalculated);
- if (!wasAlreadyScheduled && inputInfo->unscheduledUses > 0)
- --inputInfo->unscheduledUses;
- if (inputInfo->unscheduledUses == 0)
- todo.enqueue(input);
- }
-}
-
-void NodeScheduler::scheduleNodeNow(Node *node, MIInstr *&insertionPoint)
-{
- qCDebug(lcSched) << ".. scheduling node" << node->id()
- << "in block" << insertionPoint->parent()->index()
- << "before node" << insertionPoint->irNode()->id();
-
- MIInstr *newInstr = createMIInstruction(node);
- newInstr->insertBefore(insertionPoint);
- insertionPoint = newInstr;
-}
-
-void NodeScheduler::place(Node *node, MIBlock *b)
-{
- Q_ASSERT(!node->isDead());
-
- if (b == nullptr)
- return;
-
- schedulerData(node)->minimumBlock = b;
-}
-
-void NodeScheduler::placeFixed(Node *node, MIBlock *b, ScheduleOrNot markScheduled)
-{
- place(node, b);
- auto sd = schedulerData(node);
- Q_ASSERT(!sd->isFixed);
- sd->isFixed = true;
- sd->isScheduledInBlock = markScheduled == Schedule;
-}
-
-unsigned NodeScheduler::vregForNode(Node *node)
-{
- unsigned &vreg = m_vregs[unsigned(node->id())];
- if (vreg == std::numeric_limits<unsigned>::max())
- vreg = m_nextVReg++;
- return vreg;
-}
-
-void NodeScheduler::addBlockStart(std::vector<Node *> &roots, Node *startNode, MIBlock *block)
-{
- block->instructions().insert(block->instructions().begin(), createMIInstruction(startNode));
- if (startNode->opcode() == Meta::Region) {
- for (Node *use : startNode->uses()) {
- if (use->opcode() == Meta::Phi && isLive(use)) {
- block->addArgument(MIOperand::createVirtualRegister(use, vregForNode(use)));
- placeFixed(use, block, Schedule);
- roots.push_back(use);
- } else if (use->opcode() == Meta::EffectPhi && isLive(use)) {
- placeFixed(use, block, Schedule);
- roots.push_back(use);
- }
- }
- }
-}
-
-void NodeScheduler::handleStartNode(Node *startNode, MIBlock *startBlock)
-{
- startBlock->instructions().push_front(createMIInstruction(startNode));
-
- QVarLengthArray<Node *, 32> args;
- for (Node *use : startNode->uses()) {
- switch (use->opcode()) {
- case Meta::Engine: Q_FALLTHROUGH();
- case Meta::CppFrame:
- case Meta::Function:
- placeFixed(use, startBlock, Schedule);
- break;
- case Meta::Parameter: {
- auto param = ParameterPayload::get(*use->operation());
- int idx = int(param->parameterIndex());
- if (args.size() <= idx)
- args.resize(idx + 1);
- args[int(idx)] = use;
- placeFixed(use, startBlock, Schedule);
- }
- break;
- default:
- break;
- }
- }
-
- for (unsigned i = 0, ei = unsigned(args.size()); i != ei; ++i) {
- if (Node *arg = args.at(int(i)))
- startBlock->addArgument(MIOperand::createJSStackSlot(arg, i));
- }
-}
-
-static Node *firstControlOutput(Node *n)
-{
- for (auto it = n->uses().begin(), eit = n->uses().end(); it != eit; ++it) {
- if (it.isUsedAsControl())
- return *it;
- }
- return nullptr;
-}
-
-MIInstr *NodeScheduler::createMIInstruction(Node *node)
-{
- const auto opcode = node->operation()->kind();
-
- unsigned nArgs = 0;
- switch (opcode) {
- case Meta::UnwindDispatch: Q_FALLTHROUGH();
- case Meta::Jump: {
- Node *target = firstControlOutput(node);
- if (target->opcode() == Meta::Region) {
- for (Node *n : target->uses()) {
- if (n->opcode() == Meta::Phi && isLive(n))
- ++nArgs;
- }
- }
- }
- break;
- case Meta::Branch:
- nArgs = 1;
- break;
- case Meta::Return:
- nArgs = 1;
- break;
- default:
- nArgs = node->operation()->valueInputCount();
- break;
- }
-
- MIInstr *instr = MIInstr::create(m_irFunction->pool(), node, nArgs);
- for (unsigned i = 0, ei = node->operation()->valueInputCount(); i != ei; ++i)
- instr->setOperand(i, createMIOperand(node->input(i)));
- if (node->opcode() != Meta::Start && node->operation()->valueOutputCount() > 0)
- instr->setDestination(createMIOperand(node));
-
- schedulerData(node)->isScheduledInBlock = true;
- return instr;
-}
-
-MIOperand NodeScheduler::createMIOperand(Node *node)
-{
- if (node->operation()->isConstant())
- return MIOperand::createConstant(node);
-
- auto opcode = node->operation()->kind();
- switch (opcode) {
- case Meta::Parameter:
- return MIOperand::createJSStackSlot(
- node, unsigned(ParameterPayload::get(*node->operation())->parameterIndex()));
- case Meta::Engine:
- return MIOperand::createEngineRegister(node);
- case Meta::CppFrame:
- return MIOperand::createCppFrameRegister(node);
- case Meta::Function:
- return MIOperand::createFunction(node);
- default:
- if ((node->opcode() == Meta::Call
- && CallPayload::get(*node->operation())->callee() == Meta::JSThisToObject)
- || node->opcode() == Meta::StoreThis) {
- return MIOperand::createJSStackSlot(node, CallData::This);
- } else {
- return MIOperand::createVirtualRegister(node, vregForNode(node));
- }
- }
-}
-
-void NodeScheduler::showNodesByBlock(const QString &description) const
-{
- if (!lcSched().isDebugEnabled())
- return;
-
- qCDebug(lcSched) << description;
-
- for (MIBlock *b : m_miFunction->blocks()) {
- QString s;
- for (const SchedulerData *sd : m_schedulerData) {
- if (!sd)
- continue;
- if (!isLive(sd->node))
- continue;
- if (sd->minimumBlock == b) {
- if (!s.isEmpty())
- s += QStringLiteral(", ");
- s += QStringLiteral("%1 (%2)").arg(QString::number(sd->node->id()),
- sd->node->operation()->debugString());
- }
- }
- if (s.isEmpty())
- s = QStringLiteral("<<none>>");
- qCDebug(lcSched, "Nodes in block %u: %s", b->index(), s.toUtf8().constData());
- }
-}
-
-void NodeScheduler::dumpDotCFG() const
-{
- QString out;
- out += QLatin1Char('\n');
- out += QStringLiteral("digraph{root=\"L%1\" label=\"Control Flow Graph\";"
- "node[shape=circle];edge[dir=forward fontsize=10]\n")
- .arg(MIFunction::StartBlockIndex);
- for (MIBlock *src : m_miFunction->blocks()) {
- for (MIBlock *dst : src->outEdges()) {
- out += QStringLiteral("L%1->L%2\n").arg(QString::number(src->index()),
- QString::number(dst->index()));
- }
- }
- out += QStringLiteral("}\n");
- qCDebug(lcDotCFG).nospace().noquote() << out;
-}
-
-} // IR namespace
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jit/qv4schedulers_p.h b/src/qml/jit/qv4schedulers_p.h
deleted file mode 100644
index f9179816df..0000000000
--- a/src/qml/jit/qv4schedulers_p.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4SCHEDULER_P_H
-#define QV4SCHEDULER_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 "qv4global_p.h"
-#include "qv4mi_p.h"
-#include "qv4node_p.h"
-#include "qv4domtree_p.h"
-#include "qv4loopinfo_p.h"
-
-QT_REQUIRE_CONFIG(qml_tracing);
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-namespace IR {
-
-// Node scheduling "flattens" the graph into basic blocks with an ordered list of instructions.
-//
-// The various steps are mentioned in buildMIFunction, but the general idea is described in
-// https://scholarship.rice.edu/bitstream/handle/1911/96451/TR95-252.pdf in chapter 6.
-class NodeScheduler final
-{
- Q_DISABLE_COPY_MOVE(NodeScheduler)
-
- class SchedulerData final {
- Q_DISABLE_COPY_MOVE(SchedulerData)
- public:
- static SchedulerData *create(QQmlJS::MemoryPool *pool)
- { return pool->New<SchedulerData>(); }
-
- SchedulerData() = default;
- ~SchedulerData() = default;
-
- Node *node = nullptr;
- MIBlock *minimumBlock = nullptr;
- bool isFixed = false;
- bool isScheduledInBlock = false;
- static constexpr unsigned NotYetCalculated = std::numeric_limits<unsigned>::max();
- unsigned unscheduledUses = NotYetCalculated;
- };
-
-public:
- NodeScheduler(Function *irFunction);
- ~NodeScheduler() = default;
-
- MIFunction *buildMIFunction();
-
-private:
- std::vector<Node *> buildCFG();
- void scheduleEarly(const std::vector<Node *> &roots);
- void scheduleEarly(Node *node, NodeWorkList &todo);
- void propagateMinimumPosition(MIBlock *newMinimumPosition, Node *toNode, NodeWorkList &todo);
- void scheduleLate(const std::vector<Node *> &roots);
- void scheduleNodeLate(Node *node, NodeWorkList &todo);
- void enqueueInputs(Node *node, NodeWorkList &todo);
- Node *firstNotFixedUse(Node *node);
- MIBlock *commonDominatorOfUses(Node *node);
- void scheduleNodesInBlock();
- void scheduleNodesInBlock(MIInstr *&insertionPoint, MIBlock *b, NodeWorkList &todo);
- void scheduleNodeInBlock(Node *node, MIInstr *&insertionPoint, MIBlock *b, NodeWorkList &todo);
- void scheduleNodeNow(Node *node, MIInstr *&insertionPoint);
-
- void place(Node *node, MIBlock *b);
- enum ScheduleOrNot { DontSchedule, Schedule };
- void placeFixed(Node *node, MIBlock *b, ScheduleOrNot markScheduled);
- unsigned vregForNode(Node *node);
- void addBlockStart(std::vector<Node *> &roots, Node *startNode, MIBlock *block);
- void enqueueControlInputs(Node *node);
- void handleStartNode(Node *startNode, MIBlock *startBlock);
- MIInstr *createMIInstruction(Node *node);
- MIOperand createMIOperand(Node *node);
- SchedulerData *schedulerData(Node *n)
- {
- if (Q_UNLIKELY(m_schedulerData.size() <= n->id()))
- m_schedulerData.resize(n->id() + 8);
- SchedulerData *&sd = m_schedulerData[n->id()];
- if (Q_UNLIKELY(sd == nullptr)) {
- sd = SchedulerData::create(m_irFunction->pool());
- sd->node = n;
- }
- return sd;
- }
- bool isLive(Node *n) const
- { return m_live.isReachable(n->id()); }
- bool canStartBlock(Node *node) const;
- bool isControlFlowSplit(Node *node) const;
- bool isBlockTerminator(Node *node) const;
- MIBlock *getCommonDominator(MIBlock *one, MIBlock *other) const;
- MIBlock *getHoistBlock(MIBlock *block) const;
-
- void showNodesByBlock(const QString &description) const;
-
- void dumpDotCFG() const;
-
-private:
- Function *m_irFunction = nullptr;
- MIFunction *m_miFunction = nullptr;
- QScopedPointer<LoopInfo> m_loopInfo;
- QScopedPointer<DominatorTree> m_domTree;
- std::vector<int> m_dominatorDepthForBlock;
- std::vector<unsigned> m_vregs;
- std::vector<SchedulerData *> m_schedulerData;
- NodeCollector m_live;
- unsigned m_nextVReg = 0;
-};
-
-} // namespace IR
-} // namespace QV4
-
-QT_END_NAMESPACE
-
-#endif // QV4SCHEDULER_P_H
diff --git a/src/qml/jit/qv4tracingjit.cpp b/src/qml/jit/qv4tracingjit.cpp
deleted file mode 100644
index c8974b3a1b..0000000000
--- a/src/qml/jit/qv4tracingjit.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore/qloggingcategory.h>
-
-#include "qv4vme_moth_p.h"
-#include "qv4graphbuilder_p.h"
-#include "qv4lowering_p.h"
-#include "qv4mi_p.h"
-#include "qv4schedulers_p.h"
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcTracing, "qt.v4.tracing")
-
-namespace QV4 {
-
-// This is the entry point for the "tracing JIT". It uses the sea-of-nodes concept as described in
-// https://scholarship.rice.edu/bitstream/handle/1911/96451/TR95-252.pdf
-//
-// The minimal pipeline is as follows:
-// - create the graph for the function
-// - do generic lowering
-// - schedule the nodes
-// - run minimal stack slot allocation (no re-use of slots)
-// - run the assembler
-//
-// This pipeline has no optimizations, and generates quite inefficient code. It does have the
-// advantage that no trace information is used, so it can be used for testing where it replaces
-// the baseline JIT. Any optimizations are additions to this pipeline.
-//
-// Note: generators (or resuming functions in general) are not supported by this JIT.
-void Moth::runTracingJit(QV4::Function *function)
-{
- IR::Function irFunction(function);
- qCDebug(lcTracing).noquote() << "runTracingJit called for" << irFunction.name() << "...";
-
- qCDebug(lcTracing).noquote().nospace() << function->traceInfoToString();
-
- IR::GraphBuilder::buildGraph(&irFunction);
- irFunction.dump(QStringLiteral("initial IR"));
- irFunction.verify();
-
- IR::GenericLowering(irFunction).lower();
- irFunction.dump(QStringLiteral("after generic lowering"));
- irFunction.verify();
-
- IR::NodeScheduler scheduler(&irFunction);
- QScopedPointer<IR::MIFunction> miFunction(scheduler.buildMIFunction());
- miFunction->dump(QStringLiteral("initial MI"));
- irFunction.verify();
-}
-
-} // QV4 namespace
-QT_END_NAMESPACE
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index aab72f8b2d..45ea79d31a 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -470,6 +470,33 @@ void QJSEngine::installExtensions(QJSEngine::Extensions extensions, const QJSVal
QV4::GlobalExtensions::init(obj, extensions);
}
+/*!
+ \since 5.14
+ Interrupts or re-enables JavaScript execution.
+
+ If \a interrupted is \c true, any JavaScript executed by this engine
+ immediately aborts and returns an error object until this function is
+ called again with a value of \c false for \a interrupted.
+
+ This function is thread safe. You may call it from a different thread
+ in order to interrupt, for example, an infinite loop in JavaScript.
+*/
+void QJSEngine::setInterrupted(bool interrupted)
+{
+ m_v4Engine->isInterrupted = interrupted;
+}
+
+/*!
+ \since 5.14
+ Returns whether JavaScript execution is currently interrupted.
+
+ \sa setInterrupted()
+*/
+bool QJSEngine::isInterrupted() const
+{
+ return m_v4Engine->isInterrupted;
+}
+
static QUrl urlForFileName(const QString &fileName)
{
if (!fileName.startsWith(QLatin1Char(':')))
@@ -527,6 +554,8 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in
result = script.run();
if (scope.engine->hasException)
result = v4->catchException();
+ if (v4->isInterrupted)
+ result = v4->newErrorObject(QStringLiteral("Interrupted"));
QJSValue retval(v4, result->asReturnedValue());
@@ -565,7 +594,12 @@ QJSValue QJSEngine::importModule(const QString &fileName)
if (m_v4Engine->hasException)
return QJSValue(m_v4Engine, m_v4Engine->catchException());
moduleUnit->evaluate();
- return QJSValue(m_v4Engine, moduleNamespace->asReturnedValue());
+ if (!m_v4Engine->isInterrupted)
+ return QJSValue(m_v4Engine, moduleNamespace->asReturnedValue());
+
+ return QJSValue(
+ m_v4Engine,
+ m_v4Engine->newErrorObject(QStringLiteral("Interrupted"))->asReturnedValue());
}
/*!
diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h
index 6300842341..31a4d68baa 100644
--- a/src/qml/jsapi/qjsengine.h
+++ b/src/qml/jsapi/qjsengine.h
@@ -113,6 +113,9 @@ public:
void installExtensions(Extensions extensions, const QJSValue &object = QJSValue());
+ void setInterrupted(bool interrupted);
+ bool isInterrupted() const;
+
QV4::ExecutionEngine *handle() const { return m_v4Engine; }
void throwError(const QString &message);
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index e0bd986920..92eaf1d8ee 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -769,6 +769,8 @@ QJSValue QJSValue::call(const QJSValueList &args)
ScopedValue result(scope, f->call(jsCallData));
if (engine->hasException)
result = engine->catchException();
+ if (engine->isInterrupted)
+ result = engine->newErrorObject(QStringLiteral("Interrupted"));
return QJSValue(engine, result->asReturnedValue());
}
@@ -825,6 +827,8 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
ScopedValue result(scope, f->call(jsCallData));
if (engine->hasException)
result = engine->catchException();
+ if (engine->isInterrupted)
+ result = engine->newErrorObject(QStringLiteral("Interrupted"));
return QJSValue(engine, result->asReturnedValue());
}
@@ -873,6 +877,8 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
ScopedValue result(scope, f->callAsConstructor(jsCallData));
if (engine->hasException)
result = engine->catchException();
+ if (engine->isInterrupted)
+ result = engine->newErrorObject(QStringLiteral("Interrupted"));
return QJSValue(engine, result->asReturnedValue());
}
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index 5b9934282c..a87eb92caf 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -96,7 +96,7 @@ struct DateObject: Object {
double date() const { return d()->date; }
void setDate(double date) { d()->date = date; }
- QDateTime toQDateTime() const;
+ Q_QML_PRIVATE_EXPORT QDateTime toQDateTime() const;
};
template<>
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 18927c637c..e10bf3cf79 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -138,8 +138,6 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcTracingAll, "qt.v4.tracing.all")
-
using namespace QV4;
#ifndef V4_BOOTSTRAP
@@ -165,7 +163,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
, m_engineId(engineSerial.fetchAndAddOrdered(1))
, regExpCache(nullptr)
, m_multiplyWrappedQObjects(nullptr)
-#if defined(V4_ENABLE_JIT) && !defined(V4_BOOTSTRAP)
+#if QT_CONFIG(qml_jit)
, m_canAllocateExecutableMemory(OSAllocator::canAllocateExecutableMemory())
#endif
{
@@ -175,7 +173,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
bool ok = false;
maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
if (!ok || maxCallDepth <= 0) {
-#ifdef QT_NO_DEBUG
+#if defined(QT_NO_DEBUG) && !defined(__SANITIZE_ADDRESS__) && !QT_HAS_FEATURE(address_sanitizer)
maxCallDepth = 1234;
#else
// no (tail call) optimization is done, so there'll be a lot mare stack frames active
@@ -658,13 +656,6 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
ExecutionEngine::~ExecutionEngine()
{
- if (Q_UNLIKELY(lcTracingAll().isDebugEnabled())) {
- for (auto cu : compilationUnits) {
- for (auto f : qAsConst(cu->runtimeFunctions))
- qCDebug(lcTracingAll).noquote().nospace() << f->traceInfoToString();
- }
- }
-
modules.clear();
delete m_multiplyWrappedQObjects;
m_multiplyWrappedQObjects = nullptr;
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 6df4545014..d0c58eee8f 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -464,7 +464,7 @@ public:
// but any time a QObject is wrapped a second time in another engine, we have to do
// bookkeeping.
MultiplyWrappedQObjectMap *m_multiplyWrappedQObjects;
-#if defined(V4_ENABLE_JIT) && !defined(V4_BOOTSTRAP)
+#if QT_CONFIG(qml_jit)
const bool m_canAllocateExecutableMemory;
#endif
@@ -595,7 +595,7 @@ public:
bool canJIT(Function *f = nullptr)
{
-#if defined(V4_ENABLE_JIT) && !defined(V4_BOOTSTRAP)
+#if QT_CONFIG(qml_jit)
if (!m_canAllocateExecutableMemory)
return false;
if (f)
diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h
index b5cfea8863..82eccd9f3c 100644
--- a/src/qml/jsruntime/qv4enginebase_p.h
+++ b/src/qml/jsruntime/qv4enginebase_p.h
@@ -69,9 +69,23 @@ struct Q_QML_EXPORT EngineBase {
CppStackFrame *currentStackFrame = nullptr;
Value *jsStackTop = nullptr;
+
+ // The JIT expects hasException and isInterrupted to be in the same 32bit word in memory.
quint8 hasException = false;
- quint8 writeBarrierActive = false;
+ // isInterrupted is expected to be set from a different thread
+#if defined(Q_ATOMIC_INT8_IS_SUPPORTED)
+ QAtomicInteger<quint8> isInterrupted = false;
quint16 unused = 0;
+#elif defined(Q_ATOMIC_INT16_IS_SUPPORTED)
+ quint8 unused = 0;
+ QAtomicInteger<quint16> isInterrupted = false;
+#elif defined(V4_BOOTSTRAP)
+ // We don't need the isInterrupted flag when bootstrapping.
+ quint8 unused[3];
+#else
+# error V4 needs either 8bit or 16bit atomics.
+#endif
+
quint8 isExecutingInRegExpJIT = false;
quint8 padding[3];
MemoryManager *memoryManager = nullptr;
@@ -137,6 +151,10 @@ Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsSta
Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + 8);
Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE);
+#ifndef V4_BOOTSTRAP
+Q_STATIC_ASSERT(offsetof(EngineBase, isInterrupted) + sizeof(EngineBase::isInterrupted) <= offsetof(EngineBase, hasException) + 4);
+#endif
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 1bd4329fe8..debdf23d27 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -75,19 +75,12 @@ ReturnedValue Function::call(const Value *thisObject, const Value *argv, int arg
Function *Function::create(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function)
{
- quint16 traceSlotCount = 0;
-#if QT_CONFIG(qml_tracing)
- traceSlotCount = function->nTraceInfos == CompiledData::Function::NoTracing()
- ? 1
- : function->nTraceInfos;
-#endif
- quint8 *storage = new quint8[sizeof(Function) + traceSlotCount];
- return new(storage) Function(engine, unit, function);
+ return new Function(engine, unit, function);
}
void Function::destroy()
{
- delete[] reinterpret_cast<quint8 *>(this);
+ delete this;
}
Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function)
@@ -111,13 +104,6 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
internalClass = ic->d();
nFormals = compiledFunction->nFormals;
-
-#if QT_CONFIG(qml_tracing)
- if (tracingEnabled()) {
- for (uint i = 0; i < function->nTraceInfos; ++i)
- *traceInfo(i) = 0;
- }
-#endif
}
Function::~Function()
@@ -188,22 +174,4 @@ QQmlSourceLocation Function::sourceLocation() const
return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column);
}
-QString Function::traceInfoToString()
-{
- QString info = QLatin1String("=== Trace information for ") + name()->toQString() + QLatin1Char(':');
- if (!tracingEnabled())
- return info + QStringLiteral(" disabled. Interpreter call count: %1\n").arg(interpreterCallCount);
- if (compiledFunction->nTraceInfos == 0)
- return info + QLatin1String(" none.\n");
-
- info += QLatin1Char('\n');
- for (uint i = 0, ei = compiledFunction->nTraceInfos; i < ei; ++i) {
- auto bits = QString::number(*traceInfo(i), 2);
- if (bits.size() < 8)
- bits.prepend(QString(8 - bits.size(), '0'));
- info += QStringLiteral(" %1: %2\n").arg(QString::number(i), bits);
- }
- return info;
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index f8125a58f8..01b212370d 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -123,31 +123,6 @@ public:
return nullptr;
return compilationUnit->runtimeFunctions[compiledFunction->nestedFunctionIndex];
}
-
- Q_NEVER_INLINE QString traceInfoToString();
-
- quint8 *traceInfo(uint i)
- {
-#if QT_CONFIG(qml_tracing)
- Q_ASSERT((tracingEnabled() && i < traceInfoCount()) || (i == 0));
- return reinterpret_cast<quint8 *>(this) + sizeof(Function) + i;
-#else
- Q_UNUSED(i);
- return nullptr;
-#endif
- }
-
- quint32 traceInfoCount() const
- { return compiledFunction->nTraceInfos; }
-
- bool tracingEnabled() const
- {
-#if QT_CONFIG(qml_tracing)
- return traceInfoCount() != CompiledData::Function::NoTracing();
-#else
- return false;
-#endif
- }
};
}
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index e03d49c74d..4fee26f341 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -87,11 +87,11 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) {
}
Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name, VTable::Call call);
- void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr);
- void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
- void init(QV4::ExecutionContext *scope, const QString &name);
- void init();
- void destroy();
+ Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr);
+ Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
+ Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, const QString &name);
+ Q_QML_PRIVATE_EXPORT void init();
+ Q_QML_PRIVATE_EXPORT void destroy();
void setFunction(Function *f);
@@ -260,7 +260,7 @@ struct FunctionPrototype: FunctionObject
static ReturnedValue method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
-struct IndexedBuiltinFunction : FunctionObject
+struct Q_QML_PRIVATE_EXPORT IndexedBuiltinFunction : FunctionObject
{
V4_OBJECT2(IndexedBuiltinFunction, FunctionObject)
};
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index d47393b3bb..42b6edb6e2 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -82,53 +82,9 @@ inline bool isfinite(double d) { return _finite(d); }
inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
#endif
-// Decide whether to enable or disable the JIT
-
-// White list architectures
-//
-// NOTE: This should match the logic in qv4targetplatform_p.h!
-
-#if defined(Q_PROCESSOR_X86_32) && (QT_POINTER_SIZE == 4) \
- && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD))
-# define V4_ENABLE_JIT
-#elif defined(Q_PROCESSOR_X86_64) && (QT_POINTER_SIZE == 8) \
- && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD))
-# define V4_ENABLE_JIT
-#elif defined(Q_PROCESSOR_ARM_32) && (QT_POINTER_SIZE == 4) \
- && (defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD) || defined(Q_OS_INTEGRITY))
-# if defined(thumb2) || defined(__thumb2__) || ((defined(__thumb) || defined(__thumb__)) && __TARGET_ARCH_THUMB-0 == 4)
-# define V4_ENABLE_JIT
-# elif defined(__ARM_ARCH_ISA_THUMB) && __ARM_ARCH_ISA_THUMB == 2 // clang 3.5 and later will set this if the core supports the Thumb-2 ISA.
-# define V4_ENABLE_JIT
-# endif
-#elif defined(Q_PROCESSOR_ARM_64) && (QT_POINTER_SIZE == 8)
-# if defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_INTEGRITY)
-# define V4_ENABLE_JIT
-# endif
-//#elif defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX)
-//# define V4_ENABLE_JIT
-#endif
-
-// check FPU with double precision on ARM platform
-#if (defined(Q_PROCESSOR_ARM_64) || defined(Q_PROCESSOR_ARM_32)) && defined(V4_ENABLE_JIT) && defined(__ARM_FP) && (__ARM_FP <= 0x04)
-# undef V4_ENABLE_JIT
-#endif
-
-// Black list some platforms
-#if defined(V4_ENABLE_JIT)
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
-# undef V4_ENABLE_JIT
-#endif
-#endif
-
-// For debug purposes: add CONFIG+=force-compile-jit to qmake's command-line to always compile the JIT.
-#if defined(V4_FORCE_COMPILE_JIT) && !defined(V4_ENABLE_JIT)
-# define V4_ENABLE_JIT
-#endif
-
// Do certain things depending on whether the JIT is enabled or disabled
-#ifdef V4_ENABLE_JIT
+#if QT_CONFIG(qml_jit)
#define ENABLE_YARR_JIT 1
#define ENABLE_JIT 1
#define ENABLE_ASSEMBLER 1
@@ -280,20 +236,6 @@ struct IdentifierTable;
class RegExpCache;
class MultiplyWrappedQObjectMap;
-enum class ObservedTraceValues : quint8 {
- Integer = 1 << 0,
- Boolean = 1 << 1,
- Double = 1 << 2,
- Other = 1 << 3,
- TypeMask = Integer | Boolean | Double | Other,
-
- TruePathTaken = 1 << 0,
- FalsePathTaken = 1 << 1,
-
- ArrayWasAccessed = 1 << 7,
- ArrayAccessNeededFallback = 1 << 6,
-};
-
enum PropertyFlag {
Attr_Data = 0,
Attr_Accessor = 0x1,
diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp
index 5db5bd46ec..f9bc7b68c6 100644
--- a/src/qml/jsruntime/qv4identifier.cpp
+++ b/src/qml/jsruntime/qv4identifier.cpp
@@ -39,29 +39,19 @@
#include "qv4identifier_p.h"
#include "qv4identifiertable_p.h"
#include "qv4string_p.h"
+#include <private/qprimefornumbits_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-static const uchar prime_deltas[] = {
- 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
- 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
-};
-
-static inline int primeForNumBits(int numBits)
-{
- return (1 << numBits) + prime_deltas[numBits];
-}
-
-
IdentifierHashData::IdentifierHashData(IdentifierTable *table, int numBits)
: size(0)
, numBits(numBits)
, identifierTable(table)
{
refCount.store(1);
- alloc = primeForNumBits(numBits);
+ alloc = qPrimeForNumBits(numBits);
entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry));
memset(entries, 0, alloc*sizeof(IdentifierHashEntry));
identifierTable->addIdentifierHash(this);
@@ -110,7 +100,7 @@ IdentifierHashEntry *IdentifierHash::addEntry(PropertyKey identifier)
if (grow) {
++d->numBits;
- int newAlloc = primeForNumBits(d->numBits);
+ int newAlloc = qPrimeForNumBits(d->numBits);
IdentifierHashEntry *newEntries = (IdentifierHashEntry *)malloc(newAlloc * sizeof(IdentifierHashEntry));
memset(newEntries, 0, newAlloc*sizeof(IdentifierHashEntry));
for (int i = 0; i < d->alloc; ++i) {
diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp
index ae937b2889..21b47c3909 100644
--- a/src/qml/jsruntime/qv4identifiertable.cpp
+++ b/src/qml/jsruntime/qv4identifiertable.cpp
@@ -38,28 +38,18 @@
****************************************************************************/
#include "qv4identifiertable_p.h"
#include "qv4symbol_p.h"
+#include <private/qprimefornumbits_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-static const uchar prime_deltas[] = {
- 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
- 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
-};
-
-static inline int primeForNumBits(int numBits)
-{
- return (1 << numBits) + prime_deltas[numBits];
-}
-
-
IdentifierTable::IdentifierTable(ExecutionEngine *engine, int numBits)
: engine(engine)
, size(0)
, numBits(numBits)
{
- alloc = primeForNumBits(numBits);
+ alloc = qPrimeForNumBits(numBits);
entriesByHash = (Heap::StringOrSymbol **)malloc(alloc*sizeof(Heap::StringOrSymbol *));
entriesById = (Heap::StringOrSymbol **)malloc(alloc*sizeof(Heap::StringOrSymbol *));
memset(entriesByHash, 0, alloc*sizeof(Heap::String *));
@@ -87,7 +77,7 @@ void IdentifierTable::addEntry(Heap::StringOrSymbol *str)
if (grow) {
++numBits;
- int newAlloc = primeForNumBits(numBits);
+ int newAlloc = qPrimeForNumBits(numBits);
Heap::StringOrSymbol **newEntries = (Heap::StringOrSymbol **)malloc(newAlloc*sizeof(Heap::String *));
memset(newEntries, 0, newAlloc*sizeof(Heap::StringOrSymbol *));
for (uint i = 0; i < alloc; ++i) {
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index a10fda79f2..d597335031 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -45,27 +45,18 @@
#include "qv4identifiertable_p.h"
#include "qv4value_p.h"
#include "qv4mm_p.h"
+#include <private/qprimefornumbits_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-static const uchar prime_deltas[] = {
- 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
- 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
-};
-
-static inline int primeForNumBits(int numBits)
-{
- return (1 << numBits) + prime_deltas[numBits];
-}
-
PropertyHashData::PropertyHashData(int numBits)
: refCount(1)
, size(0)
, numBits(numBits)
{
- alloc = primeForNumBits(numBits);
+ alloc = qPrimeForNumBits(numBits);
entries = (PropertyHash::Entry *)malloc(alloc*sizeof(PropertyHash::Entry));
memset(entries, 0, alloc*sizeof(PropertyHash::Entry));
}
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index c2c3fa0474..99f425293e 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -242,9 +242,6 @@ ReturnedValue Lookup::getter0Inlinegetter0Inline(Lookup *l, ExecutionEngine *eng
return o->inlinePropertyDataWithOffset(l->objectLookupTwoClasses.offset)->asReturnedValue();
if (l->objectLookupTwoClasses.ic2 == o->internalClass)
return o->inlinePropertyDataWithOffset(l->objectLookupTwoClasses.offset2)->asReturnedValue();
- Value obj = Value::fromHeapObject(o);
- Value str = Value::fromHeapObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
- return static_cast<Object &>(obj).get(&static_cast<String &>(str));
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
@@ -260,9 +257,6 @@ ReturnedValue Lookup::getter0Inlinegetter0MemberData(Lookup *l, ExecutionEngine
return o->inlinePropertyDataWithOffset(l->objectLookupTwoClasses.offset)->asReturnedValue();
if (l->objectLookupTwoClasses.ic2 == o->internalClass)
return o->memberData->values.data()[l->objectLookupTwoClasses.offset2].asReturnedValue();
- Value obj = Value::fromHeapObject(o);
- Value str = Value::fromHeapObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
- return static_cast<Object &>(obj).get(&static_cast<String &>(str));
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
@@ -278,9 +272,6 @@ ReturnedValue Lookup::getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEng
return o->memberData->values.data()[l->objectLookupTwoClasses.offset].asReturnedValue();
if (l->objectLookupTwoClasses.ic2 == o->internalClass)
return o->memberData->values.data()[l->objectLookupTwoClasses.offset2].asReturnedValue();
- Value obj = Value::fromHeapObject(o);
- Value str = Value::fromHeapObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
- return static_cast<Object &>(obj).get(&static_cast<String &>(str));
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
@@ -296,9 +287,7 @@ ReturnedValue Lookup::getterProtoTwoClasses(Lookup *l, ExecutionEngine *engine,
return l->protoLookupTwoClasses.data->asReturnedValue();
if (l->protoLookupTwoClasses.protoId2 == o->internalClass->protoId)
return l->protoLookupTwoClasses.data2->asReturnedValue();
- Value obj = Value::fromHeapObject(o);
- Value str = Value::fromHeapObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]);
- return static_cast<Object &>(obj).get(&static_cast<String &>(str));
+ return getterFallback(l, engine, object);
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 7309749a81..f2e0afd797 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-struct Lookup {
+struct Q_QML_PRIVATE_EXPORT Lookup {
union {
ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object);
ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine);
diff --git a/src/qml/jsruntime/qv4math_p.h b/src/qml/jsruntime/qv4math_p.h
index a60a49a811..90246c4229 100644
--- a/src/qml/jsruntime/qv4math_p.h
+++ b/src/qml/jsruntime/qv4math_p.h
@@ -66,42 +66,27 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-static inline QMLJS_READONLY ReturnedValue add_int32(int a, int b, quint8 *traceInfo = nullptr)
+static inline QMLJS_READONLY ReturnedValue add_int32(int a, int b)
{
int result;
- if (Q_UNLIKELY(add_overflow(a, b, &result))) {
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Double);
+ if (Q_UNLIKELY(add_overflow(a, b, &result)))
return Value::fromDouble(static_cast<double>(a) + b).asReturnedValue();
- }
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Integer);
return Value::fromInt32(result).asReturnedValue();
}
-static inline QMLJS_READONLY ReturnedValue sub_int32(int a, int b, quint8 *traceInfo = nullptr)
+static inline QMLJS_READONLY ReturnedValue sub_int32(int a, int b)
{
int result;
- if (Q_UNLIKELY(sub_overflow(a, b, &result))) {
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Double);
+ if (Q_UNLIKELY(sub_overflow(a, b, &result)))
return Value::fromDouble(static_cast<double>(a) - b).asReturnedValue();
- }
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Integer);
return Value::fromInt32(result).asReturnedValue();
}
-static inline QMLJS_READONLY ReturnedValue mul_int32(int a, int b, quint8 *traceInfo = nullptr)
+static inline QMLJS_READONLY ReturnedValue mul_int32(int a, int b)
{
int result;
- if (Q_UNLIKELY(mul_overflow(a, b, &result))) {
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Double);
+ if (Q_UNLIKELY(mul_overflow(a, b, &result)))
return Value::fromDouble(static_cast<double>(a) * b).asReturnedValue();
- }
- if (traceInfo)
- *traceInfo |= quint8(QV4::ObservedTraceValues::Integer);
return Value::fromInt32(result).asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 567382cbc0..38055ef407 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -410,7 +410,7 @@ private:
friend struct ObjectPrototype;
};
-struct ObjectOwnPropertyKeyIterator : OwnPropertyKeyIterator
+struct Q_QML_PRIVATE_EXPORT ObjectOwnPropertyKeyIterator : OwnPropertyKeyIterator
{
uint arrayIndex = 0;
uint memberIndex = 0;
diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h
index 523afd4ccf..b2a2ec3dea 100644
--- a/src/qml/jsruntime/qv4propertykey_p.h
+++ b/src/qml/jsruntime/qv4propertykey_p.h
@@ -124,7 +124,7 @@ public:
return m();
}
- bool isString() const;
+ Q_QML_EXPORT bool isString() const;
bool isSymbol() const;
bool isCanonicalNumericIndexString() const;
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index d2aa334805..f3351f6da0 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -231,17 +231,17 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
} else if (r.type.isValid()) {
if (lookup) {
if (r.type.isSingleton()) {
- QQmlEngine *e = v4->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = r.type.singletonInstanceInfo();
- siinfo->init(e);
- if (siinfo->qobjectApi(e)) {
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(v4->qmlEngine());
+ if (r.type.isQObjectSingleton() || r.type.isCompositeSingleton()) {
+ e->singletonInstance<QObject*>(r.type);
lookup->qmlContextSingletonLookup.singleton =
static_cast<Heap::Object*>(
Value::fromReturnedValue(
QQmlTypeWrapper::create(v4, nullptr, r.type)
).heapObject());
} else {
- QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e)));
+ QJSValue singleton = e->singletonInstance<QJSValue>(r.type);
+ QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, singleton));
lookup->qmlContextSingletonLookup.singleton = o->d();
}
lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupSingleton;
@@ -457,11 +457,17 @@ ReturnedValue QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(Lookup *
// into the handler expression through the locals of the call context. So for onClicked: { ... }
// the parameters of the clicked signal are injected and we must allow for them to be found here
// before any other property from the QML context.
- ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context);
- if (ctx.d()->type == Heap::ExecutionContext::Type_CallContext) {
- uint index = ctx.d()->internalClass->indexOfValueOrGetter(name);
- if (index < UINT_MAX)
- return static_cast<Heap::CallContext*>(ctx.d())->locals[index].asReturnedValue();
+ for (Heap::ExecutionContext *ctx = engine->currentContext()->d(); ctx; ctx = ctx->outer) {
+ if (ctx->type == Heap::ExecutionContext::Type_CallContext) {
+ const uint index = ctx->internalClass->indexOfValueOrGetter(name);
+ if (index < std::numeric_limits<uint>::max())
+ return static_cast<Heap::CallContext *>(ctx)->locals[index].asReturnedValue();
+ }
+
+ // Skip only block contexts within the current call context.
+ // Other contexts need a regular QML property lookup. See below.
+ if (ctx->type != Heap::ExecutionContext::Type_BlockContext)
+ break;
}
bool hasProperty = false;
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index ba9029bd4d..e81c90dd1a 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -560,9 +560,9 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
QQmlContextData *callingQmlContext = scope.engine->callingQmlContext();
if (!QQmlPropertyPrivate::write(object, *property, v, callingQmlContext)) {
- const char *valueType = nullptr;
- if (v.userType() == QVariant::Invalid) valueType = "null";
- else valueType = QMetaType::typeName(v.userType());
+ const char *valueType = (v.userType() == QMetaType::UnknownType)
+ ? "an unknown type"
+ : QMetaType::typeName(v.userType());
const char *targetTypeName = QMetaType::typeName(property->propType());
if (!targetTypeName)
@@ -851,7 +851,7 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E
if (!ddata || !ddata->propertyCache) {
QQmlPropertyData local;
QQmlPropertyData *property = QQmlPropertyCache::property(engine->jsEngine(), qobj, name, qmlContext, local);
- return getProperty(engine, qobj, property);
+ return property ? getProperty(engine, qobj, property) : QV4::Encode::undefined();
}
QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobj, qmlContext);
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 8f2b162106..e95dfa775f 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -717,30 +717,6 @@ ReturnedValue Runtime::LoadElement::call(ExecutionEngine *engine, const Value &o
return getElementFallback(engine, object, index);
}
-ReturnedValue Runtime::LoadElement_Traced::call(ExecutionEngine *engine, const Value &object, const Value &index, quint8 *traceSlot)
-{
- *traceSlot |= quint8(ObservedTraceValues::ArrayWasAccessed);
- if (index.isPositiveInt()) {
- uint idx = static_cast<uint>(index.int_32());
- if (Heap::Base *b = object.heapObject()) {
- if (b->internalClass->vtable->isObject) {
- Heap::Object *o = static_cast<Heap::Object *>(b);
- if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
- Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->values.size)
- if (!s->data(idx).isEmpty())
- return s->data(idx).asReturnedValue();
- }
- }
- }
- *traceSlot |= quint8(ObservedTraceValues::ArrayAccessNeededFallback);
- return getElementIntFallback(engine, object, idx);
- }
-
- *traceSlot |= quint8(ObservedTraceValues::ArrayAccessNeededFallback);
- return getElementFallback(engine, object, index);
-}
-
static Q_NEVER_INLINE bool setElementFallback(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
{
Scope scope(engine);
@@ -796,30 +772,6 @@ void Runtime::StoreElement::call(ExecutionEngine *engine, const Value &object, c
engine->throwTypeError();
}
-void Runtime::StoreElement_traced::call(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value, quint8 *traceSlot)
-{
- *traceSlot |= quint8(ObservedTraceValues::ArrayWasAccessed);
- if (index.isPositiveInt()) {
- uint idx = static_cast<uint>(index.int_32());
- if (Heap::Base *b = object.heapObject()) {
- if (b->internalClass->vtable->isObject) {
- Heap::Object *o = static_cast<Heap::Object *>(b);
- if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
- Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->values.size) {
- s->setData(engine, idx, value);
- return;
- }
- }
- }
- }
- }
-
- *traceSlot |= quint8(ObservedTraceValues::ArrayAccessNeededFallback);
- if (!setElementFallback(engine, object, index, value) && engine->currentStackFrame->v4Function->isStrict())
- engine->throwTypeError();
-}
-
ReturnedValue Runtime::GetIterator::call(ExecutionEngine *engine, const Value &in, int iterator)
{
Scope scope(engine);
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index 86cbccde23..13a73b7046 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -154,10 +154,6 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
{
static void call(ExecutionEngine *, const Value &, const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT StoreElement_traced : Method<Throws::Yes>
- {
- static void call(ExecutionEngine *, const Value &, const Value &, const Value &, quint8 *);
- };
struct Q_QML_PRIVATE_EXPORT LoadProperty : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &, int);
@@ -170,10 +166,6 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
{
static ReturnedValue call(ExecutionEngine *, const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT LoadElement_Traced : Method<Throws::Yes>
- {
- static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, quint8 *);
- };
struct Q_QML_PRIVATE_EXPORT LoadSuperProperty : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &);
diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp
index a84521e205..a5e62d3e35 100644
--- a/src/qml/jsruntime/qv4serialize.cpp
+++ b/src/qml/jsruntime/qv4serialize.cpp
@@ -39,11 +39,6 @@
#include "qv4serialize_p.h"
-#if QT_CONFIG(qml_list_model)
-#include <private/qqmllistmodel_p.h>
-#include <private/qqmllistmodelworkeragent_p.h>
-#endif
-
#include <private/qv4value_p.h>
#include <private/qv4dateobject_p.h>
#include <private/qv4regexpobject_p.h>
@@ -85,9 +80,7 @@ enum Type {
WorkerNumber,
WorkerDate,
WorkerRegexp,
-#if QT_CONFIG(qml_list_model)
WorkerListModel,
-#endif
#if QT_CONFIG(qml_sequence_object)
WorkerSequence
#endif
@@ -235,18 +228,15 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine
} else if (const QObjectWrapper *qobjectWrapper = v.as<QV4::QObjectWrapper>()) {
// XXX TODO: Generalize passing objects between the main thread and worker scripts so
// that others can trivially plug in their elements.
-#if QT_CONFIG(qml_list_model)
- QQmlListModel *lm = qobject_cast<QQmlListModel *>(qobjectWrapper->object());
- if (lm && lm->agent()) {
- QQmlListModelWorkerAgent *agent = lm->agent();
- agent->addref();
- push(data, valueheader(WorkerListModel));
- push(data, (void *)agent);
- return;
+ if (QObject *lm = qobjectWrapper->object()) {
+ if (QObject *agent = qvariant_cast<QObject *>(lm->property("agent"))) {
+ if (QMetaObject::invokeMethod(agent, "addref")) {
+ push(data, valueheader(WorkerListModel));
+ push(data, (void *)agent);
+ return;
+ }
+ }
}
-#else
- Q_UNUSED(qobjectWrapper);
-#endif
// No other QObject's are allowed to be sent
push(data, valueheader(WorkerUndefined));
} else if (const Object *o = v.as<Object>()) {
@@ -298,6 +288,41 @@ void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine
}
}
+struct VariantRef
+{
+ VariantRef() : obj(nullptr) {}
+ VariantRef(const VariantRef &r) : obj(r.obj) { addref(); }
+ VariantRef(QObject *a) : obj(a) { addref(); }
+ ~VariantRef() { release(); }
+
+ VariantRef &operator=(const VariantRef &o) {
+ o.addref();
+ release();
+ obj = o.obj;
+ return *this;
+ }
+
+ void addref() const
+ {
+ if (obj)
+ QMetaObject::invokeMethod(obj, "addref");
+ }
+
+ void release() const
+ {
+ if (obj)
+ QMetaObject::invokeMethod(obj, "release");
+
+ }
+
+ QObject *obj;
+};
+
+QT_END_NAMESPACE
+Q_DECLARE_METATYPE(VariantRef)
+Q_DECLARE_METATYPE(QV4::ExecutionEngine *)
+QT_BEGIN_NAMESPACE
+
ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine)
{
quint32 header = popUint32(data);
@@ -366,24 +391,21 @@ ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine)
data += ALIGN(length * sizeof(quint16));
return Encode(engine->newRegExpObject(pattern, flags));
}
-#if QT_CONFIG(qml_list_model)
case WorkerListModel:
{
- void *ptr = popPtr(data);
- QQmlListModelWorkerAgent *agent = (QQmlListModelWorkerAgent *)ptr;
+ QObject *agent = reinterpret_cast<QObject *>(popPtr(data));
QV4::ScopedValue rv(scope, QV4::QObjectWrapper::wrap(engine, agent));
// ### Find a better solution then the ugly property
- QQmlListModelWorkerAgent::VariantRef ref(agent);
+ VariantRef ref(agent);
QVariant var = QVariant::fromValue(ref);
QV4::ScopedValue v(scope, scope.engine->fromVariant(var));
QV4::ScopedString s(scope, engine->newString(QStringLiteral("__qml:hidden:ref")));
rv->as<Object>()->defineReadonlyProperty(s, v);
- agent->release();
- agent->setEngine(engine);
+ QMetaObject::invokeMethod(agent, "release");
+ agent->setProperty("engine", QVariant::fromValue(engine));
return rv->asReturnedValue();
}
-#endif
#if QT_CONFIG(qml_sequence_object)
case WorkerSequence:
{
@@ -423,4 +445,3 @@ ReturnedValue Serialize::deserialize(const QByteArray &data, ExecutionEngine *en
}
QT_END_NAMESPACE
-
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 98e4f4f7b9..ec44f42933 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -61,7 +61,9 @@
#include "qv4alloca_p.h"
+#if QT_CONFIG(qml_jit)
#include <private/qv4baselinejit_p.h>
+#endif
#undef COUNT_INSTRUCTIONS
@@ -345,85 +347,9 @@ static struct InstrCount {
#undef CHECK_EXCEPTION
#endif
#define CHECK_EXCEPTION \
- if (engine->hasException) \
+ if (engine->hasException || engine->isInterrupted) \
goto handleUnwind
-static inline void traceJumpTakesTruePath(bool truePathTaken, Function *f, int slot)
-{
-#if QT_CONFIG(qml_tracing)
- quint8 *traceInfo = f->traceInfo(slot);
- Q_ASSERT(traceInfo);
- *traceInfo |= truePathTaken ? quint8(ObservedTraceValues::TruePathTaken)
- : quint8(ObservedTraceValues::FalsePathTaken);
-#else
- Q_UNUSED(truePathTaken);
- Q_UNUSED(f);
- Q_UNUSED(slot);
-#endif
-}
-
-static inline void traceValue(ReturnedValue acc, Function *f, int slot)
-{
-#if QT_CONFIG(qml_tracing)
- quint8 *traceInfo = f->traceInfo(slot);
- Q_ASSERT(traceInfo);
- switch (Primitive::fromReturnedValue(acc).type()) {
- case QV4::Value::Integer_Type:
- *traceInfo |= quint8(ObservedTraceValues::Integer);
- break;
- case QV4::Value::Boolean_Type:
- *traceInfo |= quint8(ObservedTraceValues::Boolean);
- break;
- case QV4::Value::Double_Type:
- *traceInfo |= quint8(ObservedTraceValues::Double);
- break;
- default:
- *traceInfo |= quint8(ObservedTraceValues::Other);
- break;
- }
-#else
- Q_UNUSED(acc);
- Q_UNUSED(f);
- Q_UNUSED(slot);
-#endif
-}
-
-static inline void traceIntValue(Function *f, int slot)
-{
-#if QT_CONFIG(qml_tracing)
- quint8 *traceInfo = f->traceInfo(slot);
- Q_ASSERT(traceInfo);
- *traceInfo |= quint8(ObservedTraceValues::Integer);
-#else
- Q_UNUSED(f);
- Q_UNUSED(slot);
-#endif
-}
-
-static inline void traceDoubleValue(Function *f, int slot)
-{
-#if QT_CONFIG(qml_tracing)
- quint8 *traceInfo = f->traceInfo(slot);
- Q_ASSERT(traceInfo);
- *traceInfo |= quint8(ObservedTraceValues::Double);
-#else
- Q_UNUSED(f);
- Q_UNUSED(slot);
-#endif
-}
-
-static inline void traceOtherValue(Function *f, int slot)
-{
-#if QT_CONFIG(qml_tracing)
- quint8 *traceInfo = f->traceInfo(slot);
- Q_ASSERT(traceInfo);
- *traceInfo |= quint8(ObservedTraceValues::Other);
-#else
- Q_UNUSED(f);
- Q_UNUSED(slot);
-#endif
-}
-
static inline Heap::CallContext *getScope(QV4::Value *stack, int level)
{
Heap::ExecutionContext *scope = static_cast<ExecutionContext &>(stack[CallData::Context]).d();
@@ -499,22 +425,16 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling
QV4::Debugging::Debugger *debugger = engine->debugger();
-#ifdef V4_ENABLE_JIT
+#if QT_CONFIG(qml_jit)
if (debugger == nullptr) {
if (function->jittedCode == nullptr) {
- if (engine->canJIT(function)) {
-#if QT_CONFIG(qml_tracing)
- if (function->tracingEnabled())
- runTracingJit(function);
- else
-#endif
- QV4::JIT::BaselineJIT(function).generate();
- } else {
+ if (engine->canJIT(function))
+ QV4::JIT::BaselineJIT(function).generate();
+ else
++function->interpreterCallCount;
- }
}
}
-#endif // V4_ENABLE_JIT
+#endif // QT_CONFIG(qml_jit)
// interpreter
if (debugger)
@@ -523,22 +443,6 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
ReturnedValue result;
if (function->jittedCode != nullptr && debugger == nullptr) {
result = function->jittedCode(frame, engine);
- if (QV4::Value::fromReturnedValue(result).isEmpty()) { // de-optimize!
- if (ShowWhenDeoptimiationHappens) {
- // This is debug code, which is disabled by default, and completely removed by the
- // compiler.
- fprintf(stderr, "*********************** DEOPT! %s ***********************\n"
- "*** deopt IP: %d, line: %d\n",
- function->name()->toQString().toUtf8().constData(),
- frame->instructionPointer,
- frame->lineNumber());
- }
- delete function->codeRef;
- function->codeRef = nullptr;
- function->jittedCode = nullptr;
- function->interpreterCallCount = 0; // reset to restart tracing: apparently we didn't have enough info before
- result = interpret(frame, engine, function->codeData + frame->instructionPointer);
- }
} else {
// interpreter
result = interpret(frame, engine, function->codeData);
@@ -557,11 +461,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
QV4::ReturnedValue acc = accumulator.asReturnedValue();
Value *stack = reinterpret_cast<Value *>(frame->jsFrame);
- if (function->tracingEnabled()) {
- for (int i = 0; i < int(function->nFormals); ++i)
- traceValue(frame->jsFrame->argument(i), function, i);
- }
-
MOTH_JUMP_TABLE;
for (;;) {
@@ -620,7 +519,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m());
Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
acc = cc->locals[index].asReturnedValue();
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadLocal)
MOTH_BEGIN_INSTR(StoreLocal)
@@ -633,7 +531,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(LoadScopedLocal)
auto cc = getScope(stack, scope);
acc = cc->locals[index].asReturnedValue();
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadScopedLocal)
MOTH_BEGIN_INSTR(StoreScopedLocal)
@@ -658,7 +555,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
STORE_IP();
acc = Runtime::LoadName::call(engine, name);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadName)
MOTH_BEGIN_INSTR(LoadGlobalLookup)
@@ -666,7 +562,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
acc = l->globalGetter(l, engine);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadGlobalLookup)
MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup)
@@ -674,7 +569,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
acc = l->qmlContextPropertyGetter(l, engine, nullptr);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(StoreNameStrict)
@@ -694,25 +588,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(LoadElement)
STORE_IP();
STORE_ACC();
-#if QT_CONFIG(qml_tracing)
- acc = Runtime::LoadElement_Traced::call(engine, STACK_VALUE(base), accumulator, function->traceInfo(traceSlot));
- traceValue(acc, function, traceSlot);
-#else
- Q_UNUSED(traceSlot);
acc = Runtime::LoadElement::call(engine, STACK_VALUE(base), accumulator);
-#endif
CHECK_EXCEPTION;
MOTH_END_INSTR(LoadElement)
MOTH_BEGIN_INSTR(StoreElement)
STORE_IP();
STORE_ACC();
-#if QT_CONFIG(qml_tracing)
- Runtime::StoreElement_traced::call(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator, function->traceInfo(traceSlot));
-#else
- Q_UNUSED(traceSlot);
Runtime::StoreElement::call(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator);
-#endif
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreElement)
@@ -721,7 +604,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
STORE_ACC();
acc = Runtime::LoadProperty::call(engine, accumulator, name);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadProperty)
MOTH_BEGIN_INSTR(GetLookup)
@@ -740,7 +622,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
acc = l->getter(l, engine, accumulator);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(GetLookup)
MOTH_BEGIN_INSTR(StoreProperty)
@@ -814,7 +695,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
Value undef = Value::undefinedValue();
acc = static_cast<const FunctionObject &>(func).call(&undef, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallWithReceiver)
@@ -826,14 +706,12 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
}
acc = static_cast<const FunctionObject &>(func).call(stack + thisObject, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallWithReceiver)
MOTH_BEGIN_INSTR(CallProperty)
STORE_IP();
acc = Runtime::CallProperty::call(engine, stack[base], name, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
@@ -861,49 +739,42 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallPropertyLookup)
MOTH_BEGIN_INSTR(CallElement)
STORE_IP();
acc = Runtime::CallElement::call(engine, stack[base], STACK_VALUE(index), stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallElement)
MOTH_BEGIN_INSTR(CallName)
STORE_IP();
acc = Runtime::CallName::call(engine, name, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallName)
MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
STORE_IP();
acc = Runtime::CallPossiblyDirectEval::call(engine, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallPossiblyDirectEval)
MOTH_BEGIN_INSTR(CallGlobalLookup)
STORE_IP();
acc = Runtime::CallGlobalLookup::call(engine, index, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallGlobalLookup)
MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
STORE_IP();
acc = Runtime::CallQmlContextPropertyLookup::call(engine, index, stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(CallWithSpread)
STORE_IP();
acc = Runtime::CallWithSpread::call(engine, STACK_VALUE(func), STACK_VALUE(thisObject), stack + argv, argc);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallWithSpread)
MOTH_BEGIN_INSTR(TailCall)
@@ -1118,7 +989,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
takeJump = ACC.int_32();
else
takeJump = ACC.toBoolean();
- traceJumpTakesTruePath(takeJump, function, traceSlot);
if (takeJump)
code += offset;
MOTH_END_INSTR(JumpTrue)
@@ -1129,7 +999,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
takeJump = !ACC.int_32();
else
takeJump = !ACC.toBoolean();
- traceJumpTakesTruePath(!takeJump, function, traceSlot);
if (takeJump)
code += offset;
MOTH_END_INSTR(JumpFalse)
@@ -1144,6 +1013,10 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
code += offset;
MOTH_END_INSTR(JumpNotUndefined)
+ MOTH_BEGIN_INSTR(CheckException)
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(CheckException)
+
MOTH_BEGIN_INSTR(CmpEqNull)
acc = Encode(ACC.isNullOrUndefined());
MOTH_END_INSTR(CmpEqNull)
@@ -1289,12 +1162,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_END_INSTR(UNot)
MOTH_BEGIN_INSTR(UPlus)
- if (Q_LIKELY(ACC.isNumber())) {
- if (ACC.isDouble())
- traceDoubleValue(function, traceSlot);
- else
- traceIntValue(function, traceSlot);
- } else {
+ if (Q_UNLIKELY(!ACC.isNumber())) {
acc = Encode(ACC.toNumberImpl());
CHECK_EXCEPTION;
}
@@ -1305,17 +1173,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
int a = ACC.int_32();
if (a == 0 || a == std::numeric_limits<int>::min()) {
acc = Encode(-static_cast<double>(a));
- traceDoubleValue(function, traceSlot);
} else {
- acc = sub_int32(0, ACC.int_32(), function->traceInfo(traceSlot));
+ acc = sub_int32(0, ACC.int_32());
}
} else if (ACC.isDouble()) {
acc ^= (1ull << 63); // simply flip sign bit
- traceDoubleValue(function, traceSlot);
} else {
acc = Encode(-ACC.toNumberImpl());
CHECK_EXCEPTION;
- traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(UMinus)
@@ -1326,57 +1191,49 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(Increment)
if (Q_LIKELY(ACC.integerCompatible())) {
- acc = add_int32(ACC.int_32(), 1, function->traceInfo(traceSlot));
+ acc = add_int32(ACC.int_32(), 1);
} else if (ACC.isDouble()) {
acc = QV4::Encode(ACC.doubleValue() + 1.);
- traceDoubleValue(function, traceSlot);
} else {
acc = Encode(ACC.toNumberImpl() + 1.);
CHECK_EXCEPTION;
- traceDoubleValue(function, traceSlot);
}
MOTH_END_INSTR(Increment)
MOTH_BEGIN_INSTR(Decrement)
if (Q_LIKELY(ACC.integerCompatible())) {
- acc = sub_int32(ACC.int_32(), 1, function->traceInfo(traceSlot));
+ acc = sub_int32(ACC.int_32(), 1);
} else if (ACC.isDouble()) {
acc = QV4::Encode(ACC.doubleValue() - 1.);
- traceDoubleValue(function, traceSlot);
} else {
acc = Encode(ACC.toNumberImpl() - 1.);
CHECK_EXCEPTION;
- traceDoubleValue(function, traceSlot);
}
MOTH_END_INSTR(Decrement)
MOTH_BEGIN_INSTR(Add)
const Value left = STACK_VALUE(lhs);
if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
- acc = add_int32(left.int_32(), ACC.int_32(), function->traceInfo(traceSlot));
+ acc = add_int32(left.int_32(), ACC.int_32());
} else if (left.isNumber() && ACC.isNumber()) {
acc = Encode(left.asDouble() + ACC.asDouble());
- traceDoubleValue(function, traceSlot);
} else {
STORE_ACC();
acc = Runtime::Add::call(engine, left, accumulator);
CHECK_EXCEPTION;
- traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(Add)
MOTH_BEGIN_INSTR(Sub)
const Value left = STACK_VALUE(lhs);
if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
- acc = sub_int32(left.int_32(), ACC.int_32(), function->traceInfo(traceSlot));
+ acc = sub_int32(left.int_32(), ACC.int_32());
} else if (left.isNumber() && ACC.isNumber()) {
acc = Encode(left.asDouble() - ACC.asDouble());
- traceDoubleValue(function, traceSlot);
} else {
STORE_ACC();
acc = Runtime::Sub::call(left, accumulator);
CHECK_EXCEPTION;
- traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(Sub)
@@ -1393,15 +1250,13 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(Mul)
const Value left = STACK_VALUE(lhs);
if (Q_LIKELY(Value::integerCompatible(left, ACC))) {
- acc = mul_int32(left.int_32(), ACC.int_32(), function->traceInfo(traceSlot));
+ acc = mul_int32(left.int_32(), ACC.int_32());
} else if (left.isNumber() && ACC.isNumber()) {
acc = Encode(left.asDouble() * ACC.asDouble());
- traceDoubleValue(function, traceSlot);
} else {
STORE_ACC();
acc = Runtime::Mul::call(left, accumulator);
CHECK_EXCEPTION;
- traceOtherValue(function, traceSlot);
}
MOTH_END_INSTR(Mul)
@@ -1415,7 +1270,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
STORE_ACC();
acc = Runtime::Mod::call(STACK_VALUE(lhs), accumulator);
CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
MOTH_END_INSTR(Mod)
MOTH_BEGIN_INSTR(BitAnd)
@@ -1513,7 +1367,10 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_END_INSTR(Debug)
handleUnwind:
- Q_ASSERT(engine->hasException || frame->unwindLevel);
+ // We do start the exception handler in case of isInterrupted. The exception handler will
+ // immediately abort, due to the same isInterrupted. We don't skip the exception handler
+ // because the current behavior is easier to implement in the JIT.
+ Q_ASSERT(engine->hasException || engine->isInterrupted || frame->unwindLevel);
if (!frame->unwindHandler) {
acc = Encode::undefined();
return acc;
diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h
index 4ac7120d36..8a76e60f20 100644
--- a/src/qml/jsruntime/qv4vme_moth_p.h
+++ b/src/qml/jsruntime/qv4vme_moth_p.h
@@ -58,8 +58,6 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace Moth {
-void runTracingJit(QV4::Function *function);
-
class VME
{
public:
diff --git a/src/qml/jsruntime/qv4vtable_p.h b/src/qml/jsruntime/qv4vtable_p.h
index a4d91640c5..9dda104cd1 100644
--- a/src/qml/jsruntime/qv4vtable_p.h
+++ b/src/qml/jsruntime/qv4vtable_p.h
@@ -58,7 +58,7 @@ namespace QV4 {
struct Lookup;
-struct OwnPropertyKeyIterator {
+struct Q_QML_PRIVATE_EXPORT OwnPropertyKeyIterator {
virtual ~OwnPropertyKeyIterator() = 0;
virtual PropertyKey next(const Object *o, Property *p = nullptr, PropertyAttributes *attrs = nullptr) = 0;
};
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index d96a1c285a..ca3282556e 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -70,7 +70,9 @@ include(parser/parser.pri)
include(compiler/compiler.pri)
include(jsapi/jsapi.pri)
include(jsruntime/jsruntime.pri)
-include(jit/jit.pri)
+qtConfig(qml-jit) {
+ include(jit/jit.pri)
+}
include(qml/qml.pri)
include(debugger/debugger.pri)
include(qmldirparser/qmldirparser.pri)
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri
index 0bb8cb954e..eadba394b4 100644
--- a/src/qml/qml/ftw/ftw.pri
+++ b/src/qml/qml/ftw/ftw.pri
@@ -3,6 +3,7 @@ HEADERS += \
$$PWD/qintrusivelist_p.h \
$$PWD/qpodvector_p.h \
$$PWD/qhashedstring_p.h \
+ $$PWD/qprimefornumbits_p.h \
$$PWD/qqmlrefcount_p.h \
$$PWD/qfieldlist_p.h \
$$PWD/qqmlthread_p.h \
@@ -18,8 +19,7 @@ HEADERS += \
SOURCES += \
$$PWD/qintrusivelist.cpp \
$$PWD/qhashedstring.cpp \
- $$PWD/qqmlthread.cpp \
- $$PWD/qstringhash.cpp
+ $$PWD/qqmlthread.cpp
# mirrors logic in $$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri
# clock_gettime() is implemented in librt on these systems
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
index bb6688599d..7a8fdd0a14 100644
--- a/src/qml/qml/ftw/qhashedstring.cpp
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -41,6 +41,60 @@
QT_BEGIN_NAMESPACE
+// Copy of QString's qMemCompare
+bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length)
+{
+ Q_ASSERT(lhs && rhs);
+ const quint16 *a = (const quint16 *)lhs;
+ const quint16 *b = (const quint16 *)rhs;
+
+ if (a == b || !length)
+ return true;
+
+ union {
+ const quint16 *w;
+ const quint32 *d;
+ quintptr value;
+ } sa, sb;
+ sa.w = a;
+ sb.w = b;
+
+ // check alignment
+ if ((sa.value & 2) == (sb.value & 2)) {
+ // both addresses have the same alignment
+ if (sa.value & 2) {
+ // both addresses are not aligned to 4-bytes boundaries
+ // compare the first character
+ if (*sa.w != *sb.w)
+ return false;
+ --length;
+ ++sa.w;
+ ++sb.w;
+
+ // now both addresses are 4-bytes aligned
+ }
+
+ // both addresses are 4-bytes aligned
+ // do a fast 32-bit comparison
+ const quint32 *e = sa.d + (length >> 1);
+ for ( ; sa.d != e; ++sa.d, ++sb.d) {
+ if (*sa.d != *sb.d)
+ return false;
+ }
+
+ // do we have a tail?
+ return (length & 1) ? *sa.w == *sb.w : true;
+ } else {
+ // one of the addresses isn't 4-byte aligned but the other is
+ const quint16 *e = sa.w + length;
+ for ( ; sa.w != e; ++sa.w, ++sb.w) {
+ if (*sa.w != *sb.w)
+ return false;
+ }
+ }
+ return true;
+}
+
QHashedStringRef QHashedStringRef::mid(int offset, int length) const
{
Q_ASSERT(offset < m_length);
diff --git a/src/qml/qml/ftw/qprimefornumbits_p.h b/src/qml/qml/ftw/qprimefornumbits_p.h
new file mode 100644
index 0000000000..6e9acbf7fd
--- /dev/null
+++ b/src/qml/qml/ftw/qprimefornumbits_p.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $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 QPRIMEFORNUMBITS_P_H
+#define QPRIMEFORNUMBITS_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 <private/qtqmlglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ The prime_deltas array is a table of selected prime values, even
+ though it doesn't look like one. The primes we are using are 1,
+ 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate
+ surrounding of a power of two.
+
+ The qPrimeForNumBits() function returns the prime associated to a
+ power of two. For example, qPrimeForNumBits(8) returns 257.
+*/
+
+inline int qPrimeForNumBits(int numBits)
+{
+ static constexpr const uchar prime_deltas[] = {
+ 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
+ 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
+ };
+
+ return (1 << numBits) + prime_deltas[numBits];
+}
+
+QT_END_NAMESPACE
+
+#endif // QPRIMEFORNUMBITS_P_H
diff --git a/src/qml/qml/ftw/qstringhash.cpp b/src/qml/qml/ftw/qstringhash.cpp
deleted file mode 100644
index a483dcb810..0000000000
--- a/src/qml/qml/ftw/qstringhash.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $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 "qstringhash_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*
- A QHash has initially around pow(2, MinNumBits) buckets. For
- example, if MinNumBits is 4, it has 17 buckets.
-*/
-static const int MinNumBits = 4;
-
-/*
- The prime_deltas array is a table of selected prime values, even
- though it doesn't look like one. The primes we are using are 1,
- 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate
- surrounding of a power of two.
-
- The primeForNumBits() function returns the prime associated to a
- power of two. For example, primeForNumBits(8) returns 257.
-*/
-
-static const uchar prime_deltas[] = {
- 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
- 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
-};
-
-static inline int primeForNumBits(int numBits)
-{
- return (1 << numBits) + prime_deltas[numBits];
-}
-
-void QStringHashData::rehashToSize(int size)
-{
- short bits = qMax(MinNumBits, (int)numBits);
- while (primeForNumBits(bits) < size) bits++;
-
- if (bits > numBits)
- rehashToBits(bits);
-}
-
-void QStringHashData::rehashToBits(short bits)
-{
- numBits = qMax(MinNumBits, (int)bits);
-
- int nb = primeForNumBits(numBits);
- if (nb == numBuckets && buckets)
- return;
-
- QStringHashNode **newBuckets = new QStringHashNode *[nb];
- ::memset(newBuckets, 0, sizeof(QStringHashNode *) * nb);
-
- // Preserve the existing order within buckets so that items with the
- // same key will retain the same find/findNext order
- for (int i = 0; i < numBuckets; ++i) {
- QStringHashNode *bucket = buckets[i];
- if (bucket)
- rehashNode(newBuckets, nb, bucket);
- }
-
- delete [] buckets;
- buckets = newBuckets;
- numBuckets = nb;
-}
-
-void QStringHashData::rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node)
-{
- QStringHashNode *next = node->next.data();
- if (next)
- rehashNode(newBuckets, nb, next);
-
- int bucket = node->hash % nb;
- node->next = newBuckets[bucket];
- newBuckets[bucket] = node;
-}
-
-// Copy of QString's qMemCompare
-bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length)
-{
- Q_ASSERT(lhs && rhs);
- const quint16 *a = (const quint16 *)lhs;
- const quint16 *b = (const quint16 *)rhs;
-
- if (a == b || !length)
- return true;
-
- union {
- const quint16 *w;
- const quint32 *d;
- quintptr value;
- } sa, sb;
- sa.w = a;
- sb.w = b;
-
- // check alignment
- if ((sa.value & 2) == (sb.value & 2)) {
- // both addresses have the same alignment
- if (sa.value & 2) {
- // both addresses are not aligned to 4-bytes boundaries
- // compare the first character
- if (*sa.w != *sb.w)
- return false;
- --length;
- ++sa.w;
- ++sb.w;
-
- // now both addresses are 4-bytes aligned
- }
-
- // both addresses are 4-bytes aligned
- // do a fast 32-bit comparison
- const quint32 *e = sa.d + (length >> 1);
- for ( ; sa.d != e; ++sa.d, ++sb.d) {
- if (*sa.d != *sb.d)
- return false;
- }
-
- // do we have a tail?
- return (length & 1) ? *sa.w == *sb.w : true;
- } else {
- // one of the addresses isn't 4-byte aligned but the other is
- const quint16 *e = sa.w + length;
- for ( ; sa.w != e; ++sa.w, ++sb.w) {
- if (*sa.w != *sb.w)
- return false;
- }
- }
- return true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qstringhash_p.h b/src/qml/qml/ftw/qstringhash_p.h
index c7251e8837..f9435b4919 100644
--- a/src/qml/qml/ftw/qstringhash_p.h
+++ b/src/qml/qml/ftw/qstringhash_p.h
@@ -52,11 +52,14 @@
//
#include <private/qhashedstring_p.h>
+#include <private/qprimefornumbits_p.h>
+
+#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
class QStringHashData;
-class Q_AUTOTEST_EXPORT QStringHashNode
+class QStringHashNode
{
public:
QStringHashNode()
@@ -154,12 +157,20 @@ public:
}
};
-class Q_AUTOTEST_EXPORT QStringHashData
+class QStringHashData
{
+ Q_DISABLE_COPY_MOVE(QStringHashData)
public:
- QStringHashData() {}
+ QStringHashData() = default;
+ ~QStringHashData() = default;
+
+ /*
+ A QHash has initially around pow(2, MinNumBits) buckets. For
+ example, if MinNumBits is 4, it has 17 buckets.
+ */
+ enum { MinNumBits = 4 };
- QStringHashNode **buckets = nullptr;
+ QStringHashNode **buckets = nullptr; // life cycle managed by QStringHash
int numBuckets = 0;
int size = 0;
short numBits = 0;
@@ -174,13 +185,51 @@ public:
QStringHashNode *n;
StringHash *p;
};
- void rehashToBits(short);
- void rehashToSize(int);
- void rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node);
-private:
- QStringHashData(const QStringHashData &);
- QStringHashData &operator=(const QStringHashData &);
+ void rehashToBits(short bits)
+ {
+ numBits = qMax(short(MinNumBits), bits);
+
+ int nb = qPrimeForNumBits(numBits);
+ if (nb == numBuckets && buckets)
+ return;
+
+ QStringHashNode **newBuckets = new QStringHashNode *[nb];
+ ::memset(newBuckets, 0, sizeof(QStringHashNode *) * nb);
+
+ // Preserve the existing order within buckets so that items with the
+ // same key will retain the same find/findNext order
+ for (int i = 0; i < numBuckets; ++i) {
+ QStringHashNode *bucket = buckets[i];
+ if (bucket)
+ rehashNode(newBuckets, nb, bucket);
+ }
+
+ delete [] buckets;
+ buckets = newBuckets;
+ numBuckets = nb;
+ }
+
+ void rehashToSize(int size)
+ {
+ short bits = qMax(short(MinNumBits), numBits);
+ while (qPrimeForNumBits(bits) < size)
+ bits++;
+
+ if (bits > numBits)
+ rehashToBits(bits);
+ }
+
+ void rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node)
+ {
+ QStringHashNode *next = node->next.data();
+ if (next)
+ rehashNode(newBuckets, nb, next);
+
+ int bucket = node->hash % nb;
+ node->next = newBuckets[bucket];
+ newBuckets[bucket] = node;
+ }
};
// For a supplied key type, in what form do we need to keep a hashed version?
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index 3000f56601..7b3f89e943 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -579,9 +579,15 @@ namespace QtQml {
Q_QML_EXPORT void qmlExecuteDeferred(QObject *);
Q_QML_EXPORT QQmlContext *qmlContext(const QObject *);
Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *);
- Q_QML_EXPORT QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true);
- Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(int *, const QObject *,
- const QMetaObject *, bool create);
+#if QT_DEPRECATED_SINCE(5, 14)
+ Q_QML_EXPORT QT_DEPRECATED QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true);
+ Q_QML_EXPORT QT_DEPRECATED QObject *qmlAttachedPropertiesObject(
+ int *, const QObject *, const QMetaObject *, bool create);
+#endif
+ Q_QML_EXPORT QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *,
+ const QMetaObject *);
+ Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc func,
+ bool create = true);
#ifndef Q_QDOC
}
@@ -602,8 +608,9 @@ Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versi
template<typename T>
QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
{
- static int idx = -1;
- return qmlAttachedPropertiesObject(&idx, obj, &T::staticMetaObject, create);
+ QObject *mutableObj = const_cast<QObject *>(obj);
+ return qmlAttachedPropertiesObject(
+ mutableObj, qmlAttachedPropertiesFunction(mutableObj, &T::staticMetaObject), create);
}
inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index b164517011..656c7dd515 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -517,9 +517,9 @@ QString QQmlBinding::expressionIdentifier() const
{
if (auto f = function()) {
QString url = f->sourceFile();
- quint16 lineNumber = f->compiledFunction->location.line;
- quint16 columnNumber = f->compiledFunction->location.column;
- return url + QString::asprintf(":%u:%u", uint(lineNumber), uint(columnNumber));
+ uint lineNumber = f->compiledFunction->location.line;
+ uint columnNumber = f->compiledFunction->location.column;
+ return url + QString::asprintf(":%u:%u", lineNumber, columnNumber);
}
return QStringLiteral("[native code]");
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 2468de6857..f4c03fc17c 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -57,6 +57,7 @@
#include <private/qv4value_p.h>
#include <private/qv4persistent_p.h>
#include <private/qqmlrefcount_p.h>
+#include <qqmlprivate.h>
#include <qjsengine.h>
#include <qvector.h>
@@ -265,7 +266,7 @@ public:
}
bool hasExtendedData() const { return extendedData != nullptr; }
- QHash<int, QObject *> *attachedProperties() const;
+ QHash<QQmlAttachedPropertiesFunc, QObject *> *attachedProperties() const;
static inline bool wasDeleted(const QObject *);
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index f070f16afd..bb2b3e462c 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -1057,7 +1057,7 @@ QQmlEngine::~QQmlEngine()
// XXX TODO: performance -- store list of singleton types separately?
QList<QQmlType> singletonTypes = QQmlMetaType::qmlSingletonTypes();
for (const QQmlType &currType : singletonTypes)
- currType.singletonInstanceInfo()->destroy(this);
+ d->destroySingletonInstance(currType);
delete d->rootContext;
d->rootContext = nullptr;
@@ -1402,23 +1402,13 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
template<>
QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
{
+ Q_D(QQmlEngine);
QQmlType type = QQmlMetaType::qmlType(qmlTypeId, QQmlMetaType::TypeIdCategory::QmlType);
if (!type.isValid() || !type.isSingleton())
return QJSValue();
- QQmlType::SingletonInstanceInfo* info = type.singletonInstanceInfo();
- info->init(this);
-
- if (QObject* o = info->qobjectApi(this))
- return this->newQObject(o);
- else {
- QJSValue value = info->scriptApi(this);
- if (!value.isUndefined())
- return value;
- }
-
- return QJSValue();
+ return d->singletonInstance<QJSValue>(type);
}
/*!
@@ -1617,29 +1607,39 @@ QQmlEngine *qmlEngine(const QObject *obj)
return data->context->engine;
}
-QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
+static QObject *resolveAttachedProperties(QQmlAttachedPropertiesFunc pf, QQmlData *data,
+ QObject *object, bool create)
{
- QQmlData *data = QQmlData::get(object, create);
- if (!data)
- return nullptr; // Attached properties are only on objects created by QML, unless explicitly requested (create==true)
+ if (!pf)
+ return nullptr;
- QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0;
+ QObject *rv = data->hasExtendedData() ? data->attachedProperties()->value(pf) : 0;
if (rv || !create)
return rv;
- QQmlEnginePrivate *engine = QQmlEnginePrivate::get(data->context);
- QQmlAttachedPropertiesFunc pf = QQmlMetaType::attachedPropertiesFuncById(engine, id);
- if (!pf)
- return nullptr;
-
- rv = pf(const_cast<QObject *>(object));
+ rv = pf(object);
if (rv)
- data->attachedProperties()->insert(id, rv);
+ data->attachedProperties()->insert(pf, rv);
return rv;
}
+#if QT_DEPRECATED_SINCE(5, 14)
+QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
+{
+ QQmlData *data = QQmlData::get(object, create);
+
+ // Attached properties are only on objects created by QML,
+ // unless explicitly requested (create==true)
+ if (!data)
+ return nullptr;
+
+ QQmlEnginePrivate *engine = QQmlEnginePrivate::get(data->context);
+ return resolveAttachedProperties(QQmlMetaType::attachedPropertiesFuncById(engine, id), data,
+ const_cast<QObject *>(object), create);
+}
+
QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
const QMetaObject *attachedMetaObject, bool create)
{
@@ -1653,6 +1653,30 @@ QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
return qmlAttachedPropertiesObjectById(*idCache, object, create);
}
+#endif
+
+QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *object,
+ const QMetaObject *attachedMetaObject)
+{
+ QQmlEngine *engine = object ? qmlEngine(object) : nullptr;
+ return QQmlMetaType::attachedPropertiesFunc(engine ? QQmlEnginePrivate::get(engine) : nullptr,
+ attachedMetaObject);
+}
+
+QObject *qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc func, bool create)
+{
+ if (!object)
+ return nullptr;
+
+ QQmlData *data = QQmlData::get(object, create);
+
+ // Attached properties are only on objects created by QML,
+ // unless explicitly requested (create==true)
+ if (!data)
+ return nullptr;
+
+ return resolveAttachedProperties(func, data, object, create);
+}
} // namespace QtQml
@@ -1694,7 +1718,7 @@ public:
QQmlDataExtended();
~QQmlDataExtended();
- QHash<int, QObject *> attachedProperties;
+ QHash<QQmlAttachedPropertiesFunc, QObject *> attachedProperties;
};
QQmlDataExtended::QQmlDataExtended()
@@ -1840,7 +1864,7 @@ void QQmlData::disconnectNotifiers()
}
}
-QHash<int, QObject *> *QQmlData::attachedProperties() const
+QHash<QQmlAttachedPropertiesFunc, QObject *> *QQmlData::attachedProperties() const
{
if (!extendedData) extendedData = new QQmlDataExtended;
return &extendedData->attachedProperties;
@@ -2413,6 +2437,67 @@ void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::CompiledData::Compi
m_compositeTypes.remove(compilationUnit->metaTypeId);
}
+template<>
+QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
+{
+ Q_Q(QQmlEngine);
+
+ QJSValue value = singletonInstances.value(type);
+ if (!value.isUndefined()) {
+ return value;
+ }
+
+ QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
+ Q_ASSERT(siinfo != nullptr);
+
+ if (siinfo->scriptCallback) {
+ value = siinfo->scriptCallback(q, q);
+ if (value.isQObject()) {
+ QObject *o = value.toQObject();
+ // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
+ // should behave identically to QML singleton types.
+ q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
+ }
+ singletonInstances.insert(type, value);
+
+ } else if (siinfo->qobjectCallback) {
+ QObject *o = siinfo->qobjectCallback(q, q);
+ if (!o) {
+ qFatal("qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.",
+ qPrintable(QString::fromUtf8(type.typeName())));
+ }
+ // if this object can use a property cache, create it now
+ QQmlData::ensurePropertyCache(q, o);
+ // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
+ // should behave identically to QML singleton types.
+ q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
+ value = q->newQObject(o);
+ singletonInstances.insert(type, value);
+
+ } else if (!siinfo->url.isEmpty()) {
+ QQmlComponent component(q, siinfo->url, QQmlComponent::PreferSynchronous);
+ QObject *o = component.beginCreate(q->rootContext());
+ value = q->newQObject(o);
+ singletonInstances.insert(type, value);
+ component.completeCreate();
+ }
+
+ return value;
+}
+
+void QQmlEnginePrivate::destroySingletonInstance(const QQmlType &type)
+{
+ Q_ASSERT(type.isSingleton() || type.isCompositeSingleton());
+
+ QObject* o = singletonInstances.take(type).toQObject();
+ if (o) {
+ QQmlData *ddata = QQmlData::get(o, false);
+ if (type.singletonInstanceInfo()->url.isEmpty() && ddata && ddata->indestructible && ddata->explicitIndestructibleSet)
+ return;
+ delete o;
+ }
+}
+
bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
{
return typeLoader.isTypeLoaded(url);
diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h
index 871e6bd9b4..da91c8fa15 100644
--- a/src/qml/qml/qqmlengine.h
+++ b/src/qml/qml/qqmlengine.h
@@ -175,12 +175,7 @@ Q_QML_EXPORT QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId);
template<typename T>
T QQmlEngine::singletonInstance(int qmlTypeId) {
- QJSValue instance = singletonInstance<QJSValue>(qmlTypeId);
- if (!instance.isQObject())
- return nullptr;
-
- QObject *object = instance.toQObject();
- return qobject_cast<T>(object);
+ return qobject_cast<T>(singletonInstance<QJSValue>(qmlTypeId).toQObject());
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index dab4e54cd6..4f7fb79593 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -229,6 +229,10 @@ public:
bool isTypeLoaded(const QUrl &url) const;
bool isScriptLoaded(const QUrl &url) const;
+ template <typename T>
+ T singletonInstance(const QQmlType &type);
+ void destroySingletonInstance(const QQmlType &type);
+
void sendQuit();
void sendExit(int retCode = 0);
void warning(const QQmlError &);
@@ -262,6 +266,8 @@ public:
mutable QMutex networkAccessManagerMutex;
private:
+ QHash<QQmlType, QJSValue> singletonInstances;
+
// These members must be protected by a QQmlEnginePrivate::Locker as they are required by
// the threaded loader. Only access them through their respective accessor methods.
QHash<int, QV4::CompiledData::CompilationUnit *> m_compositeTypes;
@@ -437,6 +443,14 @@ QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e)
return get(qmlEngine);
}
+template<>
+Q_QML_PRIVATE_EXPORT QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type);
+
+template<typename T>
+T QQmlEnginePrivate::singletonInstance(const QQmlType &type) {
+ return qobject_cast<T>(singletonInstance<QJSValue>(type).toQObject());
+}
+
QT_END_NAMESPACE
#endif // QQMLENGINE_P_H
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index 453c8ab8a8..92f2ccbb4a 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -182,7 +182,7 @@ private:
QV4::Function *m_v4Function;
};
-class QQmlPropertyCapture
+class Q_QML_PRIVATE_EXPORT QQmlPropertyCapture
{
public:
QQmlPropertyCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e, QQmlJavaScriptExpression::DeleteWatcher *w)
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 32f281b4f2..09df23de51 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -76,6 +76,8 @@ public:
const QQmlMetaTypeData *operator->() const { return data; }
operator const QQmlMetaTypeData *() const { return data; }
+ bool isValid() const { return data != nullptr; }
+
private:
QMutexLocker locker;
LockedData *data = nullptr;
@@ -143,12 +145,6 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
d->baseMetaObject = type.metaObject;
d->extraData.cd->attachedPropertiesFunc = type.attachedPropertiesFunction;
d->extraData.cd->attachedPropertiesType = type.attachedPropertiesMetaObject;
- if (d->extraData.cd->attachedPropertiesType) {
- d->extraData.cd->attachedPropertiesId = data->attachedPropertyId(d->baseMetaObject,
- d->index);
- } else {
- d->extraData.cd->attachedPropertiesId = -1;
- }
d->extraData.cd->parserStatusCast = type.parserStatusCast;
d->extraData.cd->propertyValueSourceCast = type.valueSourceCast;
d->extraData.cd->propertyValueInterceptorCast = type.valueInterceptorCast;
@@ -599,19 +595,6 @@ void QQmlMetaType::registerUndeletableType(const QQmlType &dtype)
data->undeletableTypes.insert(dtype);
}
-int QQmlMetaType::registerAttachedPropertyId(const QMetaObject *metaObject, int index)
-{
- QQmlMetaTypeDataPtr data;
- return data->attachedPropertyId(metaObject, index);
-}
-
-bool QQmlMetaType::unregisterAttachedPropertyId(const QMetaObject *metaObject, int index)
-{
- QQmlMetaTypeDataPtr data;
- // This is run from the QQmlType dtor. QQmlTypes in user code can outlive QQmlMetaTypeData.
- return data ? data->removeAttachedPropertyId(metaObject, index) : false;
-}
-
static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const QString &uri,
int majorVersion)
{
@@ -916,6 +899,7 @@ int QQmlMetaType::listType(int id)
return 0;
}
+#if QT_DEPRECATED_SINCE(5, 14)
int QQmlMetaType::attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMetaObject *mo)
{
QQmlMetaTypeDataPtr data;
@@ -937,6 +921,16 @@ QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(QQmlEnginePr
QQmlMetaTypeDataPtr data;
return data->types.at(id).attachedPropertiesFunction(engine);
}
+#endif
+
+QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFunc(QQmlEnginePrivate *engine,
+ const QMetaObject *mo)
+{
+ QQmlMetaTypeDataPtr data;
+
+ QQmlType type(data->metaObjectToType.value(mo));
+ return type.attachedPropertiesFunction(engine);
+}
QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject)
{
@@ -1216,6 +1210,10 @@ void QQmlMetaType::freeUnusedTypesAndCaches()
{
QQmlMetaTypeDataPtr data;
+ // in case this is being called during program exit, `data` might be destructed already
+ if (!data.isValid())
+ return;
+
bool deletedAtLeastOneType;
do {
deletedAtLeastOneType = false;
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index dde9cf68d7..9af982d1c3 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -88,9 +88,6 @@ public:
static void registerUndeletableType(const QQmlType &dtype);
- static int registerAttachedPropertyId(const QMetaObject *metaObject, int index);
- static bool unregisterAttachedPropertyId(const QMetaObject *metaObject, int index);
-
static QList<QString> qmlTypeNames();
static QList<QQmlType> qmlTypes();
static QList<QQmlType> qmlSingletonTypes();
@@ -122,8 +119,14 @@ public:
static QObject *toQObject(const QVariant &, bool *ok = nullptr);
static int listType(int);
- static int attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMetaObject *);
- static QQmlAttachedPropertiesFunc attachedPropertiesFuncById(QQmlEnginePrivate *, int);
+#if QT_DEPRECATED_SINCE(5, 14)
+ static QT_DEPRECATED int attachedPropertiesFuncId(QQmlEnginePrivate *engine,
+ const QMetaObject *);
+ static QT_DEPRECATED QQmlAttachedPropertiesFunc attachedPropertiesFuncById(QQmlEnginePrivate *,
+ int);
+#endif
+ static QQmlAttachedPropertiesFunc attachedPropertiesFunc(QQmlEnginePrivate *,
+ const QMetaObject *);
enum TypeCategory { Unknown, Object, List };
static TypeCategory typeCategory(int);
diff --git a/src/qml/qml/qqmlmetatypedata_p.h b/src/qml/qml/qqmlmetatypedata_p.h
index c45bc16280..5239b635ce 100644
--- a/src/qml/qml/qqmlmetatypedata_p.h
+++ b/src/qml/qml/qqmlmetatypedata_p.h
@@ -134,27 +134,8 @@ struct QQmlMetaTypeData
qWarning("%s", message.toUtf8().constData());
}
- int attachedPropertyId(const QMetaObject *metaObject, int ownIndex)
- {
- auto iter = attachedPropertyIds.find(metaObject);
- return (iter == attachedPropertyIds.end())
- ? *attachedPropertyIds.insert(metaObject, ownIndex)
- : *iter;
- }
-
- bool removeAttachedPropertyId(const QMetaObject *metaObject, int ownIndex)
- {
- auto iter = attachedPropertyIds.find(metaObject);
- if (iter != attachedPropertyIds.end() && *iter == ownIndex) {
- attachedPropertyIds.erase(iter);
- return true;
- }
- return false;
- }
-
private:
QStringList *m_typeRegistrationFailures = nullptr;
- QHash<const QMetaObject *, int> attachedPropertyIds;
};
inline uint qHash(const QQmlMetaTypeData::VersionedUri &v)
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index c36b3ed386..26d3b5b6c1 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -824,8 +824,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
else
return false;
}
- const int id = attachedType.attachedPropertiesId(QQmlEnginePrivate::get(engine));
- QObject *qmlObject = qmlAttachedPropertiesObjectById(id, _qobject);
+ QObject *qmlObject = qmlAttachedPropertiesObject(
+ _qobject, attachedType.attachedPropertiesFunction(QQmlEnginePrivate::get(engine)));
if (!populateInstance(binding->value.objectIndex, qmlObject, qmlObject, /*value type property*/nullptr))
return false;
return true;
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index c0232a7691..fa05b3fe19 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -77,6 +77,11 @@ typedef void (*IRLoaderFunction)(Document *, const QQmlPrivate::CachedQmlUnit *)
typedef QObject *(*QQmlAttachedPropertiesFunc)(QObject *);
+inline uint qHash(QQmlAttachedPropertiesFunc func, uint seed = 0)
+{
+ return qHash(quintptr(func), seed);
+}
+
template <typename TYPE>
class QQmlTypeInfo
{
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 000b88ebaa..c8166695ba 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -277,7 +277,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
if (!func) return; // Not an attachable type
- currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject);
+ currentObject = qmlAttachedPropertiesObject(currentObject, func);
if (!currentObject) return; // Something is broken with the attachable type
} else if (r.importNamespace) {
if ((ii + 1) == path.count()) return; // No type following the namespace
@@ -289,7 +289,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
if (!func) return; // Not an attachable type
- currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject);
+ currentObject = qmlAttachedPropertiesObject(currentObject, func);
if (!currentObject) return; // Something is broken with the attachable type
} else if (r.scriptIndex != -1) {
diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp
index 88eedec061..926e2810d5 100644
--- a/src/qml/qml/qqmltype.cpp
+++ b/src/qml/qml/qqmltype.cpp
@@ -51,70 +51,6 @@
QT_BEGIN_NAMESPACE
-void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
-{
- if (scriptCallback && scriptApi(e).isUndefined()) {
- QJSValue value = scriptCallback(e, e);
- if (value.isQObject()) {
- QObject *o = value.toQObject();
- // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
- // should behave identically to QML singleton types.
- e->setContextForObject(o, new QQmlContext(e->rootContext(), e));
- }
- setScriptApi(e, value);
- } else if (qobjectCallback && !qobjectApi(e)) {
- QObject *o = qobjectCallback(e, e);
- setQObjectApi(e, o);
- if (!o) {
- qFatal("qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.", qPrintable(typeName));
- }
- // if this object can use a property cache, create it now
- QQmlData::ensurePropertyCache(e, o);
- // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
- // should behave identically to QML singleton types.
- e->setContextForObject(o, new QQmlContext(e->rootContext(), e));
- } else if (!url.isEmpty() && !qobjectApi(e)) {
- QQmlComponent component(e, url, QQmlComponent::PreferSynchronous);
- QObject *o = component.beginCreate(e->rootContext());
- setQObjectApi(e, o);
- if (o)
- component.completeCreate();
- }
-}
-
-void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e)
-{
- // cleans up the engine-specific singleton instances if they exist.
- scriptApis.remove(e);
- QObject *o = qobjectApis.take(e);
- if (o) {
- QQmlData *ddata = QQmlData::get(o, false);
- if (url.isEmpty() && ddata && ddata->indestructible && ddata->explicitIndestructibleSet)
- return;
- delete o;
- }
-}
-
-void QQmlType::SingletonInstanceInfo::setQObjectApi(QQmlEngine *e, QObject *o)
-{
- qobjectApis.insert(e, o);
-}
-
-QObject *QQmlType::SingletonInstanceInfo::qobjectApi(QQmlEngine *e) const
-{
- return qobjectApis.value(e);
-}
-
-void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, const QJSValue &v)
-{
- scriptApis.insert(e, v);
-}
-
-QJSValue QQmlType::SingletonInstanceInfo::scriptApi(QQmlEngine *e) const
-{
- return scriptApis.value(e);
-}
-
QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
: regType(type), iid(nullptr), typeId(0), listId(0), revision(0),
containsRevisionedAttributes(false), baseMetaObject(nullptr),
@@ -156,10 +92,6 @@ QQmlTypePrivate::~QQmlTypePrivate()
qDeleteAll(scopedEnums);
switch (regType) {
case QQmlType::CppType:
- // If attached properties were successfully registered, deregister them.
- // (They may not have been registered if some other type used the same baseMetaObject)
- if (extraData.cd->attachedPropertiesType)
- QQmlMetaType::unregisterAttachedPropertyId(baseMetaObject, index);
delete extraData.cd->customParser;
delete extraData.cd;
break;
@@ -640,6 +572,16 @@ bool QQmlType::isCompositeSingleton() const
return d && d->regType == CompositeSingletonType;
}
+bool QQmlType::isQObjectSingleton() const
+{
+ return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->qobjectCallback;
+}
+
+bool QQmlType::isQJSValueSingleton() const
+{
+ return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->scriptCallback;
+}
+
int QQmlType::typeId() const
{
return d ? d->typeId : -1;
@@ -708,6 +650,7 @@ const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) c
return base.attachedPropertiesType(engine);
}
+#if QT_DEPRECATED_SINCE(5, 14)
/*
This is the id passed to qmlAttachedPropertiesById(). This is different from the index
for the case that a single class is registered under two or more names (eg. Item in
@@ -718,13 +661,14 @@ int QQmlType::attachedPropertiesId(QQmlEnginePrivate *engine) const
if (!d)
return -1;
if (d->regType == CppType)
- return d->extraData.cd->attachedPropertiesId;
+ return d->extraData.cd->attachedPropertiesType ? d->index : -1;
QQmlType base;
if (d->regType == CompositeType)
base = resolveCompositeBaseType(engine);
return base.attachedPropertiesId(engine);
}
+#endif
int QQmlType::parserStatusCast() const
{
diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h
index 0e59b1be06..1d65a08c8f 100644
--- a/src/qml/qml/qqmltype_p.h
+++ b/src/qml/qml/qqmltype_p.h
@@ -118,6 +118,8 @@ public:
bool isInterface() const;
bool isComposite() const;
bool isCompositeSingleton() const;
+ bool isQObjectSingleton() const;
+ bool isQJSValueSingleton() const;
int typeId() const;
int qListTypeId() const;
@@ -129,7 +131,9 @@ public:
QQmlAttachedPropertiesFunc attachedPropertiesFunction(QQmlEnginePrivate *engine) const;
const QMetaObject *attachedPropertiesType(QQmlEnginePrivate *engine) const;
- int attachedPropertiesId(QQmlEnginePrivate *engine) const;
+#if QT_DEPRECATED_SINCE(5, 14)
+ QT_DEPRECATED int attachedPropertiesId(QQmlEnginePrivate *engine) const;
+#endif
int parserStatusCast() const;
const char *interfaceIId() const;
@@ -138,28 +142,13 @@ public:
int index() const;
- class Q_QML_PRIVATE_EXPORT SingletonInstanceInfo
+ struct Q_QML_PRIVATE_EXPORT SingletonInstanceInfo
{
- public:
- SingletonInstanceInfo()
- : scriptCallback(nullptr), qobjectCallback(nullptr), instanceMetaObject(nullptr) {}
-
- QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *);
- QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *);
- const QMetaObject *instanceMetaObject;
+ QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *) = nullptr;
+ QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *) = nullptr;
+ const QMetaObject *instanceMetaObject = nullptr;
QString typeName;
QUrl url; // used by composite singletons
-
- void setQObjectApi(QQmlEngine *, QObject *);
- QObject *qobjectApi(QQmlEngine *) const;
- void setScriptApi(QQmlEngine *, const QJSValue &);
- QJSValue scriptApi(QQmlEngine *) const;
-
- void init(QQmlEngine *);
- void destroy(QQmlEngine *);
-
- QHash<QQmlEngine *, QJSValue> scriptApis;
- QHash<QQmlEngine *, QObject *> qobjectApis;
};
SingletonInstanceInfo *singletonInstanceInfo() const;
diff --git a/src/qml/qml/qqmltype_p_p.h b/src/qml/qml/qqmltype_p_p.h
index b317aff740..d381e11df4 100644
--- a/src/qml/qml/qqmltype_p_p.h
+++ b/src/qml/qml/qqmltype_p_p.h
@@ -83,7 +83,6 @@ public:
QQmlCustomParser *customParser;
QQmlAttachedPropertiesFunc attachedPropertiesFunc;
const QMetaObject *attachedPropertiesType;
- int attachedPropertiesId;
int propertyValueSourceCast;
int propertyValueInterceptorCast;
bool registerEnumClassesUnscoped;
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 86513b5ff8..236daac75c 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -89,25 +89,21 @@ QObject* QQmlTypeWrapper::singletonObject() const
if (!isSingleton())
return nullptr;
- QQmlEngine *e = engine()->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = d()->type().singletonInstanceInfo();
- siinfo->init(e);
- return siinfo->qobjectApi(e);
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine());
+ return e->singletonInstance<QObject*>(d()->type());
}
QVariant QQmlTypeWrapper::toVariant() const
{
- // Only Singleton type wrappers can be converted to a variant.
if (!isSingleton())
- return QVariant();
+ return QVariant::fromValue<QObject *>(d()->object);
- QQmlEngine *e = engine()->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = d()->type().singletonInstanceInfo();
- siinfo->init(e);
- if (QObject *qobjectSingleton = siinfo->qobjectApi(e))
- return QVariant::fromValue<QObject*>(qobjectSingleton);
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine());
+ const QQmlType type = d()->type();
+ if (type.isQJSValueSingleton())
+ return QVariant::fromValue<QJSValue>(e->singletonInstance<QJSValue>(type));
- return QVariant::fromValue<QJSValue>(siinfo->scriptApi(e));
+ return QVariant::fromValue<QObject*>(e->singletonInstance<QObject*>(type));
}
@@ -195,50 +191,51 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
// singleton types are handled differently to other types.
if (type.isSingleton()) {
- QQmlEngine *e = v4->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
- siinfo->init(e);
-
- QObject *qobjectSingleton = siinfo->qobjectApi(e);
- if (qobjectSingleton) {
-
- // check for enum value
- const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
- if (includeEnums && name->startsWithUpper()) {
- bool ok = false;
- int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok);
- if (ok)
- return QV4::Value::fromInt32(value).asReturnedValue();
-
- value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
- if (ok) {
- Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
- enumWrapper->d()->typePrivate = type.priv();
- QQmlType::refHandle(enumWrapper->d()->typePrivate);
- enumWrapper->d()->scopeEnumIndex = value;
- return enumWrapper.asReturnedValue();
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(v4->qmlEngine());
+ QJSValue scriptSingleton;
+ if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
+ if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
+ // check for enum value
+ const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
+ if (includeEnums && name->startsWithUpper()) {
+ bool ok = false;
+ int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok);
+ if (ok)
+ return QV4::Value::fromInt32(value).asReturnedValue();
+
+ value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
+ if (ok) {
+ Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
+ enumWrapper->d()->typePrivate = type.priv();
+ QQmlType::refHandle(enumWrapper->d()->typePrivate);
+ enumWrapper->d()->scopeEnumIndex = value;
+ return enumWrapper.asReturnedValue();
+ }
}
- }
- // check for property.
- bool ok;
- const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, &ok);
- if (hasProperty)
- *hasProperty = ok;
-
- // Warn when attempting to access a lowercased enum value, singleton case
- if (!ok && includeEnums && !name->startsWithUpper()) {
- enumForSingleton(v4, name, qobjectSingleton, type, &ok);
- if (ok)
- return throwLowercaseEnumError(v4, name, type);
- }
+ // check for property.
+ bool ok;
+ const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, &ok);
+ if (hasProperty)
+ *hasProperty = ok;
+
+ // Warn when attempting to access a lowercased enum value, singleton case
+ if (!ok && includeEnums && !name->startsWithUpper()) {
+ enumForSingleton(v4, name, qobjectSingleton, type, &ok);
+ if (ok)
+ return throwLowercaseEnumError(v4, name, type);
+ }
- return result;
- } else if (!siinfo->scriptApi(e).isUndefined()) {
- // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
- QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e)));
- if (!!o)
- return o->get(name);
+ return result;
+ }
+ } else if (type.isQJSValueSingleton()) {
+ QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
+ if (!scriptSingleton.isUndefined()) {
+ // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
+ QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, scriptSingleton));
+ if (!!o)
+ return o->get(name);
+ }
}
// Fall through to base implementation
@@ -263,7 +260,9 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
// Fall through to base implementation
} else if (w->d()->object) {
- QObject *ao = qmlAttachedPropertiesObjectById(type.attachedPropertiesId(QQmlEnginePrivate::get(v4->qmlEngine())), object);
+ QObject *ao = qmlAttachedPropertiesObject(
+ object,
+ type.attachedPropertiesFunction(QQmlEnginePrivate::get(v4->qmlEngine())));
if (ao)
return QV4::QObjectWrapper::getQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty);
@@ -335,26 +334,28 @@ bool QQmlTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value,
if (type.isValid() && !type.isSingleton() && w->d()->object) {
QObject *object = w->d()->object;
QQmlEngine *e = scope.engine->qmlEngine();
- QObject *ao = qmlAttachedPropertiesObjectById(type.attachedPropertiesId(QQmlEnginePrivate::get(e)), object);
+ QObject *ao = qmlAttachedPropertiesObject(
+ object, type.attachedPropertiesFunction(QQmlEnginePrivate::get(e)));
if (ao)
return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value);
return false;
} else if (type.isSingleton()) {
- QQmlEngine *e = scope.engine->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
- siinfo->init(e);
-
- QObject *qobjectSingleton = siinfo->qobjectApi(e);
- if (qobjectSingleton) {
- return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value);
- } else if (!siinfo->scriptApi(e).isUndefined()) {
- QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(scope.engine, siinfo->scriptApi(e)));
- if (!apiprivate) {
- QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
- scope.engine->throwError(error);
- return false;
- } else {
- return apiprivate->put(name, value);
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(scope.engine->qmlEngine());
+ if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
+ if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type))
+ return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value);
+
+ } else {
+ QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
+ if (!scriptSingleton.isUndefined()) {
+ QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(scope.engine, scriptSingleton));
+ if (!apiprivate) {
+ QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
+ scope.engine->throwError(error);
+ return false;
+ } else {
+ return apiprivate->put(name, value);
+ }
}
}
}
@@ -446,27 +447,25 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
if (type.isValid()) {
if (type.isSingleton()) {
- QQmlEngine *e = engine->qmlEngine();
- QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
- siinfo->init(e);
-
- QObject *qobjectSingleton = siinfo->qobjectApi(e);
- if (qobjectSingleton) {
-
- const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
- if (!includeEnums || !name->startsWithUpper()) {
- QQmlData *ddata = QQmlData::get(qobjectSingleton, false);
- if (ddata && ddata->propertyCache) {
- ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton)));
- QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
- if (property) {
- lookup->qobjectLookup.ic = This->internalClass();
- lookup->qobjectLookup.staticQObject = static_cast<Heap::QObjectWrapper *>(val->heapObject());
- lookup->qobjectLookup.propertyCache = ddata->propertyCache;
- lookup->qobjectLookup.propertyCache->addref();
- lookup->qobjectLookup.propertyData = property;
- lookup->getter = QV4::QObjectWrapper::lookupGetter;
- return lookup->getter(lookup, engine, *This);
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine());
+ if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
+ if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
+ const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
+ if (!includeEnums || !name->startsWithUpper()) {
+ QQmlData *ddata = QQmlData::get(qobjectSingleton, false);
+ if (ddata && ddata->propertyCache) {
+ ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton)));
+ QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
+ if (property) {
+ lookup->qobjectLookup.ic = This->internalClass();
+ lookup->qobjectLookup.staticQObject = static_cast<Heap::QObjectWrapper *>(val->heapObject());
+ lookup->qobjectLookup.propertyCache = ddata->propertyCache;
+ lookup->qobjectLookup.propertyCache->addref();
+ lookup->qobjectLookup.propertyData = property;
+ lookup->getter = QV4::QObjectWrapper::lookupGetter;
+ return lookup->getter(lookup, engine, *This);
+ }
+ // Fall through to base implementation
}
// Fall through to base implementation
}
diff --git a/src/qml/qtqmlglobal.h b/src/qml/qtqmlglobal.h
index 090b830b3c..a111f72e81 100644
--- a/src/qml/qtqmlglobal.h
+++ b/src/qml/qtqmlglobal.h
@@ -53,7 +53,7 @@
#else
# define QT_FEATURE_qml_debug -1
# define QT_FEATURE_qml_sequence_object 1
-# define QT_FEATURE_qml_tracing -1
+# define QT_FEATURE_qml_jit -1
#endif
QT_BEGIN_NAMESPACE
diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri
index 5a56208dc4..ba11271d66 100644
--- a/src/qml/types/types.pri
+++ b/src/qml/types/types.pri
@@ -1,27 +1,12 @@
SOURCES += \
$$PWD/qqmlbind.cpp \
$$PWD/qqmlconnections.cpp \
- $$PWD/qqmlmodelsmodule.cpp \
- $$PWD/qqmlmodelindexvaluetype.cpp \
- $$PWD/qqmlobjectmodel.cpp \
- $$PWD/qquickpackage.cpp \
- $$PWD/qqmlinstantiator.cpp \
- $$PWD/qqmltableinstancemodel.cpp \
- $$PWD/qqmltablemodel.cpp \
- $$PWD/qqmltablemodelcolumn.cpp
+ $$PWD/qqmlmodelindexvaluetype.cpp
HEADERS += \
$$PWD/qqmlbind_p.h \
$$PWD/qqmlconnections_p.h \
- $$PWD/qqmlmodelsmodule_p.h \
- $$PWD/qqmlmodelindexvaluetype_p.h \
- $$PWD/qqmlobjectmodel_p.h \
- $$PWD/qquickpackage_p.h \
- $$PWD/qqmlinstantiator_p.h \
- $$PWD/qqmlinstantiator_p_p.h \
- $$PWD/qqmltableinstancemodel_p.h \
- $$PWD/qqmltablemodel_p.h \
- $$PWD/qqmltablemodelcolumn_p.h
+ $$PWD/qqmlmodelindexvaluetype_p.h
qtConfig(qml-worker-script) {
SOURCES += \
@@ -30,28 +15,6 @@ qtConfig(qml-worker-script) {
$$PWD/qquickworkerscript_p.h
}
-qtConfig(qml-list-model) {
- SOURCES += \
- $$PWD/qqmllistmodel.cpp \
- $$PWD/qqmllistmodelworkeragent.cpp
-
- HEADERS += \
- $$PWD/qqmllistmodel_p.h \
- $$PWD/qqmllistmodel_p_p.h \
- $$PWD/qqmllistmodelworkeragent_p.h
-}
-
-qtConfig(qml-delegate-model) {
- SOURCES += \
- $$PWD/qqmldelegatemodel.cpp \
- $$PWD/qqmldelegatecomponent.cpp
-
- HEADERS += \
- $$PWD/qqmldelegatemodel_p.h \
- $$PWD/qqmldelegatemodel_p_p.h \
- $$PWD/qqmldelegatecomponent_p.h
-}
-
qtConfig(qml-animation) {
SOURCES += \
$$PWD/qqmltimer.cpp
diff --git a/src/qml/util/util.pri b/src/qml/util/util.pri
index bebb271f1b..3b121ba3cb 100644
--- a/src/qml/util/util.pri
+++ b/src/qml/util/util.pri
@@ -1,19 +1,5 @@
SOURCES += \
- $$PWD/qqmlchangeset.cpp \
- $$PWD/qqmllistaccessor.cpp \
- $$PWD/qqmllistcompositor.cpp \
$$PWD/qqmlpropertymap.cpp
HEADERS += \
- $$PWD/qqmlchangeset_p.h \
- $$PWD/qqmllistaccessor_p.h \
- $$PWD/qqmllistcompositor_p.h \
$$PWD/qqmlpropertymap.h
-
-qtConfig(qml-delegate-model) {
- SOURCES += \
- $$PWD/qqmladaptormodel.cpp
-
- HEADERS += \
- $$PWD/qqmladaptormodel_p.h
-}
diff --git a/src/qmldebug/qqmlprofilerevent_p.h b/src/qmldebug/qqmlprofilerevent_p.h
index 1e205d8dbb..a7e37d1964 100644
--- a/src/qmldebug/qqmlprofilerevent_p.h
+++ b/src/qmldebug/qqmlprofilerevent_p.h
@@ -291,7 +291,7 @@ private:
squeeze(const Container &numbers)
{
typedef typename QIntegerForSize<sizeof(Number) / 2>::Signed Small;
- foreach (Number item, numbers) {
+ for (Number item : numbers) {
if (!squeezable<Number, Small>(item))
return false;
}
diff --git a/src/qmlmodels/configure.json b/src/qmlmodels/configure.json
new file mode 100644
index 0000000000..2aa8a50e69
--- /dev/null
+++ b/src/qmlmodels/configure.json
@@ -0,0 +1,31 @@
+{
+ "module": "qmlmodels",
+ "depends": [
+ "core-private",
+ "qml-private"
+ ],
+
+ "features": {
+ "qml-list-model": {
+ "label": "QML list model",
+ "purpose": "Provides the ListModel QML type.",
+ "section": "QML",
+ "output": [ "privateFeature" ]
+ },
+ "qml-delegate-model": {
+ "label": "QML delegate model",
+ "purpose": "Provides the DelegateModel QML type.",
+ "section": "QML",
+ "output": [ "privateFeature" ]
+ }
+ },
+ "summary": [
+ {
+ "section": "Qt QML Models",
+ "entries": [
+ "qml-list-model",
+ "qml-delegate-model"
+ ]
+ }
+ ]
+}
diff --git a/src/qmlmodels/qmlmodels.pro b/src/qmlmodels/qmlmodels.pro
new file mode 100644
index 0000000000..84f87f8bb1
--- /dev/null
+++ b/src/qmlmodels/qmlmodels.pro
@@ -0,0 +1,57 @@
+TARGET = QtQmlModels
+QT = core-private qml-private
+
+DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES QT_NO_FOREACH
+
+HEADERS += \
+ $$PWD/qqmlchangeset_p.h \
+ $$PWD/qqmlinstantiator_p.h \
+ $$PWD/qqmlinstantiator_p_p.h \
+ $$PWD/qqmllistaccessor_p.h \
+ $$PWD/qqmllistcompositor_p.h \
+ $$PWD/qqmlmodelsmodule_p.h \
+ $$PWD/qqmlobjectmodel_p.h \
+ $$PWD/qqmltableinstancemodel_p.h \
+ $$PWD/qqmltablemodel_p.h \
+ $$PWD/qqmltablemodelcolumn_p.h \
+ $$PWD/qquickpackage_p.h \
+ $$PWD/qtqmlmodelsglobal_p.h \
+ $$PWD/qtqmlmodelsglobal.h \
+
+SOURCES += \
+ $$PWD/qqmlchangeset.cpp \
+ $$PWD/qqmlinstantiator.cpp \
+ $$PWD/qqmllistaccessor.cpp \
+ $$PWD/qqmllistcompositor.cpp \
+ $$PWD/qqmlmodelsmodule.cpp \
+ $$PWD/qqmlobjectmodel.cpp \
+ $$PWD/qqmltableinstancemodel.cpp \
+ $$PWD/qqmltablemodel.cpp \
+ $$PWD/qqmltablemodelcolumn.cpp \
+ $$PWD/qquickpackage.cpp
+
+qtConfig(qml-list-model) {
+ SOURCES += \
+ $$PWD/qqmllistmodel.cpp \
+ $$PWD/qqmllistmodelworkeragent.cpp
+
+ HEADERS += \
+ $$PWD/qqmllistmodel_p.h \
+ $$PWD/qqmllistmodel_p_p.h \
+ $$PWD/qqmllistmodelworkeragent_p.h
+}
+
+qtConfig(qml-delegate-model) {
+ SOURCES += \
+ $$PWD/qqmladaptormodel.cpp \
+ $$PWD/qqmldelegatemodel.cpp \
+ $$PWD/qqmldelegatecomponent.cpp
+
+ HEADERS += \
+ $$PWD/qqmladaptormodel_p.h \
+ $$PWD/qqmldelegatemodel_p.h \
+ $$PWD/qqmldelegatemodel_p_p.h \
+ $$PWD/qqmldelegatecomponent_p.h
+}
+
+load(qt_module)
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qmlmodels/qqmladaptormodel.cpp
index f991ae0a69..f991ae0a69 100644
--- a/src/qml/util/qqmladaptormodel.cpp
+++ b/src/qmlmodels/qqmladaptormodel.cpp
diff --git a/src/qml/util/qqmladaptormodel_p.h b/src/qmlmodels/qqmladaptormodel_p.h
index 8c18466ab5..a4549127af 100644
--- a/src/qml/util/qqmladaptormodel_p.h
+++ b/src/qmlmodels/qqmladaptormodel_p.h
@@ -53,10 +53,12 @@
#include <QtCore/qabstractitemmodel.h>
-#include "private/qqmllistaccessor_p.h"
#include <private/qqmlglobal_p.h>
+#include <private/qqmllistaccessor_p.h>
+#include <private/qtqmlmodelsglobal_p.h>
#include <private/qqmlguard_p.h>
#include <private/qqmlnullablevalue_p.h>
+#include <private/qqmlpropertycache_p.h>
QT_REQUIRE_CONFIG(qml_delegate_model);
@@ -68,7 +70,7 @@ class QQmlDelegateModel;
class QQmlDelegateModelItem;
class QQmlDelegateModelItemMetaType;
-class Q_QML_PRIVATE_EXPORT QQmlAdaptorModel : public QQmlStrongJSQObjectReference<QObject>
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlAdaptorModel : public QQmlStrongJSQObjectReference<QObject>
{
public:
class Accessors
diff --git a/src/qml/util/qqmlchangeset.cpp b/src/qmlmodels/qqmlchangeset.cpp
index ba876b42e2..ba876b42e2 100644
--- a/src/qml/util/qqmlchangeset.cpp
+++ b/src/qmlmodels/qqmlchangeset.cpp
diff --git a/src/qml/util/qqmlchangeset_p.h b/src/qmlmodels/qqmlchangeset_p.h
index 8347a3ff19..5b44d2958c 100644
--- a/src/qml/util/qqmlchangeset_p.h
+++ b/src/qmlmodels/qqmlchangeset_p.h
@@ -53,11 +53,11 @@
#include <QtCore/qdebug.h>
#include <QtCore/qvector.h>
-#include <QtQml/private/qtqmlglobal_p.h>
+#include <QtQmlModels/private/qtqmlmodelsglobal_p.h>
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlChangeSet
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlChangeSet
{
public:
struct MoveKey
@@ -153,8 +153,8 @@ inline uint qHash(const QQmlChangeSet::MoveKey &key) { return qHash(qMakePair(ke
inline bool operator ==(const QQmlChangeSet::MoveKey &l, const QQmlChangeSet::MoveKey &r) {
return l.moveId == r.moveId && l.offset == r.offset; }
-Q_QML_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet::Change &change);
-Q_QML_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet &change);
+Q_QMLMODELS_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet::Change &change);
+Q_QMLMODELS_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet &change);
QT_END_NAMESPACE
diff --git a/src/qml/types/qqmldelegatecomponent.cpp b/src/qmlmodels/qqmldelegatecomponent.cpp
index 470f6cab6a..a7e9536917 100644
--- a/src/qml/types/qqmldelegatecomponent.cpp
+++ b/src/qmlmodels/qqmldelegatecomponent.cpp
@@ -38,7 +38,7 @@
****************************************************************************/
#include "qqmldelegatecomponent_p.h"
-#include <QtQml/private/qqmladaptormodel_p.h>
+#include <QtQmlModels/private/qqmladaptormodel_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/types/qqmldelegatecomponent_p.h b/src/qmlmodels/qqmldelegatecomponent_p.h
index c925ed9a60..1d20f0327b 100644
--- a/src/qml/types/qqmldelegatecomponent_p.h
+++ b/src/qmlmodels/qqmldelegatecomponent_p.h
@@ -51,7 +51,7 @@
// We mean it.
//
-#include <private/qtqmlglobal_p.h>
+#include <private/qtqmlmodelsglobal_p.h>
#include <qqmlcomponent.h>
QT_REQUIRE_CONFIG(qml_delegate_model);
@@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE
// TODO: consider making QQmlAbstractDelegateComponent public API
class QQmlAbstractDelegateComponentPrivate;
class QQmlAdaptorModel;
-class Q_QML_PRIVATE_EXPORT QQmlAbstractDelegateComponent : public QQmlComponent
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlAbstractDelegateComponent : public QQmlComponent
{
Q_OBJECT
public:
@@ -81,7 +81,7 @@ private:
Q_DISABLE_COPY(QQmlAbstractDelegateComponent)
};
-class Q_QML_PRIVATE_EXPORT QQmlDelegateChoice : public QObject
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateChoice : public QObject
{
Q_OBJECT
Q_PROPERTY(QVariant roleValue READ roleValue WRITE setRoleValue NOTIFY roleValueChanged)
@@ -120,7 +120,7 @@ private:
QQmlComponent *m_delegate = nullptr;
};
-class Q_QML_PRIVATE_EXPORT QQmlDelegateChooser : public QQmlAbstractDelegateComponent
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateChooser : public QQmlAbstractDelegateComponent
{
Q_OBJECT
Q_PROPERTY(QString role READ role WRITE setRole NOTIFY roleChanged)
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
index 0e57119368..742c164508 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
@@ -52,7 +52,7 @@
#include <private/qv4value_p.h>
#include <private/qv4functionobject_p.h>
-#include <qv4objectiterator_p.h>
+#include <private/qv4objectiterator_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qmlmodels/qqmldelegatemodel_p.h
index 2684162514..21eaef02e0 100644
--- a/src/qml/types/qqmldelegatemodel_p.h
+++ b/src/qmlmodels/qqmldelegatemodel_p.h
@@ -51,7 +51,7 @@
// We mean it.
//
-#include <private/qtqmlglobal_p.h>
+#include <private/qtqmlmodelsglobal_p.h>
#include <private/qqmllistcompositor_p.h>
#include <private/qqmlobjectmodel_p.h>
#include <private/qqmlincubator_p.h>
@@ -59,8 +59,6 @@
#include <QtCore/qabstractitemmodel.h>
#include <QtCore/qstringlist.h>
-#include <private/qqmlglobal_p.h>
-
QT_REQUIRE_CONFIG(qml_delegate_model);
QT_BEGIN_NAMESPACE
@@ -73,7 +71,7 @@ class QQmlDelegateModelAttached;
class QQmlDelegateModelPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlDelegateModel : public QQmlInstanceModel, public QQmlParserStatus
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateModel : public QQmlInstanceModel, public QQmlParserStatus
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlDelegateModel)
@@ -159,7 +157,7 @@ private:
};
class QQmlDelegateModelGroupPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlDelegateModelGroup : public QObject
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateModelGroup : public QObject
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qmlmodels/qqmldelegatemodel_p_p.h
index 7f10bbf370..92362b8876 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qmlmodels/qqmldelegatemodel_p_p.h
@@ -69,7 +69,7 @@ typedef QQmlListCompositor Compositor;
class QQmlDelegateModelAttachedMetaObject;
class QQmlAbstractDelegateComponent;
-class Q_QML_PRIVATE_EXPORT QQmlDelegateModelItemMetaType : public QQmlRefCount
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateModelItemMetaType : public QQmlRefCount
{
public:
QQmlDelegateModelItemMetaType(QV4::ExecutionEngine *engine, QQmlDelegateModel *model, const QStringList &groupNames);
diff --git a/src/qml/types/qqmlinstantiator.cpp b/src/qmlmodels/qqmlinstantiator.cpp
index a23ec0f2b4..af1b526e1d 100644
--- a/src/qml/types/qqmlinstantiator.cpp
+++ b/src/qmlmodels/qqmlinstantiator.cpp
@@ -43,9 +43,9 @@
#include <QtQml/QQmlComponent>
#include <QtQml/QQmlInfo>
#include <QtQml/QQmlError>
-#include <QtQml/private/qqmlobjectmodel_p.h>
+#include <QtQmlModels/private/qqmlobjectmodel_p.h>
#if QT_CONFIG(qml_delegate_model)
-#include <QtQml/private/qqmldelegatemodel_p.h>
+#include <QtQmlModels/private/qqmldelegatemodel_p.h>
#endif
QT_BEGIN_NAMESPACE
diff --git a/src/qml/types/qqmlinstantiator_p.h b/src/qmlmodels/qqmlinstantiator_p.h
index ca371adc23..8b00a1e033 100644
--- a/src/qml/types/qqmlinstantiator_p.h
+++ b/src/qmlmodels/qqmlinstantiator_p.h
@@ -53,12 +53,12 @@
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlparserstatus.h>
-#include <QtQml/private/qtqmlglobal_p.h>
+#include <QtQmlModels/private/qtqmlmodelsglobal_p.h>
QT_BEGIN_NAMESPACE
class QQmlInstantiatorPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlInstantiator : public QObject, public QQmlParserStatus
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlInstantiator : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
diff --git a/src/qml/types/qqmlinstantiator_p_p.h b/src/qmlmodels/qqmlinstantiator_p_p.h
index 4c76d5c689..bf153d8723 100644
--- a/src/qml/types/qqmlinstantiator_p_p.h
+++ b/src/qmlmodels/qqmlinstantiator_p_p.h
@@ -59,7 +59,7 @@
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlInstantiatorPrivate : public QObjectPrivate
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlInstantiatorPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QQmlInstantiator)
diff --git a/src/qml/types/qqmlitemmodels.qdoc b/src/qmlmodels/qqmlitemmodels.qdoc
index f6e1b0b1b9..f6e1b0b1b9 100644
--- a/src/qml/types/qqmlitemmodels.qdoc
+++ b/src/qmlmodels/qqmlitemmodels.qdoc
diff --git a/src/qml/types/qqmlitemselectionmodel.qdoc b/src/qmlmodels/qqmlitemselectionmodel.qdoc
index 43da4f7a55..43da4f7a55 100644
--- a/src/qml/types/qqmlitemselectionmodel.qdoc
+++ b/src/qmlmodels/qqmlitemselectionmodel.qdoc
diff --git a/src/qml/util/qqmllistaccessor.cpp b/src/qmlmodels/qqmllistaccessor.cpp
index 46a11e2bc2..46a11e2bc2 100644
--- a/src/qml/util/qqmllistaccessor.cpp
+++ b/src/qmlmodels/qqmllistaccessor.cpp
diff --git a/src/qml/util/qqmllistaccessor_p.h b/src/qmlmodels/qqmllistaccessor_p.h
index bcd079adef..bcd079adef 100644
--- a/src/qml/util/qqmllistaccessor_p.h
+++ b/src/qmlmodels/qqmllistaccessor_p.h
diff --git a/src/qml/util/qqmllistcompositor.cpp b/src/qmlmodels/qqmllistcompositor.cpp
index 921e86f355..921e86f355 100644
--- a/src/qml/util/qqmllistcompositor.cpp
+++ b/src/qmlmodels/qqmllistcompositor.cpp
diff --git a/src/qml/util/qqmllistcompositor_p.h b/src/qmlmodels/qqmllistcompositor_p.h
index 172040559c..172040559c 100644
--- a/src/qml/util/qqmllistcompositor_p.h
+++ b/src/qmlmodels/qqmllistcompositor_p.h
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qmlmodels/qqmllistmodel.cpp
index 5b5bcd8464..5b5bcd8464 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qmlmodels/qqmllistmodel.cpp
diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qmlmodels/qqmllistmodel_p.h
index 471e33aa5a..4aabd790a5 100644
--- a/src/qml/types/qqmllistmodel_p.h
+++ b/src/qmlmodels/qqmllistmodel_p.h
@@ -51,7 +51,7 @@
// We mean it.
//
-#include <qqml.h>
+#include <private/qtqmlmodelsglobal_p.h>
#include <private/qqmlcustomparser_p.h>
#include <QtCore/QObject>
@@ -77,11 +77,12 @@ namespace QV4 {
struct ModelObject;
}
-class Q_QML_PRIVATE_EXPORT QQmlListModel : public QAbstractListModel
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlListModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(bool dynamicRoles READ dynamicRoles WRITE setDynamicRoles)
+ Q_PROPERTY(QObject *agent READ agent CONSTANT REVISION(14))
public:
QQmlListModel(QObject *parent=nullptr);
@@ -134,7 +135,7 @@ private:
inline bool canMove(int from, int to, int n) const { return !(from+n > count() || to+n > count() || from < 0 || to < 0 || n < 0); }
- QQmlListModelWorkerAgent *m_agent;
+ mutable QQmlListModelWorkerAgent *m_agent;
mutable QV4::ExecutionEngine *m_engine;
QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compilationUnit;
bool m_mainThread;
diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qmlmodels/qqmllistmodel_p_p.h
index 2876c71de6..a0d0e9ad89 100644
--- a/src/qml/types/qqmllistmodel_p_p.h
+++ b/src/qmlmodels/qqmllistmodel_p_p.h
@@ -52,6 +52,7 @@
//
#include "qqmllistmodel_p.h"
+#include <private/qtqmlmodelsglobal_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlopenmetaobject_p.h>
#include <private/qv4qobjectwrapper_p.h>
diff --git a/src/qml/types/qqmllistmodelworkeragent.cpp b/src/qmlmodels/qqmllistmodelworkeragent.cpp
index f7cb08dcf4..7e92810f78 100644
--- a/src/qml/types/qqmllistmodelworkeragent.cpp
+++ b/src/qmlmodels/qqmllistmodelworkeragent.cpp
@@ -66,9 +66,17 @@ QQmlListModelWorkerAgent::~QQmlListModelWorkerAgent()
mutex.unlock();
}
+QV4::ExecutionEngine *QQmlListModelWorkerAgent::engine() const
+{
+ return m_copy->m_engine;
+}
+
void QQmlListModelWorkerAgent::setEngine(QV4::ExecutionEngine *eng)
{
- m_copy->m_engine = eng;
+ if (eng != m_copy->m_engine) {
+ m_copy->m_engine = eng;
+ emit engineChanged(eng);
+ }
}
void QQmlListModelWorkerAgent::addref()
diff --git a/src/qml/types/qqmllistmodelworkeragent_p.h b/src/qmlmodels/qqmllistmodelworkeragent_p.h
index 69d1785618..f79c0c557a 100644
--- a/src/qml/types/qqmllistmodelworkeragent_p.h
+++ b/src/qmlmodels/qqmllistmodelworkeragent_p.h
@@ -51,7 +51,7 @@
// We mean it.
//
-#include <qqml.h>
+#include <qtqmlmodelsglobal_p.h>
#include <QEvent>
#include <QMutex>
@@ -70,14 +70,17 @@ class QQmlListModelWorkerAgent : public QObject
{
Q_OBJECT
Q_PROPERTY(int count READ count)
+ Q_PROPERTY(QV4::ExecutionEngine *engine READ engine WRITE setEngine NOTIFY engineChanged)
public:
QQmlListModelWorkerAgent(QQmlListModel *);
~QQmlListModelWorkerAgent();
+
+ QV4::ExecutionEngine *engine() const;
void setEngine(QV4::ExecutionEngine *eng);
- void addref();
- void release();
+ Q_INVOKABLE void addref();
+ Q_INVOKABLE void release();
int count() const;
@@ -91,24 +94,11 @@ public:
Q_INVOKABLE void move(int from, int to, int count);
Q_INVOKABLE void sync();
- struct VariantRef
- {
- VariantRef() : a(nullptr) {}
- VariantRef(const VariantRef &r) : a(r.a) { if (a) a->addref(); }
- VariantRef(QQmlListModelWorkerAgent *_a) : a(_a) { if (a) a->addref(); }
- ~VariantRef() { if (a) a->release(); }
-
- VariantRef &operator=(const VariantRef &o) {
- if (o.a) o.a->addref();
- if (a) a->release();
- a = o.a;
- return *this;
- }
-
- QQmlListModelWorkerAgent *a;
- };
-
void modelDestroyed();
+
+signals:
+ void engineChanged(QV4::ExecutionEngine *engine);
+
protected:
bool event(QEvent *) override;
@@ -134,7 +124,5 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QQmlListModelWorkerAgent::VariantRef)
-
#endif // QQUICKLISTMODELWORKERAGENT_P_H
diff --git a/src/qml/types/qqmlmodelsmodule.cpp b/src/qmlmodels/qqmlmodelsmodule.cpp
index 840b435d18..989fec9b7d 100644
--- a/src/qml/types/qqmlmodelsmodule.cpp
+++ b/src/qmlmodels/qqmlmodelsmodule.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qqmlmodelsmodule_p.h"
+#include <private/qtqmlmodelsglobal_p.h>
#include <QtCore/qitemselectionmodel.h>
#if QT_CONFIG(qml_list_model)
#include <private/qqmllistmodel_p.h>
diff --git a/src/qml/types/qqmlmodelsmodule_p.h b/src/qmlmodels/qqmlmodelsmodule_p.h
index 2bb04f1e11..7e02578db9 100644
--- a/src/qml/types/qqmlmodelsmodule_p.h
+++ b/src/qmlmodels/qqmlmodelsmodule_p.h
@@ -51,11 +51,11 @@
// We mean it.
//
-#include <private/qtqmlglobal_p.h>
+#include <private/qtqmlmodelsglobal_p.h>
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlModelsModule
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlModelsModule
{
public:
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qmlmodels/qqmlobjectmodel.cpp
index b6330b4295..b6330b4295 100644
--- a/src/qml/types/qqmlobjectmodel.cpp
+++ b/src/qmlmodels/qqmlobjectmodel.cpp
diff --git a/src/qml/types/qqmlobjectmodel_p.h b/src/qmlmodels/qqmlobjectmodel_p.h
index 1284ba1780..99bfd86269 100644
--- a/src/qml/types/qqmlobjectmodel_p.h
+++ b/src/qmlmodels/qqmlobjectmodel_p.h
@@ -51,7 +51,7 @@
// We mean it.
//
-#include <private/qtqmlglobal_p.h>
+#include <private/qtqmlmodelsglobal_p.h>
#include <private/qqmlincubator_p.h>
#include <QtQml/qqml.h>
#include <QtCore/qobject.h>
@@ -62,7 +62,7 @@ class QObject;
class QQmlChangeSet;
class QAbstractItemModel;
-class Q_QML_PRIVATE_EXPORT QQmlInstanceModel : public QObject
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlInstanceModel : public QObject
{
Q_OBJECT
@@ -104,7 +104,7 @@ private:
class QQmlObjectModelAttached;
class QQmlObjectModelPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlObjectModel : public QQmlInstanceModel
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlObjectModel : public QQmlInstanceModel
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlObjectModel)
diff --git a/src/qml/types/qqmltableinstancemodel.cpp b/src/qmlmodels/qqmltableinstancemodel.cpp
index 2170e2daec..b244a007e5 100644
--- a/src/qml/types/qqmltableinstancemodel.cpp
+++ b/src/qmlmodels/qqmltableinstancemodel.cpp
@@ -43,7 +43,7 @@
#include <QtCore/QTimer>
#include <QtQml/private/qqmlincubator_p.h>
-#include <QtQml/private/qqmlchangeset_p.h>
+#include <QtQmlModels/private/qqmlchangeset_p.h>
#include <QtQml/private/qqmlcomponent_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/types/qqmltableinstancemodel_p.h b/src/qmlmodels/qqmltableinstancemodel_p.h
index 39ec66d136..20331df5cc 100644
--- a/src/qml/types/qqmltableinstancemodel_p.h
+++ b/src/qmlmodels/qqmltableinstancemodel_p.h
@@ -51,8 +51,8 @@
// We mean it.
//
-#include <QtQml/private/qqmldelegatemodel_p.h>
-#include <QtQml/private/qqmldelegatemodel_p_p.h>
+#include <QtQmlModels/private/qqmldelegatemodel_p.h>
+#include <QtQmlModels/private/qqmldelegatemodel_p_p.h>
QT_BEGIN_NAMESPACE
@@ -79,7 +79,7 @@ public:
QQmlTableInstanceModel *tableInstanceModel = nullptr;
};
-class Q_QML_PRIVATE_EXPORT QQmlTableInstanceModel : public QQmlInstanceModel
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlTableInstanceModel : public QQmlInstanceModel
{
Q_OBJECT
diff --git a/src/qml/types/qqmltablemodel.cpp b/src/qmlmodels/qqmltablemodel.cpp
index 4a96e7a46b..4a96e7a46b 100644
--- a/src/qml/types/qqmltablemodel.cpp
+++ b/src/qmlmodels/qqmltablemodel.cpp
diff --git a/src/qml/types/qqmltablemodel_p.h b/src/qmlmodels/qqmltablemodel_p.h
index a1bb97e7d4..114b162e5c 100644
--- a/src/qml/types/qqmltablemodel_p.h
+++ b/src/qmlmodels/qqmltablemodel_p.h
@@ -54,14 +54,14 @@
#include <QtCore/QObject>
#include <QtCore/QAbstractTableModel>
#include <QtQml/qqml.h>
-#include <QtQml/private/qtqmlglobal_p.h>
-#include <QtQml/private/qqmltablemodelcolumn_p.h>
+#include <QtQmlModels/private/qtqmlmodelsglobal_p.h>
+#include <QtQmlModels/private/qqmltablemodelcolumn_p.h>
#include <QtQml/QJSValue>
#include <QtQml/QQmlListProperty>
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlTableModel : public QAbstractTableModel, public QQmlParserStatus
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlTableModel : public QAbstractTableModel, public QQmlParserStatus
{
Q_OBJECT
Q_PROPERTY(int columnCount READ columnCount NOTIFY columnCountChanged FINAL)
diff --git a/src/qml/types/qqmltablemodelcolumn.cpp b/src/qmlmodels/qqmltablemodelcolumn.cpp
index 93da0642de..93da0642de 100644
--- a/src/qml/types/qqmltablemodelcolumn.cpp
+++ b/src/qmlmodels/qqmltablemodelcolumn.cpp
diff --git a/src/qml/types/qqmltablemodelcolumn_p.h b/src/qmlmodels/qqmltablemodelcolumn_p.h
index 41c02482c0..d125f8bb16 100644
--- a/src/qml/types/qqmltablemodelcolumn_p.h
+++ b/src/qmlmodels/qqmltablemodelcolumn_p.h
@@ -53,12 +53,12 @@
#include <QtCore/QObject>
#include <QtQml/qqml.h>
-#include <QtQml/private/qtqmlglobal_p.h>
+#include <QtQmlModels/private/qtqmlmodelsglobal_p.h>
#include <QtQml/qjsvalue.h>
QT_BEGIN_NAMESPACE
-class Q_QML_AUTOTEST_EXPORT QQmlTableModelColumn : public QObject
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlTableModelColumn : public QObject
{
Q_OBJECT
Q_PROPERTY(QJSValue display READ display WRITE setDisplay NOTIFY displayChanged FINAL)
diff --git a/src/qml/types/qquickpackage.cpp b/src/qmlmodels/qquickpackage.cpp
index 03539d8737..03539d8737 100644
--- a/src/qml/types/qquickpackage.cpp
+++ b/src/qmlmodels/qquickpackage.cpp
diff --git a/src/qml/types/qquickpackage_p.h b/src/qmlmodels/qquickpackage_p.h
index 122c7fcb30..122c7fcb30 100644
--- a/src/qml/types/qquickpackage_p.h
+++ b/src/qmlmodels/qquickpackage_p.h
diff --git a/src/qmlmodels/qtqmlmodelsglobal.h b/src/qmlmodels/qtqmlmodelsglobal.h
new file mode 100644
index 0000000000..6e6cf299b2
--- /dev/null
+++ b/src/qmlmodels/qtqmlmodelsglobal.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $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 QTQMLMODELSGLOBAL_H
+#define QTQMLMODELSGLOBAL_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtQmlModels/qtqmlmodels-config.h>
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(QT_STATIC)
+# if defined(QT_BUILD_QMLMODELS_LIB)
+# define Q_QMLMODELS_EXPORT Q_DECL_EXPORT
+# else
+# define Q_QMLMODELS_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define Q_QMLMODELS_EXPORT
+#endif
+
+QT_END_NAMESPACE
+#endif // QTQMLMODELSGLOBAL_H
diff --git a/src/qmlmodels/qtqmlmodelsglobal_p.h b/src/qmlmodels/qtqmlmodelsglobal_p.h
new file mode 100644
index 0000000000..145112c9c1
--- /dev/null
+++ b/src/qmlmodels/qtqmlmodelsglobal_p.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $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 QTQMLMODELSGLOBAL_P_H
+#define QTQMLMODELSGLOBAL_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 <QtQml/private/qtqmlglobal_p.h>
+#include <QtQmlModels/qtqmlmodelsglobal.h>
+#include <QtQmlModels/private/qtqmlmodels-config_p.h>
+
+#define Q_QMLMODELS_PRIVATE_EXPORT Q_QMLMODELS_EXPORT
+#define Q_QMLMODELS_AUTOTEST_EXPORT Q_AUTOTEST_EXPORT
+
+#endif // QTQMLMODELSGLOBAL_P_H
diff --git a/src/quick/configure.json b/src/quick/configure.json
index 9ec3531ef4..70fe6d2129 100644
--- a/src/quick/configure.json
+++ b/src/quick/configure.json
@@ -2,7 +2,8 @@
"module": "quick",
"depends": [
"qml-private",
- "gui-private"
+ "gui-private",
+ "qmlmodels-private"
],
"testDir": "../../config.tests",
diff --git a/src/quick/doc/snippets/pointerHandlers/handlerFlick.qml b/src/quick/doc/snippets/pointerHandlers/handlerFlick.qml
new file mode 100644
index 0000000000..f74b075357
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/handlerFlick.qml
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.14
+import Qt.labs.animation 1.0
+
+Item {
+ width: 320; height: 480
+ Flow {
+ id: content
+ width: parent.width
+ spacing: 2; padding: 2
+
+ WheelHandler {
+ orientation: Qt.Vertical
+ property: "y"
+ rotationScale: 15
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
+ onActiveChanged: if (!active) ybr.returnToBounds()
+ }
+
+ DragHandler {
+ xAxis.enabled: false
+ onActiveChanged: if (!active) ybr.returnToBounds()
+ }
+
+ BoundaryRule on y {
+ id: ybr
+ minimum: content.parent.height - content.height
+ maximum: 0
+ minimumOvershoot: 400; maximumOvershoot: 400
+ overshootFilter: BoundaryRule.Peak
+ }
+
+ Repeater {
+ model: 1000
+ Rectangle { color: "gray"; width: 10 + Math.random() * 100; height: 15 }
+ }
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/wheelHandler.qml b/src/quick/doc/snippets/pointerHandlers/wheelHandler.qml
new file mode 100644
index 0000000000..2c9913ac97
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/wheelHandler.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.14
+
+Rectangle {
+ width: 170; height: 120
+ color: "green"; antialiasing: true
+
+ WheelHandler {
+ property: "rotation"
+ onWheel: console.log("rotation", event.angleDelta.y,
+ "scaled", rotation, "@", point.position, "=>", parent.rotation)
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/qml/boundaryRule.qml b/src/quick/doc/snippets/qml/boundaryRule.qml
new file mode 100644
index 0000000000..c010f5de5e
--- /dev/null
+++ b/src/quick/doc/snippets/qml/boundaryRule.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.14
+import Qt.labs.animation 1.0
+
+Rectangle {
+ id: root
+ width: 170; height: 120
+ color: "green"
+
+ DragHandler {
+ id: dragHandler
+ yAxis.minimum: -1000
+ xAxis.minimum: -1000
+ onActiveChanged: if (!active) xbr.returnToBounds();
+ }
+
+ BoundaryRule on x {
+ id: xbr
+ minimum: -50
+ maximum: 100
+ minimumOvershoot: 40
+ maximumOvershoot: 40
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/qml/tableview/tablemodel.cpp b/src/quick/doc/snippets/qml/tableview/cpp-tablemodel.cpp
index ea9f76f131..ea9f76f131 100644
--- a/src/quick/doc/snippets/qml/tableview/tablemodel.cpp
+++ b/src/quick/doc/snippets/qml/tableview/cpp-tablemodel.cpp
diff --git a/src/quick/doc/snippets/qml/tableview/tablemodel.qml b/src/quick/doc/snippets/qml/tableview/cpp-tablemodel.qml
index 8a8ec94958..8a8ec94958 100644
--- a/src/quick/doc/snippets/qml/tableview/tablemodel.qml
+++ b/src/quick/doc/snippets/qml/tableview/cpp-tablemodel.qml
diff --git a/src/quick/doc/snippets/qml/tableview/qml-tablemodel.qml b/src/quick/doc/snippets/qml/tableview/qml-tablemodel.qml
new file mode 100644
index 0000000000..a01a2a628a
--- /dev/null
+++ b/src/quick/doc/snippets/qml/tableview/qml-tablemodel.qml
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//![0]
+import QtQuick 2.14
+import Qt.labs.qmlmodels 1.0
+
+TableView {
+ anchors.fill: parent
+ columnSpacing: 1
+ rowSpacing: 1
+ clip: true
+
+ model: TableModel {
+ TableModelColumn { display: "name" }
+ TableModelColumn { display: "color" }
+
+ rows: [
+ {
+ "name": "cat",
+ "color": "black"
+ },
+ {
+ "name": "dog",
+ "color": "brown"
+ },
+ {
+ "name": "bird",
+ "color": "white"
+ }
+ ]
+ }
+
+ delegate: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 50
+ border.width: 1
+
+ Text {
+ text: display
+ anchors.centerIn: parent
+ }
+ }
+}
+//![0]
diff --git a/src/quick/handlers/handlers.pri b/src/quick/handlers/handlers.pri
index fa2f25c793..49975bd1ca 100644
--- a/src/quick/handlers/handlers.pri
+++ b/src/quick/handlers/handlers.pri
@@ -27,3 +27,9 @@ SOURCES += \
$$PWD/qquicksinglepointhandler.cpp \
$$PWD/qquicktaphandler.cpp \
$$PWD/qquickdragaxis.cpp
+
+qtConfig(wheelevent) {
+ HEADERS += $$PWD/qquickwheelhandler_p.h $$PWD/qquickwheelhandler_p_p.h
+ SOURCES += $$PWD/qquickwheelhandler.cpp
+}
+
diff --git a/src/quick/handlers/qquickmultipointhandler.cpp b/src/quick/handlers/qquickmultipointhandler.cpp
index 5c10ecce75..0afc9997aa 100644
--- a/src/quick/handlers/qquickmultipointhandler.cpp
+++ b/src/quick/handlers/qquickmultipointhandler.cpp
@@ -70,14 +70,15 @@ bool QQuickMultiPointHandler::wantsPointerEvent(QQuickPointerEvent *event)
if (!QQuickPointerDeviceHandler::wantsPointerEvent(event))
return false;
-#if QT_CONFIG(gestures)
- if (event->asPointerNativeGestureEvent())
- return true;
-#endif
-
if (event->asPointerScrollEvent())
return false;
+ bool ret = false;
+#if QT_CONFIG(gestures)
+ if (event->asPointerNativeGestureEvent() && event->point(0)->state() != QQuickEventPoint::Released)
+ ret = true;
+#endif
+
// If points were pressed or released within parentItem, reset stored state
// and check eligible points again. This class of handlers is intended to
// handle a specific number of points, so a differing number of points will
@@ -97,7 +98,7 @@ bool QQuickMultiPointHandler::wantsPointerEvent(QQuickPointerEvent *event)
return true;
}
- const bool ret = (candidatePoints.size() >= minimumPointCount() && candidatePoints.size() <= maximumPointCount());
+ ret = ret || (candidatePoints.size() >= minimumPointCount() && candidatePoints.size() <= maximumPointCount());
if (ret) {
const int c = candidatePoints.count();
d->currentPoints.resize(c);
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp
index 4025cd7fbf..a5a867015c 100644
--- a/src/quick/handlers/qquickpinchhandler.cpp
+++ b/src/quick/handlers/qquickpinchhandler.cpp
@@ -279,9 +279,9 @@ void QQuickPinchHandler::onActiveChanged()
m_startScale = m_accumulatedScale;
m_startRotation = 0;
}
- qCInfo(lcPinchHandler) << "activated with starting scale" << m_startScale << "rotation" << m_startRotation;
+ qCDebug(lcPinchHandler) << "activated with starting scale" << m_startScale << "rotation" << m_startRotation;
} else {
- qCInfo(lcPinchHandler) << "deactivated with scale" << m_activeScale << "rotation" << m_activeRotation;
+ qCDebug(lcPinchHandler) << "deactivated with scale" << m_activeScale << "rotation" << m_activeRotation;
}
}
diff --git a/src/quick/handlers/qquickwheelhandler.cpp b/src/quick/handlers/qquickwheelhandler.cpp
new file mode 100644
index 0000000000..90e4fef97e
--- /dev/null
+++ b/src/quick/handlers/qquickwheelhandler.cpp
@@ -0,0 +1,520 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "qquickwheelhandler_p.h"
+#include "qquickwheelhandler_p_p.h"
+#include <QLoggingCategory>
+#include <QtMath>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcWheelHandler, "qt.quick.handler.wheel")
+
+/*!
+ \qmltype WheelHandler
+ \instantiates QQuickWheelHandler
+ \inqmlmodule QtQuick
+ \ingroup qtquick-input-handlers
+ \brief Handler for the mouse wheel.
+
+ WheelHandler is a handler that is used to interactively manipulate some
+ numeric property of an Item as the user rotates the mouse wheel. Like other
+ Input Handlers, by default it manipulates its \l {PointerHandler::target}
+ {target}. Declare \l property to control which target property will be
+ manipulated:
+
+ \snippet pointerHandlers/wheelHandler.qml 0
+
+ \l BoundaryRule is quite useful in combination with WheelHandler (as well
+ as with other Input Handlers) to declare the allowed range of values that
+ the target property can have. For example it is possible to implement
+ scrolling using a combination of WheelHandler and \l DragHandler to
+ manipulate the scrollable Item's \l{QQuickItem::y}{y} property when the
+ user rotates the wheel or drags the item on a touchscreen, and
+ \l BoundaryRule to limit the range of motion from the top to the bottom:
+
+ \snippet pointerHandlers/handlerFlick.qml 0
+
+ Alternatively if \l targetProperty is not set or \l target is null,
+ WheelHandler will not automatically manipulate anything; but the
+ \l rotation property can be used in a binding to manipulate another
+ property, or you can implement \c onWheel and handle the wheel event
+ directly.
+
+ WheelHandler handles only a rotating mouse wheel by default.
+ Optionally it can handle smooth-scrolling events from touchpad gestures,
+ by setting \l acceptedDevices to \c{PointerDevice.Mouse | PointerDevice.TouchPad}.
+
+ \note Some non-mouse hardware (such as a touch-sensitive Wacom tablet, or
+ a Linux laptop touchpad) generates real wheel events from gestures.
+ WheelHandler will respond to those events as wheel events regardless of the
+ setting of the \l acceptedDevices property.
+
+ \sa MouseArea
+ \sa Flickable
+*/
+
+QQuickWheelHandler::QQuickWheelHandler(QQuickItem *parent)
+ : QQuickSinglePointHandler(*(new QQuickWheelHandlerPrivate), parent)
+{
+ setAcceptedDevices(QQuickPointerDevice::Mouse);
+}
+
+/*!
+ \qmlproperty enum QtQuick::WheelHandler::orientation
+
+ Which wheel to react to. The default is \c Qt.Vertical.
+
+ Not every mouse has a \c Horizontal wheel; sometimes it is emulated by
+ tilting the wheel sideways. A touchpad can usually generate both vertical
+ and horizontal wheel events.
+*/
+Qt::Orientation QQuickWheelHandler::orientation() const
+{
+ Q_D(const QQuickWheelHandler);
+ return d->orientation;
+}
+
+void QQuickWheelHandler::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QQuickWheelHandler);
+ if (d->orientation == orientation)
+ return;
+
+ d->orientation = orientation;
+ emit orientationChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick::WheelHandler::invertible
+
+ Whether or not to reverse the direction of property change if
+ \l QQuickPointerScrollEvent::inverted is true. The default is \c true.
+
+ If the operating system has a "natural scrolling" setting that causes
+ scrolling to be in the same direction as the finger movement, then if this
+ property is set to \c true, and WheelHandler is directly setting a property
+ on \l target, the direction of movement will correspond to the system setting.
+ If this property is set to \l false, it will invert the \l rotation so that
+ the direction of motion is always the same as the direction of finger movement.
+*/
+bool QQuickWheelHandler::isInvertible() const
+{
+ Q_D(const QQuickWheelHandler);
+ return d->invertible;
+}
+
+void QQuickWheelHandler::setInvertible(bool invertible)
+{
+ Q_D(QQuickWheelHandler);
+ if (d->invertible == invertible)
+ return;
+
+ d->invertible = invertible;
+ emit invertibleChanged();
+}
+
+/*!
+ \qmlproperty real QtQuick::WheelHandler::activeTimeout
+
+ The amount of time in seconds after which the \l active property will
+ revert to \c false if no more wheel events are received. The default is
+ \c 0.1 (100 ms).
+
+ When WheelHandler handles events that contain
+ \l {Qt::ScrollPhase}{scroll phase} information, such as events from some
+ touchpads, the \l active property will become \c false as soon as an event
+ with phase \l Qt::ScrollEnd is received; in that case the timeout is not
+ necessary. But a conventional mouse with a wheel does not provide the
+ \l {QQuickPointerScrollEvent::phase}{scroll phase}: the mouse cannot detect
+ when the user has decided to stop scrolling, so the \l active property
+ transitions to \c false after this much time has elapsed.
+*/
+qreal QQuickWheelHandler::activeTimeout() const
+{
+ Q_D(const QQuickWheelHandler);
+ return d->activeTimeout;
+}
+
+void QQuickWheelHandler::setActiveTimeout(qreal timeout)
+{
+ Q_D(QQuickWheelHandler);
+ if (qFuzzyCompare(d->activeTimeout, timeout))
+ return;
+
+ if (timeout < 0) {
+ qWarning("activeTimeout must be positive");
+ return;
+ }
+
+ d->activeTimeout = timeout;
+ emit activeTimeoutChanged();
+}
+
+/*!
+ \qmlproperty real QtQuick::WheelHandler::rotation
+
+ The angle through which the mouse wheel has been rotated since the last
+ time this property was set, in wheel degrees.
+
+ A positive value indicates that the wheel was rotated up/right;
+ a negative value indicates that the wheel was rotated down/left.
+
+ A basic mouse click-wheel works in steps of 15 degrees.
+
+ The default is \c 0 at startup. It can be programmatically set to any value
+ at any time. The value will be adjusted from there as the user rotates the
+ mouse wheel.
+
+ \sa orientation
+*/
+qreal QQuickWheelHandler::rotation() const
+{
+ Q_D(const QQuickWheelHandler);
+ return d->rotation * d->rotationScale;
+}
+
+void QQuickWheelHandler::setRotation(qreal rotation)
+{
+ Q_D(QQuickWheelHandler);
+ if (qFuzzyCompare(d->rotation, rotation / d->rotationScale))
+ return;
+
+ d->rotation = rotation / d->rotationScale;
+ emit rotationChanged();
+}
+
+/*!
+ \qmlproperty real QtQuick::WheelHandler::rotationScale
+
+ The scaling to be applied to the \l rotation property, and to the
+ \l property on the \l target item, if any. The default is 1, such that
+ \l rotation will be in units of degrees of rotation. It can be set to a
+ negative number to invert the effect of the direction of mouse wheel
+ rotation.
+*/
+qreal QQuickWheelHandler::rotationScale() const
+{
+ Q_D(const QQuickWheelHandler);
+ return d->rotationScale;
+}
+
+void QQuickWheelHandler::setRotationScale(qreal rotationScale)
+{
+ Q_D(QQuickWheelHandler);
+ if (qFuzzyCompare(d->rotationScale, rotationScale))
+ return;
+ if (qFuzzyIsNull(rotationScale)) {
+ qWarning("rotationScale cannot be set to zero");
+ return;
+ }
+
+ d->rotationScale = rotationScale;
+ emit rotationScaleChanged();
+}
+
+/*!
+ \qmlproperty string QtQuick::WheelHandler::property
+
+ The property to be modified on the \l target when the mouse wheel is rotated.
+
+ The default is no property (empty string). When no target property is being
+ automatically modified, you can use bindings to react to mouse wheel
+ rotation in arbitrary ways.
+
+ You can use the mouse wheel to adjust any numeric property. For example if
+ \c property is set to \c x, the \l target will move horizontally as the
+ wheel is rotated. The following properties have special behavior:
+
+ \value scale
+ \l{QQuickItem::scale}{scale} will be modified in a non-linear fashion
+ as described under \l targetScaleMultiplier. If
+ \l targetTransformAroundCursor is \c true, the \l{QQuickItem::x}{x} and
+ \l{QQuickItem::y}{y} properties will be simultaneously adjusted so that
+ the user will effectively zoom into or out of the point under the mouse
+ cursor.
+ \value rotation
+ \l{QQuickItem::rotation}{rotation} will be set to \l rotation. If
+ \l targetTransformAroundCursor is \c true, the l{QQuickItem::x}{x} and
+ \l{QQuickItem::y}{y} properties will be simultaneously adjusted so
+ that the user will effectively rotate the item around the point under
+ the mouse cursor.
+
+ The adjustment of the given target property is always scaled by \l rotationScale.
+*/
+QString QQuickWheelHandler::property() const
+{
+ Q_D(const QQuickWheelHandler);
+ return d->propertyName;
+}
+
+void QQuickWheelHandler::setProperty(const QString &propertyName)
+{
+ Q_D(QQuickWheelHandler);
+ if (d->propertyName == propertyName)
+ return;
+
+ d->propertyName = propertyName;
+ d->metaPropertyDirty = true;
+ emit propertyChanged();
+}
+
+/*!
+ \qmlproperty real QtQuick::WheelHandler::targetScaleMultiplier
+
+ The amount by which the \l target \l{QQuickItem::scale}{scale} is to be
+ multiplied whenever the \l rotation changes by 15 degrees. This
+ is relevant only when \l property is \c "scale".
+
+ The \c scale will be multiplied by
+ \c targetScaleMultiplier \sup {angleDelta * rotationScale / 15}.
+ The default is \c 2 \sup {1/3}, which means that if \l rotationScale is left
+ at its default value, and the mouse wheel is rotated by one "click"
+ (15 degrees), the \l target will be scaled by approximately 1.25; after
+ three "clicks" its size will be doubled or halved, depending on the
+ direction that the wheel is rotated. If you want to make it double or halve
+ with every 2 clicks of the wheel, set this to \c 2 \sup {1/2} (1.4142).
+ If you want to make it scale the opposite way as the wheel is rotated,
+ set \c rotationScale to a negative value.
+*/
+qreal QQuickWheelHandler::targetScaleMultiplier() const
+{
+ Q_D(const QQuickWheelHandler);
+ return d->targetScaleMultiplier;
+}
+
+void QQuickWheelHandler::setTargetScaleMultiplier(qreal targetScaleMultiplier)
+{
+ Q_D(QQuickWheelHandler);
+ if (qFuzzyCompare(d->targetScaleMultiplier, targetScaleMultiplier))
+ return;
+
+ d->targetScaleMultiplier = targetScaleMultiplier;
+ emit targetScaleMultiplierChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick::WheelHandler::targetTransformAroundCursor
+
+ Whether the \l target should automatically be repositioned in such a way
+ that it is transformed around the mouse cursor position while the
+ \l property is adjusted. The default is \c true.
+
+ If \l property is set to \c "rotation" and \l targetTransformAroundCursor
+ is \c true, then as the wheel is rotated, the \l target item will rotate in
+ place around the mouse cursor position. If \c targetTransformAroundCursor
+ is \c false, it will rotate around its
+ \l{QQuickItem::transformOrigin}{transformOrigin} instead.
+*/
+bool QQuickWheelHandler::isTargetTransformAroundCursor() const
+{
+ Q_D(const QQuickWheelHandler);
+ return d->targetTransformAroundCursor;
+}
+
+void QQuickWheelHandler::setTargetTransformAroundCursor(bool ttac)
+{
+ Q_D(QQuickWheelHandler);
+ if (d->targetTransformAroundCursor == ttac)
+ return;
+
+ d->targetTransformAroundCursor = ttac;
+ emit targetTransformAroundCursorChanged();
+}
+
+bool QQuickWheelHandler::wantsPointerEvent(QQuickPointerEvent *event)
+{
+ if (!event)
+ return false;
+ QQuickPointerScrollEvent *scroll = event->asPointerScrollEvent();
+ if (!scroll)
+ return false;
+ if (!acceptedDevices().testFlag(QQuickPointerDevice::DeviceType::TouchPad)
+ && scroll->synthSource() != Qt::MouseEventNotSynthesized)
+ return false;
+ if (!active()) {
+ switch (orientation()) {
+ case Qt::Horizontal:
+ if (qFuzzyIsNull(scroll->angleDelta().x()) && qFuzzyIsNull(scroll->pixelDelta().x()))
+ return false;
+ break;
+ case Qt::Vertical:
+ if (qFuzzyIsNull(scroll->angleDelta().y()) && qFuzzyIsNull(scroll->pixelDelta().y()))
+ return false;
+ break;
+ }
+ }
+ QQuickEventPoint *point = event->point(0);
+ if (QQuickPointerDeviceHandler::wantsPointerEvent(event) && wantsEventPoint(point) && parentContains(point)) {
+ setPointId(point->pointId());
+ return true;
+ }
+ return false;
+}
+
+void QQuickWheelHandler::handleEventPoint(QQuickEventPoint *point)
+{
+ Q_D(QQuickWheelHandler);
+ QQuickPointerScrollEvent *event = point->pointerEvent()->asPointerScrollEvent();
+ setActive(true); // ScrollEnd will not happen unless it was already active (see setActive(false) below)
+ point->setAccepted();
+ qreal inversion = !d->invertible && event->isInverted() ? -1 : 1;
+ qreal angleDelta = inversion * qreal(orientation() == Qt::Horizontal ? event->angleDelta().x() :
+ event->angleDelta().y()) / 8;
+ d->rotation += angleDelta;
+ emit rotationChanged();
+ emit wheel(event);
+ if (!d->propertyName.isEmpty() && target()) {
+ QQuickItem *t = target();
+ // writing target()'s property is done via QMetaProperty::write() so that any registered interceptors can react.
+ if (d->propertyName == QLatin1String("scale")) {
+ qreal multiplier = qPow(d->targetScaleMultiplier, angleDelta * d->rotationScale / 15); // wheel "clicks"
+ const QPointF centroidParentPos = t->parentItem()->mapFromScene(point->scenePosition());
+ const QPointF positionWas = t->position();
+ const qreal scaleWas = t->scale();
+ const qreal activePropertyValue = scaleWas * multiplier;
+ qCDebug(lcWheelHandler) << objectName() << "angle delta" << event->angleDelta() << "pixel delta" << event->pixelDelta()
+ << "@" << point->position() << "in parent" << centroidParentPos
+ << "in scene" << point->scenePosition()
+ << "multiplier" << multiplier << "scale" << scaleWas
+ << "->" << activePropertyValue;
+ d->targetMetaProperty().write(t, activePropertyValue);
+ if (d->targetTransformAroundCursor) {
+ // If an interceptor intervened, scale may now be different than we asked for. Adjust accordingly.
+ multiplier = t->scale() / scaleWas;
+ const QPointF adjPos = QQuickItemPrivate::get(t)->adjustedPosForTransform(
+ centroidParentPos, positionWas, QVector2D(), scaleWas, multiplier, t->rotation(), 0);
+ qCDebug(lcWheelHandler) << "adjusting item pos" << adjPos << "in scene" << t->parentItem()->mapToScene(adjPos);
+ t->setPosition(adjPos);
+ }
+ } else if (d->propertyName == QLatin1String("rotation")) {
+ const QPointF positionWas = t->position();
+ const qreal rotationWas = t->rotation();
+ const qreal activePropertyValue = rotationWas + angleDelta * d->rotationScale;
+ const QPointF centroidParentPos = t->parentItem()->mapFromScene(point->scenePosition());
+ qCDebug(lcWheelHandler) << objectName() << "angle delta" << event->angleDelta() << "pixel delta" << event->pixelDelta()
+ << "@" << point->position() << "in parent" << centroidParentPos
+ << "in scene" << point->scenePosition() << "rotation" << t->rotation()
+ << "->" << activePropertyValue;
+ d->targetMetaProperty().write(t, activePropertyValue);
+ if (d->targetTransformAroundCursor) {
+ // If an interceptor intervened, rotation may now be different than we asked for. Adjust accordingly.
+ const QPointF adjPos = QQuickItemPrivate::get(t)->adjustedPosForTransform(
+ centroidParentPos, positionWas, QVector2D(),
+ t->scale(), 1, rotationWas, t->rotation() - rotationWas);
+ qCDebug(lcWheelHandler) << "adjusting item pos" << adjPos << "in scene" << t->parentItem()->mapToScene(adjPos);
+ t->setPosition(adjPos);
+ }
+ } else {
+ qCDebug(lcWheelHandler) << objectName() << "angle delta" << event->angleDelta() << "scaled" << angleDelta << "total" << d->rotation << "pixel delta" << event->pixelDelta()
+ << "@" << point->position() << "in scene" << point->scenePosition() << "rotation" << t->rotation();
+ qreal delta = 0;
+ if (event->hasPixelDelta()) {
+ delta = inversion * d->rotationScale * qreal(orientation() == Qt::Horizontal ? event->pixelDelta().x() : event->pixelDelta().y());
+ qCDebug(lcWheelHandler) << "changing target" << d->propertyName << "by pixel delta" << delta << "from" << event;
+ } else {
+ delta = angleDelta * d->rotationScale;
+ qCDebug(lcWheelHandler) << "changing target" << d->propertyName << "by scaled angle delta" << delta << "from" << event;
+ }
+ bool ok = false;
+ qreal value = d->targetMetaProperty().read(t).toReal(&ok);
+ if (ok)
+ d->targetMetaProperty().write(t, value + qreal(delta));
+ else
+ qWarning() << "failed to read property" << d->propertyName << "of" << t;
+ }
+ }
+ switch (event->phase()) {
+ case Qt::ScrollEnd:
+ qCDebug(lcWheelHandler) << objectName() << "deactivating due to ScrollEnd phase";
+ setActive(false);
+ break;
+ case Qt::NoScrollPhase:
+ d->deactivationTimer.start(qRound(d->activeTimeout * 1000), this);
+ break;
+ case Qt::ScrollBegin:
+ case Qt::ScrollUpdate:
+ case Qt::ScrollMomentum:
+ break;
+ }
+}
+
+void QQuickWheelHandler::onTargetChanged(QQuickItem *oldTarget)
+{
+ Q_UNUSED(oldTarget)
+ Q_D(QQuickWheelHandler);
+ d->metaPropertyDirty = true;
+}
+
+void QQuickWheelHandler::onActiveChanged()
+{
+ Q_D(QQuickWheelHandler);
+ if (!active())
+ d->deactivationTimer.stop();
+}
+
+void QQuickWheelHandler::timerEvent(QTimerEvent *event)
+{
+ Q_D(const QQuickWheelHandler);
+ if (event->timerId() == d->deactivationTimer.timerId()) {
+ qCDebug(lcWheelHandler) << objectName() << "deactivating due to timeout";
+ setActive(false);
+ }
+}
+
+QQuickWheelHandlerPrivate::QQuickWheelHandlerPrivate()
+ : QQuickSinglePointHandlerPrivate()
+{
+}
+
+QMetaProperty &QQuickWheelHandlerPrivate::targetMetaProperty() const
+{
+ Q_Q(const QQuickWheelHandler);
+ if (metaPropertyDirty && q->target()) {
+ if (!propertyName.isEmpty()) {
+ const QMetaObject *targetMeta = q->target()->metaObject();
+ metaProperty = targetMeta->property(
+ targetMeta->indexOfProperty(propertyName.toLocal8Bit().constData()));
+ }
+ metaPropertyDirty = false;
+ }
+ return metaProperty;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/handlers/qquickwheelhandler_p.h b/src/quick/handlers/qquickwheelhandler_p.h
new file mode 100644
index 0000000000..f8d1c00726
--- /dev/null
+++ b/src/quick/handlers/qquickwheelhandler_p.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 QQUICKWHEELHANDLER_H
+#define QQUICKWHEELHANDLER_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 "qquickitem.h"
+#include "qevent.h"
+#include "qquicksinglepointhandler_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickWheelEvent;
+class QQuickWheelHandlerPrivate;
+
+class Q_QUICK_PRIVATE_EXPORT QQuickWheelHandler : public QQuickSinglePointHandler
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged)
+ Q_PROPERTY(bool invertible READ isInvertible WRITE setInvertible NOTIFY invertibleChanged)
+ Q_PROPERTY(qreal activeTimeout READ activeTimeout WRITE setActiveTimeout NOTIFY activeTimeoutChanged)
+ Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+ Q_PROPERTY(qreal rotationScale READ rotationScale WRITE setRotationScale NOTIFY rotationScaleChanged)
+ Q_PROPERTY(QString property READ property WRITE setProperty NOTIFY propertyChanged)
+ Q_PROPERTY(qreal targetScaleMultiplier READ targetScaleMultiplier WRITE setTargetScaleMultiplier NOTIFY targetScaleMultiplierChanged)
+ Q_PROPERTY(bool targetTransformAroundCursor READ isTargetTransformAroundCursor WRITE setTargetTransformAroundCursor NOTIFY targetTransformAroundCursorChanged)
+
+public:
+ explicit QQuickWheelHandler(QQuickItem *parent = nullptr);
+
+ Qt::Orientation orientation() const;
+ void setOrientation(Qt::Orientation orientation);
+
+ bool isInvertible() const;
+ void setInvertible(bool invertible);
+
+ qreal activeTimeout() const;
+ void setActiveTimeout(qreal timeout);
+
+ qreal rotation() const;
+ void setRotation(qreal rotation);
+
+ qreal rotationScale() const;
+ void setRotationScale(qreal rotationScale);
+
+ QString property() const;
+ void setProperty(const QString &name);
+
+ qreal targetScaleMultiplier() const;
+ void setTargetScaleMultiplier(qreal targetScaleMultiplier);
+
+ bool isTargetTransformAroundCursor() const;
+ void setTargetTransformAroundCursor(bool ttac);
+
+Q_SIGNALS:
+ void wheel(QQuickPointerScrollEvent *event);
+
+ void orientationChanged();
+ void invertibleChanged();
+ void activeTimeoutChanged();
+ void rotationChanged();
+ void rotationScaleChanged();
+ void propertyChanged();
+ void targetScaleMultiplierChanged();
+ void targetTransformAroundCursorChanged();
+
+protected:
+ bool wantsPointerEvent(QQuickPointerEvent *event) override;
+ void handleEventPoint(QQuickEventPoint *point) override;
+ void onTargetChanged(QQuickItem *oldTarget) override;
+ void onActiveChanged() override;
+ void timerEvent(QTimerEvent *event) override;
+
+ Q_DECLARE_PRIVATE(QQuickWheelHandler)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickWheelHandler)
+
+#endif // QQUICKWHEELHANDLER_H
diff --git a/src/quick/handlers/qquickwheelhandler_p_p.h b/src/quick/handlers/qquickwheelhandler_p_p.h
new file mode 100644
index 0000000000..d35e04c51b
--- /dev/null
+++ b/src/quick/handlers/qquickwheelhandler_p_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 QQUICKWHEELHANDLER_P_P_H
+#define QQUICKWHEELHANDLER_P_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 "qquicksinglepointhandler_p_p.h"
+#include "qquickwheelhandler_p.h"
+#include <QtCore/qbasictimer.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_PRIVATE_EXPORT QQuickWheelHandlerPrivate : public QQuickSinglePointHandlerPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickWheelHandler)
+
+public:
+ static QQuickWheelHandlerPrivate* get(QQuickWheelHandler *q) { return q->d_func(); }
+ static const QQuickWheelHandlerPrivate* get(const QQuickWheelHandler *q) { return q->d_func(); }
+
+ QQuickWheelHandlerPrivate();
+
+ QMetaProperty &targetMetaProperty() const;
+
+ QBasicTimer deactivationTimer;
+ qreal activeTimeout = 0.1;
+ qreal rotationScale = 1;
+ qreal rotation = 0; // in units of degrees
+ qreal targetScaleMultiplier = 1.25992104989487; // qPow(2, 1/3)
+ QString propertyName;
+ mutable QMetaProperty metaProperty;
+ Qt::Orientation orientation = Qt::Vertical;
+ mutable bool metaPropertyDirty = true;
+ bool invertible = true;
+ bool targetTransformAroundCursor = true;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKWHEELHANDLER_P_P_H
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index c43eab6b8a..28b217b7b3 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -1135,10 +1135,10 @@ void QQuickEventTouchPoint::reset(const QTouchEvent::TouchPoint &tp, ulong times
struct PointVelocityData {
QVector2D velocity;
QPointF pos;
- ulong timestamp;
+ ulong timestamp = 0;
};
-typedef QMap<quint64, PointVelocityData*> PointDataForPointIdMap;
+typedef QMap<quint64, PointVelocityData> PointDataForPointIdMap;
Q_GLOBAL_STATIC(PointDataForPointIdMap, g_previousPointData)
static const int PointVelocityAgeLimit = 500; // milliseconds
@@ -1149,42 +1149,36 @@ static const int PointVelocityAgeLimit = 500; // milliseconds
*/
QVector2D QQuickEventPoint::estimatedVelocity() const
{
- PointVelocityData *prevPoint = g_previousPointData->value(m_pointId);
- if (!prevPoint) {
+ auto prevPointIt = g_previousPointData->find(m_pointId);
+ auto end = g_previousPointData->end();
+ if (prevPointIt == end) {
// cleanup events older than PointVelocityAgeLimit
- auto end = g_previousPointData->end();
for (auto it = g_previousPointData->begin(); it != end; ) {
- PointVelocityData *data = it.value();
- if (m_timestamp - data->timestamp > PointVelocityAgeLimit) {
+ if (m_timestamp - it->timestamp > PointVelocityAgeLimit)
it = g_previousPointData->erase(it);
- delete data;
- } else {
+ else
++it;
- }
}
- // TODO optimize: stop this dynamic memory thrashing
- prevPoint = new PointVelocityData;
- prevPoint->velocity = QVector2D();
- prevPoint->timestamp = 0;
- prevPoint->pos = QPointF();
- g_previousPointData->insert(m_pointId, prevPoint);
+ prevPointIt = g_previousPointData->insert(m_pointId, PointVelocityData());
}
- const ulong timeElapsed = m_timestamp - prevPoint->timestamp;
+
+ auto &prevPoint = prevPointIt.value();
+ const ulong timeElapsed = m_timestamp - prevPoint.timestamp;
if (timeElapsed == 0) // in case we call estimatedVelocity() twice on the same QQuickEventPoint
return m_velocity;
QVector2D newVelocity;
- if (prevPoint->timestamp != 0)
- newVelocity = QVector2D(m_scenePos - prevPoint->pos)/timeElapsed;
+ if (prevPoint.timestamp != 0)
+ newVelocity = QVector2D(m_scenePos - prevPoint.pos) / timeElapsed;
// VERY simple kalman filter: does a weighted average
// where the older velocities get less and less significant
static const float KalmanGain = 0.7f;
QVector2D filteredVelocity = newVelocity * KalmanGain + m_velocity * (1.0f - KalmanGain);
- prevPoint->velocity = filteredVelocity;
- prevPoint->pos = m_scenePos;
- prevPoint->timestamp = m_timestamp;
+ prevPoint.velocity = filteredVelocity;
+ prevPoint.pos = m_scenePos;
+ prevPoint.timestamp = m_timestamp;
return filteredVelocity;
}
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index e614b1bd6d..1a3737091f 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -605,6 +605,7 @@ private:
bool m_inverted = false;
friend class QQuickWindowPrivate;
+ friend class QQuickWheelHandler;
Q_DISABLE_COPY(QQuickPointerScrollEvent)
};
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index cd5cca5ac9..2a1c442653 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -120,6 +120,7 @@
#include "handlers/qquickpinchhandler_p.h"
#include "handlers/qquickpointhandler_p.h"
#include "handlers/qquicktaphandler_p.h"
+#include "handlers/qquickwheelhandler_p.h"
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcTransient)
@@ -475,6 +476,12 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterUncreatableType<QQuickItemView, 13>(uri, 2, 13, itemViewName, itemViewMessage);
qmlRegisterType<QQuickPathView, 13>(uri, 2, 13, "PathView");
qmlRegisterType<QQuickGridView, 13>(uri, 2, 13, "GridView");
+#if QT_CONFIG(quick_tableview)
+ qmlRegisterType<QQuickTableView, 14>(uri, 2, 14, "TableView");
+#endif
+#if QT_CONFIG(wheelevent)
+ qmlRegisterType<QQuickWheelHandler>(uri, 2, 14, "WheelHandler");
+#endif
}
static void initResources()
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index ea5b5df9c6..0f1594f904 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -59,9 +59,9 @@ QT_REQUIRE_CONFIG(quick_itemview);
#include "qquickitemviewfxitem_p_p.h"
#include "qquickitemviewtransition_p.h"
#include "qquickflickable_p_p.h"
-#include <QtQml/private/qqmlobjectmodel_p.h>
-#include <QtQml/private/qqmldelegatemodel_p.h>
-#include <QtQml/private/qqmlchangeset_p.h>
+#include <QtQmlModels/private/qqmlobjectmodel_p.h>
+#include <QtQmlModels/private/qqmldelegatemodel_p.h>
+#include <QtQmlModels/private/qqmlchangeset_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/quick/items/qquickrepeater.cpp b/src/quick/items/qquickrepeater.cpp
index 805b6fe190..c8a03aff33 100644
--- a/src/quick/items/qquickrepeater.cpp
+++ b/src/quick/items/qquickrepeater.cpp
@@ -41,7 +41,6 @@
#include "qquickrepeater_p_p.h"
#include <private/qqmlglobal_p.h>
-#include <private/qqmllistaccessor_p.h>
#include <private/qqmlchangeset_p.h>
#include <private/qqmldelegatemodel_p.h>
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 1dca5bea4a..8f5130fc17 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -42,10 +42,10 @@
#include <QtCore/qtimer.h>
#include <QtCore/qdir.h>
-#include <QtQml/private/qqmldelegatemodel_p.h>
-#include <QtQml/private/qqmldelegatemodel_p_p.h>
+#include <QtQmlModels/private/qqmldelegatemodel_p.h>
+#include <QtQmlModels/private/qqmldelegatemodel_p_p.h>
#include <QtQml/private/qqmlincubator_p.h>
-#include <QtQml/private/qqmlchangeset_p.h>
+#include <QtQmlModels/private/qqmlchangeset_p.h>
#include <QtQml/qqmlinfo.h>
#include <QtQuick/private/qquickflickable_p_p.h>
@@ -76,14 +76,23 @@
\section1 Example Usage
+ \section2 C++ Models
+
The following example shows how to create a model from C++ with multiple
columns:
- \snippet qml/tableview/tablemodel.cpp 0
+ \snippet qml/tableview/cpp-tablemodel.cpp 0
And then how to use it from QML:
- \snippet qml/tableview/tablemodel.qml 0
+ \snippet qml/tableview/cpp-tablemodel.qml 0
+
+ \section2 QML Models
+
+ For prototyping and displaying very simple data (from a web API, for
+ example), \l TableModel can be used:
+
+ \snippet qml/tableview/qml-tablemodel.qml 0
\section1 Reusing items
@@ -606,6 +615,11 @@ void QQuickTableViewPrivate::updateContentWidth()
{
Q_Q(QQuickTableView);
+ if (syncHorizontally) {
+ q->QQuickFlickable::setContentWidth(syncView->contentWidth());
+ return;
+ }
+
if (explicitContentWidth.isValid()) {
// Don't calculate contentWidth when it
// was set explicitly by the application.
@@ -625,6 +639,11 @@ void QQuickTableViewPrivate::updateContentHeight()
{
Q_Q(QQuickTableView);
+ if (syncVertically) {
+ q->QQuickFlickable::setContentHeight(syncView->contentHeight());
+ return;
+ }
+
if (explicitContentHeight.isValid()) {
// Don't calculate contentHeight when it
// was set explicitly by the application.
@@ -1048,6 +1067,11 @@ qreal QQuickTableViewPrivate::getColumnLayoutWidth(int column)
if (explicitColumnWidth >= 0)
return explicitColumnWidth;
+ if (syncHorizontally) {
+ if (syncView->d_func()->loadedColumns.contains(column))
+ return syncView->d_func()->getColumnLayoutWidth(column);
+ }
+
// Iterate over the currently visible items in the column. The downside
// of doing that, is that the column width will then only be based on the implicit
// width of the currently loaded items (which can be different depending on which
@@ -1077,6 +1101,11 @@ qreal QQuickTableViewPrivate::getRowLayoutHeight(int row)
if (explicitRowHeight >= 0)
return explicitRowHeight;
+ if (syncVertically) {
+ if (syncView->d_func()->loadedRows.contains(row))
+ return syncView->d_func()->getRowLayoutHeight(row);
+ }
+
// Iterate over the currently visible items in the row. The downside
// of doing that, is that the row height will then only be based on the implicit
// height of the currently loaded items (which can be different depending on which
@@ -1106,6 +1135,9 @@ qreal QQuickTableViewPrivate::getColumnWidth(int column)
if (cachedColumnWidth.startIndex == column)
return cachedColumnWidth.size;
+ if (syncHorizontally)
+ return syncView->d_func()->getColumnWidth(column);
+
if (columnWidthProvider.isUndefined())
return noExplicitColumnWidth;
@@ -1140,6 +1172,9 @@ qreal QQuickTableViewPrivate::getRowHeight(int row)
if (cachedRowHeight.startIndex == row)
return cachedRowHeight.size;
+ if (syncVertically)
+ return syncView->d_func()->getRowHeight(row);
+
if (rowHeightProvider.isUndefined())
return noExplicitRowHeight;
@@ -1489,48 +1524,103 @@ bool QQuickTableViewPrivate::moveToNextRebuildState()
return true;
}
-QPoint QQuickTableViewPrivate::calculateNewTopLeft()
-{
- const int firstVisibleLeft = nextVisibleEdgeIndex(Qt::RightEdge, 0);
- const int firstVisibleTop = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
-
- return QPoint(firstVisibleLeft, firstVisibleTop);
-}
-
-void QQuickTableViewPrivate::calculateTopLeft(QPoint &topLeft, QPointF &topLeftPos)
+void QQuickTableViewPrivate::calculateTopLeft(QPoint &topLeftCell, QPointF &topLeftPos)
{
if (tableSize.isEmpty()) {
- releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
- topLeft = QPoint(kEdgeIndexAtEnd, kEdgeIndexAtEnd);
+ // There is no cell that can be top left
+ topLeftCell.rx() = kEdgeIndexAtEnd;
+ topLeftCell.ry() = kEdgeIndexAtEnd;
return;
}
- if (rebuildOptions & RebuildOption::All) {
- qCDebug(lcTableViewDelegateLifecycle()) << "RebuildOption::All";
- releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
- topLeft = calculateNewTopLeft();
- } else if (rebuildOptions & RebuildOption::ViewportOnly) {
- qCDebug(lcTableViewDelegateLifecycle()) << "RebuildOption::ViewportOnly";
- releaseLoadedItems(reusableFlag);
+ if (syncHorizontally || syncVertically) {
+ const auto syncView_d = syncView->d_func();
- if (rebuildOptions & RebuildOption::CalculateNewTopLeftRow) {
- const int newRow = int(viewportRect.y() / (averageEdgeSize.height() + cellSpacing.height()));
- topLeft.ry() = qBound(0, newRow, tableSize.height() - 1);
- topLeftPos.ry() = topLeft.y() * (averageEdgeSize.height() + cellSpacing.height());
- } else {
- topLeft.ry() = qBound(0, topRow(), tableSize.height() - 1);
- topLeftPos.ry() = loadedTableOuterRect.topLeft().y();
+ if (syncView_d->loadedItems.isEmpty()) {
+ // The sync view contains no loaded items. This probably means
+ // that it has not been rebuilt yet. Which also means that
+ // we cannot rebuild anything before this happens.
+ topLeftCell.rx() = kEdgeIndexNotSet;
+ topLeftCell.ry() = kEdgeIndexNotSet;
+ return;
+ }
+
+ // Get sync view top left, and use that as our own top left (if possible)
+ const QPoint syncViewTopLeftCell(syncView_d->leftColumn(), syncView_d->topRow());
+ const auto syncViewTopLeftFxItem = syncView_d->loadedTableItem(syncViewTopLeftCell);
+ const QPointF syncViewTopLeftPos = syncViewTopLeftFxItem->geometry().topLeft();
+
+ if (syncHorizontally) {
+ topLeftCell.rx() = syncViewTopLeftCell.x();
+ topLeftPos.rx() = syncViewTopLeftPos.x();
+
+ if (topLeftCell.x() >= tableSize.width()) {
+ // Top left is outside our own model.
+ topLeftCell.rx() = kEdgeIndexAtEnd;
+ topLeftPos.rx() = kEdgeIndexAtEnd;
+ }
}
- if (rebuildOptions & RebuildOption::CalculateNewTopLeftColumn) {
+
+ if (syncVertically) {
+ topLeftCell.ry() = syncViewTopLeftCell.y();
+ topLeftPos.ry() = syncViewTopLeftPos.y();
+
+ if (topLeftCell.y() >= tableSize.height()) {
+ // Top left is outside our own model.
+ topLeftCell.ry() = kEdgeIndexAtEnd;
+ topLeftPos.ry() = kEdgeIndexAtEnd;
+ }
+ }
+
+ if (syncHorizontally && syncVertically) {
+ // We have a valid top left, so we're done
+ return;
+ }
+ }
+
+ // Since we're not sync-ing both horizontal and vertical, calculate the missing
+ // dimention(s) ourself. If we rebuild all, we find the first visible top-left
+ // item starting from cell(0, 0). Otherwise, guesstimate which row or column that
+ // should be the new top-left given the geometry of the viewport.
+
+ if (!syncHorizontally) {
+ if (rebuildOptions & RebuildOption::All) {
+ // Find the first visible column from the beginning
+ topLeftCell.rx() = nextVisibleEdgeIndex(Qt::RightEdge, 0);
+ if (topLeftCell.x() == kEdgeIndexAtEnd) {
+ // No visible column found
+ return;
+ }
+ } else if (rebuildOptions & RebuildOption::CalculateNewTopLeftColumn) {
+ // Guesstimate new top left
const int newColumn = int(viewportRect.x() / (averageEdgeSize.width() + cellSpacing.width()));
- topLeft.rx() = qBound(0, newColumn, tableSize.width() - 1);
- topLeftPos.rx() = topLeft.x() * (averageEdgeSize.width() + cellSpacing.width());
+ topLeftCell.rx() = qBound(0, newColumn, tableSize.width() - 1);
+ topLeftPos.rx() = topLeftCell.x() * (averageEdgeSize.width() + cellSpacing.width());
} else {
- topLeft.rx() = qBound(0, leftColumn(), tableSize.width() - 1);
+ // Keep the current top left, unless it's outside model
+ topLeftCell.rx() = qBound(0, leftColumn(), tableSize.width() - 1);
topLeftPos.rx() = loadedTableOuterRect.topLeft().x();
}
- } else {
- Q_TABLEVIEW_UNREACHABLE(rebuildOptions);
+ }
+
+ if (!syncVertically) {
+ if (rebuildOptions & RebuildOption::All) {
+ // Find the first visible row from the beginning
+ topLeftCell.ry() = nextVisibleEdgeIndex(Qt::BottomEdge, 0);
+ if (topLeftCell.y() == kEdgeIndexAtEnd) {
+ // No visible row found
+ return;
+ }
+ } else if (rebuildOptions & RebuildOption::CalculateNewTopLeftRow) {
+ // Guesstimate new top left
+ const int newRow = int(viewportRect.y() / (averageEdgeSize.height() + cellSpacing.height()));
+ topLeftCell.ry() = qBound(0, newRow, tableSize.height() - 1);
+ topLeftPos.ry() = topLeftCell.y() * (averageEdgeSize.height() + cellSpacing.height());
+ } else {
+ // Keep the current top left, unless it's outside model
+ topLeftCell.ry() = qBound(0, topRow(), tableSize.height() - 1);
+ topLeftPos.ry() = loadedTableOuterRect.topLeft().y();
+ }
}
}
@@ -1542,12 +1632,22 @@ void QQuickTableViewPrivate::beginRebuildTable()
QPointF topLeftPos;
calculateTopLeft(topLeft, topLeftPos);
+ if (rebuildOptions & RebuildOption::All)
+ releaseLoadedItems(QQmlTableInstanceModel::NotReusable);
+ else if (rebuildOptions & RebuildOption::ViewportOnly)
+ releaseLoadedItems(reusableFlag);
+
loadedColumns.clear();
loadedRows.clear();
loadedTableOuterRect = QRect();
loadedTableInnerRect = QRect();
clearEdgeSizeCache();
+ if (syncHorizontally)
+ setLocalViewportX(syncView->contentX());
+ if (syncVertically)
+ setLocalViewportY(syncView->contentY());
+
if (!model) {
qCDebug(lcTableViewDelegateLifecycle()) << "no model found, leaving table empty";
return;
@@ -1564,7 +1664,12 @@ void QQuickTableViewPrivate::beginRebuildTable()
}
if (topLeft.x() == kEdgeIndexAtEnd || topLeft.y() == kEdgeIndexAtEnd) {
- qCDebug(lcTableViewDelegateLifecycle()) << "no visible rows or columns, leaving table empty";
+ qCDebug(lcTableViewDelegateLifecycle()) << "no visible row or column found, leaving table empty";
+ return;
+ }
+
+ if (topLeft.x() == kEdgeIndexNotSet || topLeft.y() == kEdgeIndexNotSet) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "could not resolve top-left item, leaving table empty";
return;
}
@@ -1733,11 +1838,59 @@ void QQuickTableViewPrivate::scheduleRebuildTable(RebuildOptions options) {
q_func()->polish();
}
+QQuickTableView *QQuickTableViewPrivate::rootSyncView() const
+{
+ QQuickTableView *root = const_cast<QQuickTableView *>(q_func());
+ while (QQuickTableView *view = root->d_func()->syncView)
+ root = view;
+ return root;
+}
+
void QQuickTableViewPrivate::updatePolish()
{
+ // We always start updating from the top of the syncView tree, since
+ // the layout of a syncView child will depend on the layout of the syncView.
+ // E.g when a new column is flicked in, the syncView should load and layout
+ // the column first, before any syncChildren gets a chance to do the same.
+ Q_TABLEVIEW_ASSERT(!polishing, "recursive updatePolish() calls are not allowed!");
+ rootSyncView()->d_func()->updateTableRecursive();
+}
+
+bool QQuickTableViewPrivate::updateTableRecursive()
+{
+ if (polishing) {
+ // We're already updating the Table in this view, so
+ // we cannot continue. Signal this back by returning false.
+ // The caller can then choose to call "polish()" instead, to
+ // do the update later.
+ return false;
+ }
+
+ const bool updateComplete = updateTable();
+ if (!updateComplete)
+ return false;
+
+ for (auto syncChild : qAsConst(syncChildren)) {
+ auto syncChild_d = syncChild->d_func();
+ syncChild_d->scheduledRebuildOptions |= rebuildOptions;
+
+ const bool descendantUpdateComplete = syncChild_d->updateTableRecursive();
+ if (!descendantUpdateComplete)
+ return false;
+ }
+
+ rebuildOptions = RebuildOption::None;
+
+ return true;
+}
+
+bool QQuickTableViewPrivate::updateTable()
+{
// Whenever something changes, e.g viewport moves, spacing is set to a
// new value, model changes etc, this function will end up being called. Here
// we check what needs to be done, and load/unload cells accordingly.
+ // If we cannot complete the update (because we need to wait for an item
+ // to load async), we return false.
Q_TABLEVIEW_ASSERT(!polishing, "recursive updatePolish() calls are not allowed!");
QBoolBlocker polishGuard(polishing, true);
@@ -1747,25 +1900,27 @@ void QQuickTableViewPrivate::updatePolish()
// as an atomic operation, which means that we don't continue doing anything else until all
// items have been received and laid out. Note that updatePolish is then called once more
// after the loadRequest has completed to handle anything that might have occurred in-between.
- return;
+ return false;
}
if (rebuildState != RebuildState::Done) {
processRebuildTable();
- return;
+ return rebuildState == RebuildState::Done;
}
syncWithPendingChanges();
if (rebuildState == RebuildState::Begin) {
processRebuildTable();
- return;
+ return rebuildState == RebuildState::Done;
}
if (loadedItems.isEmpty())
- return;
+ return !loadRequest.isActive();
loadAndUnloadVisibleEdges();
+
+ return !loadRequest.isActive();
}
void QQuickTableViewPrivate::fixup(QQuickFlickablePrivate::AxisData &data, qreal minExtent, qreal maxExtent)
@@ -1855,9 +2010,14 @@ void QQuickTableViewPrivate::syncWithPendingChanges()
// such assignments into effect until we're in a state that allows it.
Q_Q(QQuickTableView);
viewportRect = QRectF(q->contentX(), q->contentY(), q->width(), q->height());
+
+ // Sync rebuild options first, in case we schedule a rebuild from one of the
+ // other sync calls above. If so, we need to start a new rebuild from the top.
syncRebuildOptions();
+
syncModel();
syncDelegate();
+ syncSyncView();
}
void QQuickTableViewPrivate::syncRebuildOptions()
@@ -1922,6 +2082,46 @@ void QQuickTableViewPrivate::syncModel()
connectToModel();
}
+void QQuickTableViewPrivate::syncSyncView()
+{
+ Q_Q(QQuickTableView);
+
+ if (assignedSyncView != syncView) {
+ if (syncView)
+ syncView->d_func()->syncChildren.removeOne(q);
+
+ if (assignedSyncView) {
+ QQuickTableView *view = assignedSyncView;
+
+ while (view) {
+ if (view == q) {
+ if (!layoutWarningIssued) {
+ layoutWarningIssued = true;
+ qmlWarning(q) << "TableView: recursive syncView connection detected!";
+ }
+ syncView = nullptr;
+ return;
+ }
+ view = view->d_func()->syncView;
+ }
+
+ assignedSyncView->d_func()->syncChildren.append(q);
+ scheduledRebuildOptions |= RebuildOption::ViewportOnly;
+ q->polish();
+ }
+
+ syncView = assignedSyncView;
+ }
+
+ syncHorizontally = syncView && assignedSyncDirection & Qt::Horizontal;
+ syncVertically = syncView && assignedSyncDirection & Qt::Vertical;
+
+ if (syncHorizontally)
+ q->setColumnSpacing(syncView->columnSpacing());
+ if (syncVertically)
+ q->setRowSpacing(syncView->rowSpacing());
+}
+
void QQuickTableViewPrivate::connectToModel()
{
Q_TABLEVIEW_ASSERT(model, "");
@@ -2051,6 +2251,84 @@ void QQuickTableViewPrivate::modelResetCallback()
scheduleRebuildTable(RebuildOption::All);
}
+void QQuickTableViewPrivate::scheduleRebuildIfFastFlick()
+{
+ Q_Q(QQuickTableView);
+
+ // If the viewport has moved more than one page vertically or horizontally, we switch
+ // strategy from refilling edges around the current table to instead rebuild the table
+ // from scratch inside the new viewport. This will greatly improve performance when flicking
+ // a long distance in one go, which can easily happen when dragging on scrollbars.
+
+ // Check the viewport moved more than one page vertically
+ if (!viewportRect.intersects(QRectF(viewportRect.x(), q->contentY(), 1, q->height()))) {
+ scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftRow;
+ scheduledRebuildOptions |= RebuildOption::ViewportOnly;
+ }
+
+ // Check the viewport moved more than one page horizontally
+ if (!viewportRect.intersects(QRectF(q->contentX(), viewportRect.y(), q->width(), 1))) {
+ scheduledRebuildOptions |= RebuildOption::CalculateNewTopLeftColumn;
+ scheduledRebuildOptions |= RebuildOption::ViewportOnly;
+ }
+}
+
+void QQuickTableViewPrivate::setLocalViewportX(qreal contentX)
+{
+ // Set the new viewport position if changed, but don't trigger any
+ // rebuilds or updates. We use this function internally to distinguish
+ // external flicking from internal sync-ing of the content view.
+ Q_Q(QQuickTableView);
+ QBoolBlocker blocker(inSetLocalViewportPos, true);
+
+ if (qFuzzyCompare(contentX, q->contentX()))
+ return;
+
+ q->setContentX(contentX);
+}
+
+void QQuickTableViewPrivate::setLocalViewportY(qreal contentY)
+{
+ // Set the new viewport position if changed, but don't trigger any
+ // rebuilds or updates. We use this function internally to distinguish
+ // external flicking from internal sync-ing of the content view.
+ Q_Q(QQuickTableView);
+ QBoolBlocker blocker(inSetLocalViewportPos, true);
+
+ if (qFuzzyCompare(contentY, q->contentY()))
+ return;
+
+ q->setContentY(contentY);
+}
+
+void QQuickTableViewPrivate::syncViewportPosRecursive()
+{
+ Q_Q(QQuickTableView);
+ QBoolBlocker recursionGuard(inSyncViewportPosRecursive, true);
+
+ if (syncView) {
+ auto syncView_d = syncView->d_func();
+ if (!syncView_d->inSyncViewportPosRecursive) {
+ if (syncHorizontally)
+ syncView_d->setLocalViewportX(q->contentX());
+ if (syncVertically)
+ syncView_d->setLocalViewportY(q->contentY());
+ syncView_d->syncViewportPosRecursive();
+ }
+ }
+
+ for (auto syncChild : qAsConst(syncChildren)) {
+ auto syncChild_d = syncChild->d_func();
+ if (!syncChild_d->inSyncViewportPosRecursive) {
+ if (syncChild_d->syncHorizontally)
+ syncChild_d->setLocalViewportX(q->contentX());
+ if (syncChild_d->syncVertically)
+ syncChild_d->setLocalViewportY(q->contentY());
+ syncChild_d->syncViewportPosRecursive();
+ }
+ }
+}
+
QQuickTableView::QQuickTableView(QQuickItem *parent)
: QQuickFlickable(*(new QQuickTableViewPrivate), parent)
{
@@ -2214,6 +2492,41 @@ void QQuickTableView::setContentHeight(qreal height)
QQuickFlickable::setContentHeight(height);
}
+QQuickTableView *QQuickTableView::syncView() const
+{
+ return d_func()->assignedSyncView;
+}
+
+void QQuickTableView::setSyncView(QQuickTableView *view)
+{
+ Q_D(QQuickTableView);
+ if (d->assignedSyncView == view)
+ return;
+
+ d->assignedSyncView = view;
+ d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
+
+ emit syncViewChanged();
+}
+
+Qt::Orientations QQuickTableView::syncDirection() const
+{
+ return d_func()->assignedSyncDirection;
+}
+
+void QQuickTableView::setSyncDirection(Qt::Orientations direction)
+{
+ Q_D(QQuickTableView);
+ if (d->assignedSyncDirection == direction)
+ return;
+
+ d->assignedSyncDirection = direction;
+ if (d->assignedSyncView)
+ d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
+
+ emit syncDirectionChanged();
+}
+
void QQuickTableView::forceLayout()
{
d_func()->forceLayout();
@@ -2241,45 +2554,42 @@ void QQuickTableView::geometryChanged(const QRectF &newGeometry, const QRectF &o
void QQuickTableView::viewportMoved(Qt::Orientations orientation)
{
Q_D(QQuickTableView);
+
+ // If the new viewport position was set from the setLocalViewportXY()
+ // functions, we just update the position silently and return. Otherwise, if
+ // the viewport was flicked by the user, or some other control, we
+ // recursively sync all the views in the hierarchy to the same position.
QQuickFlickable::viewportMoved(orientation);
+ if (d->inSetLocalViewportPos)
+ return;
- QQuickTableViewPrivate::RebuildOptions options = QQuickTableViewPrivate::RebuildOption::None;
+ // Move all views in the syncView hierarchy to the same contentX/Y.
+ // We need to start from this view (and not the root syncView) to
+ // ensure that we respect all the individual syncDirection flags
+ // between the individual views in the hierarchy.
+ d->syncViewportPosRecursive();
- // Check the viewport moved more than one page vertically
- if (!d->viewportRect.intersects(QRectF(d->viewportRect.x(), contentY(), 1, height())))
- options |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow;
- // Check the viewport moved more than one page horizontally
- if (!d->viewportRect.intersects(QRectF(contentX(), d->viewportRect.y(), width(), 1)))
- options |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn;
-
- if (options) {
- // When the viewport has moved more than one page vertically or horizontally, we switch
- // strategy from refilling edges around the current table to instead rebuild the table
- // from scratch inside the new viewport. This will greatly improve performance when flicking
- // a long distance in one go, which can easily happen when dragging on scrollbars.
- options |= QQuickTableViewPrivate::RebuildOption::ViewportOnly;
- d->scheduleRebuildTable(options);
- }
-
- if (d->scheduledRebuildOptions) {
- // No reason to do anything, since we're about to rebuild the whole table anyway.
- // Besides, calling updatePolish, which will start the rebuild, can easily cause
- // binding loops to happen since we usually end up modifying the geometry of the
- // viewport (contentItem) as well.
- return;
- }
+ auto rootView = d->rootSyncView();
+ auto rootView_d = rootView->d_func();
- // Calling polish() will schedule a polish event. But while the user is flicking, several
- // mouse events will be handled before we get an updatePolish() call. And the updatePolish()
- // call will only see the last mouse position. This results in a stuttering flick experience
- // (especially on windows). We improve on this by calling updatePolish() directly. But this
- // has the pitfall that we open up for recursive callbacks. E.g while inside updatePolish(), we
- // load/unload items, and emit signals. The application can listen to those signals and set a
- // new contentX/Y on the flickable. So we need to guard for this, to avoid unexpected behavior.
- if (d->polishing)
- polish();
- else
- d->updatePolish();
+ rootView_d->scheduleRebuildIfFastFlick();
+
+ if (!rootView_d->polishScheduled) {
+ if (rootView_d->scheduledRebuildOptions) {
+ // When we need to rebuild, collecting several viewport
+ // moves and do a single polish gives a quicker UI.
+ rootView->polish();
+ } else {
+ // Updating the table right away when flicking
+ // slowly gives a smoother experience.
+ const bool updated = rootView->d_func()->updateTableRecursive();
+ if (!updated) {
+ // One, or more, of the views are already in an
+ // update, so we need to wait a cycle.
+ rootView->polish();
+ }
+ }
+ }
}
void QQuickTableViewPrivate::_q_componentFinalized()
@@ -2315,6 +2625,71 @@ void QQuickTableView::componentComplete()
d_func()->registerCallbackWhenBindingsAreEvaluated();
}
+class QObjectPrivate;
+class QQuickTableSectionSizeProviderPrivate : public QObjectPrivate {
+public:
+ QQuickTableSectionSizeProviderPrivate();
+ ~QQuickTableSectionSizeProviderPrivate();
+ QHash<int, qreal> hash;
+};
+
+QQuickTableSectionSizeProvider::QQuickTableSectionSizeProvider(QObject *parent)
+ : QObject (*(new QQuickTableSectionSizeProviderPrivate), parent)
+{
+}
+
+void QQuickTableSectionSizeProvider::setSize(int section, qreal size)
+{
+ Q_D(QQuickTableSectionSizeProvider);
+ if (section < 0 || size < 0) {
+ qmlWarning(this) << "setSize: section or size less than zero";
+ return;
+ }
+ if (qFuzzyCompare(QQuickTableSectionSizeProvider::size(section), size))
+ return;
+ d->hash.insert(section, size);
+ emit sizeChanged();
+}
+
+// return -1.0 if no valid explicit size retrieved
+qreal QQuickTableSectionSizeProvider::size(int section)
+{
+ Q_D(QQuickTableSectionSizeProvider);
+ auto it = d->hash.find(section);
+ if (it != d->hash.end())
+ return *it;
+ return -1.0;
+}
+
+// return true if section is valid
+bool QQuickTableSectionSizeProvider::resetSize(int section)
+{
+ Q_D(QQuickTableSectionSizeProvider);
+ if (d->hash.empty())
+ return false;
+
+ auto ret = d->hash.remove(section);
+ if (ret)
+ emit sizeChanged();
+ return ret;
+}
+
+void QQuickTableSectionSizeProvider::resetAll()
+{
+ Q_D(QQuickTableSectionSizeProvider);
+ d->hash.clear();
+ emit sizeChanged();
+}
+
+QQuickTableSectionSizeProviderPrivate::QQuickTableSectionSizeProviderPrivate()
+ : QObjectPrivate()
+{
+}
+
+QQuickTableSectionSizeProviderPrivate::~QQuickTableSectionSizeProviderPrivate()
+{
+
+}
#include "moc_qquicktableview_p.cpp"
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktableview_p.h b/src/quick/items/qquicktableview_p.h
index f32c71b983..3d46221574 100644
--- a/src/quick/items/qquicktableview_p.h
+++ b/src/quick/items/qquicktableview_p.h
@@ -79,6 +79,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTableView : public QQuickFlickable
Q_PROPERTY(bool reuseItems READ reuseItems WRITE setReuseItems NOTIFY reuseItemsChanged)
Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth NOTIFY contentWidthChanged)
Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight NOTIFY contentHeightChanged)
+ Q_PROPERTY(QQuickTableView *syncView READ syncView WRITE setSyncView NOTIFY syncViewChanged REVISION 14)
+ Q_PROPERTY(Qt::Orientations syncDirection READ syncDirection WRITE setSyncDirection NOTIFY syncDirectionChanged REVISION 14)
public:
QQuickTableView(QQuickItem *parent = nullptr);
@@ -110,6 +112,12 @@ public:
void setContentWidth(qreal width);
void setContentHeight(qreal height);
+ QQuickTableView *syncView() const;
+ void setSyncView(QQuickTableView *view);
+
+ Qt::Orientations syncDirection() const;
+ void setSyncDirection(Qt::Orientations direction);
+
Q_INVOKABLE void forceLayout();
static QQuickTableViewAttached *qmlAttachedProperties(QObject *);
@@ -124,6 +132,8 @@ Q_SIGNALS:
void modelChanged();
void delegateChanged();
void reuseItemsChanged();
+ Q_REVISION(14) void syncViewChanged();
+ Q_REVISION(14) void syncDirectionChanged();
protected:
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index 6bbfd4e2d6..7f2aee9105 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -54,9 +54,9 @@
#include "qquicktableview_p.h"
#include <QtCore/qtimer.h>
-#include <QtQml/private/qqmltableinstancemodel_p.h>
+#include <QtQmlModels/private/qqmltableinstancemodel_p.h>
#include <QtQml/private/qqmlincubator_p.h>
-#include <QtQml/private/qqmlchangeset_p.h>
+#include <QtQmlModels/private/qqmlchangeset_p.h>
#include <QtQml/qqmlinfo.h>
#include <QtQuick/private/qquickflickable_p_p.h>
@@ -70,6 +70,25 @@ static const qreal kDefaultRowHeight = 50;
static const qreal kDefaultColumnWidth = 50;
class FxTableItem;
+class QQuickTableSectionSizeProviderPrivate;
+
+class Q_QUICK_PRIVATE_EXPORT QQuickTableSectionSizeProvider : public QObject {
+ Q_OBJECT
+
+public:
+ QQuickTableSectionSizeProvider(QObject *parent=nullptr);
+ void setSize(int section, qreal size);
+ qreal size(int section);
+ bool resetSize(int section);
+ void resetAll();
+
+Q_SIGNALS:
+ void sizeChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickTableSectionSizeProvider)
+ Q_DECLARE_PRIVATE(QQuickTableSectionSizeProvider)
+};
class Q_QML_AUTOTEST_EXPORT QQuickTableViewPrivate : public QQuickFlickablePrivate
{
@@ -249,9 +268,15 @@ public:
bool blockItemCreatedCallback = false;
bool layoutWarningIssued = false;
bool polishing = false;
+ bool syncVertically = false;
+ bool syncHorizontally = false;
+ bool inSetLocalViewportPos = false;
+ bool inSyncViewportPosRecursive = false;
QJSValue rowHeightProvider;
QJSValue columnWidthProvider;
+ QQuickTableSectionSizeProvider rowHeights;
+ QQuickTableSectionSizeProvider columnWidths;
EdgeRange cachedNextVisibleEdgeIndex[4];
EdgeRange cachedColumnWidth;
@@ -271,6 +296,11 @@ public:
QSizeF averageEdgeSize;
+ QPointer<QQuickTableView> assignedSyncView;
+ QPointer<QQuickTableView> syncView;
+ QList<QPointer<QQuickTableView> > syncChildren;
+ Qt::Orientations assignedSyncDirection = Qt::Horizontal | Qt::Vertical;
+
const static QPoint kLeft;
const static QPoint kRight;
const static QPoint kUp;
@@ -303,6 +333,10 @@ public:
inline int leftColumn() const { return loadedColumns.firstKey(); }
inline int rightColumn() const { return loadedColumns.lastKey(); }
+ QQuickTableView *rootSyncView() const;
+
+ bool updateTableRecursive();
+ bool updateTable();
void relayoutTable();
void relayoutTableItems();
@@ -349,7 +383,6 @@ public:
void processRebuildTable();
bool moveToNextRebuildState();
- QPoint calculateNewTopLeft();
void calculateTopLeft(QPoint &topLeft, QPointF &topLeftPos);
void beginRebuildTable();
void layoutAfterLoadingInitialTable();
@@ -369,6 +402,7 @@ public:
inline void syncDelegate();
inline void syncModel();
inline void syncRebuildOptions();
+ inline void syncSyncView();
void connectToModel();
void disconnectFromModel();
@@ -382,6 +416,11 @@ public:
void layoutChangedCallback(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
void modelResetCallback();
+ void scheduleRebuildIfFastFlick();
+ void setLocalViewportX(qreal contentX);
+ void setLocalViewportY(qreal contentY);
+ void syncViewportPosRecursive();
+
void _q_componentFinalized();
void registerCallbackWhenBindingsAreEvaluated();
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 9d0f4a6893..f3a2b07620 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -2551,7 +2551,7 @@ bool QQuickWindowPrivate::deliverPressOrReleaseEvent(QQuickPointerEvent *event,
if (point->grabberPointerHandler())
cancelTouchMouseSynthesis();
} else {
- qCWarning(DBG_TOUCH_TARGET) << "during delivery of touch press, synth-mouse ID" << touchMouseId << "is missing from" << event;
+ qCWarning(DBG_TOUCH_TARGET) << "during delivery of touch press, synth-mouse ID" << hex << touchMouseId << "is missing from" << event;
}
}
for (int i = 0; i < pointCount; ++i) {
diff --git a/src/quick/quick.pro b/src/quick/quick.pro
index 37d2ad1172..700f794af4 100644
--- a/src/quick/quick.pro
+++ b/src/quick/quick.pro
@@ -1,6 +1,6 @@
TARGET = QtQuick
-QT = core-private gui-private qml-private
+QT = core-private gui-private qml-private qmlmodels-private
qtConfig(qml-network): \
QT_PRIVATE += network
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp
index 02be9daac0..2043b50545 100644
--- a/src/quick/util/qquickanimation.cpp
+++ b/src/quick/util/qquickanimation.cpp
@@ -812,7 +812,7 @@ QQuickColorAnimation::~QQuickColorAnimation()
// States are defined here...
]
- transition: Transition {
+ transitions: Transition {
ColorAnimation { from: "#c0c0c0"; duration: 2000 }
}
}
diff --git a/src/quick/util/qquickboundaryrule.cpp b/src/quick/util/qquickboundaryrule.cpp
new file mode 100644
index 0000000000..3558c8bfa0
--- /dev/null
+++ b/src/quick/util/qquickboundaryrule.cpp
@@ -0,0 +1,574 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "qquickboundaryrule_p.h"
+
+#include <qqmlcontext.h>
+#include <qqmlinfo.h>
+#include <private/qqmlproperty_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qobject_p.h>
+#include <private/qquickanimation_p_p.h>
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcBR, "qt.quick.boundaryrule")
+
+class QQuickBoundaryReturnJob;
+class QQuickBoundaryRulePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickBoundaryRule)
+public:
+ QQuickBoundaryRulePrivate() {}
+
+ QQmlProperty property;
+ QEasingCurve easing = QEasingCurve(QEasingCurve::OutQuad);
+ QQuickBoundaryReturnJob *returnAnimationJob = nullptr;
+ // read-only properties, updated on each write()
+ qreal targetValue = 0; // after easing was applied
+ qreal peakOvershoot = 0;
+ qreal currentOvershoot = 0;
+ // settable properties
+ qreal minimum = 0;
+ qreal maximum = 0;
+ qreal minimumOvershoot = 0;
+ qreal maximumOvershoot = 0;
+ qreal overshootScale = 0.5;
+ int returnDuration = 100;
+ QQuickBoundaryRule::OvershootFilter overshootFilter = QQuickBoundaryRule::OvershootFilter::None;
+ bool enabled = true;
+ bool finalized = false;
+
+ qreal easedOvershoot(qreal overshootingValue);
+ void resetOvershoot();
+};
+
+class QQuickBoundaryReturnJob : public QAbstractAnimationJob
+{
+public:
+ QQuickBoundaryReturnJob(QQuickBoundaryRulePrivate *br, qreal to)
+ : QAbstractAnimationJob()
+ , boundaryRule(br)
+ , fromValue(br->targetValue)
+ , toValue(to) {}
+
+ int duration() const override { return boundaryRule->returnDuration; }
+
+ void updateCurrentTime(int) override;
+
+ void updateState(QAbstractAnimationJob::State newState,
+ QAbstractAnimationJob::State oldState) override;
+
+ QQuickBoundaryRulePrivate *boundaryRule;
+ qreal fromValue; // snapshot of initial value from which we're returning
+ qreal toValue; // target property value to which we're returning
+};
+
+void QQuickBoundaryReturnJob::updateCurrentTime(int t)
+{
+ // The easing property tells how to behave when the property is being
+ // externally manipulated beyond the bounds. During returnToBounds()
+ // we run it in reverse, by reversing time.
+ qreal progress = (duration() - t) / qreal(duration());
+ qreal easingValue = boundaryRule->easing.valueForProgress(progress);
+ qreal delta = qAbs(fromValue - toValue) * easingValue;
+ qreal value = (fromValue > toValue ? toValue + delta : toValue - delta);
+ qCDebug(lcBR) << t << "ms" << qRound(progress * 100) << "% easing" << easingValue << "->" << value;
+ QQmlPropertyPrivate::write(boundaryRule->property, value,
+ QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
+}
+
+void QQuickBoundaryReturnJob::updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState)
+{
+ Q_UNUSED(oldState)
+ if (newState == QAbstractAnimationJob::Stopped) {
+ qCDebug(lcBR) << "return animation done";
+ boundaryRule->resetOvershoot();
+ boundaryRule->returnAnimationJob = nullptr;
+ delete this;
+ }
+}
+
+/*!
+ \qmltype BoundaryRule
+ \instantiates QQuickBoundaryRule
+ \inqmlmodule Qt.labs.animation
+ \ingroup qtquick-transitions-animations
+ \ingroup qtquick-interceptors
+ \brief Defines a restriction on the range of values that can be set on a numeric property.
+ \since 5.14
+
+ A BoundaryRule defines the range of values that a particular property is
+ allowed to have. When an out-of-range value would otherwise be set,
+ it applies "resistance" via an easing curve.
+
+ For example, the following BoundaryRule prevents DragHandler from dragging
+ the Rectangle too far:
+
+ \snippet qml/boundaryRule.qml 0
+
+ Note that a property cannot have more than one assigned BoundaryRule.
+
+ \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation#Behaviors}{Behavior example}, {Qt QML}
+*/
+
+QQuickBoundaryRule::QQuickBoundaryRule(QObject *parent)
+ : QObject(*(new QQuickBoundaryRulePrivate), parent)
+ , QQmlPropertyValueInterceptor()
+{
+}
+
+QQuickBoundaryRule::~QQuickBoundaryRule()
+{
+ Q_D(QQuickBoundaryRule);
+ // stop any running animation and
+ // prevent QQuickBoundaryReturnJob::updateState() from accessing QQuickBoundaryRulePrivate
+ delete d->returnAnimationJob;
+}
+
+/*!
+ \qmlproperty bool QtQuick::BoundaryRule::enabled
+
+ This property holds whether the rule will be enforced when the tracked
+ property changes value.
+
+ By default a BoundaryRule is enabled.
+*/
+bool QQuickBoundaryRule::enabled() const
+{
+ Q_D(const QQuickBoundaryRule);
+ return d->enabled;
+}
+
+void QQuickBoundaryRule::setEnabled(bool enabled)
+{
+ Q_D(QQuickBoundaryRule);
+ if (d->enabled == enabled)
+ return;
+ d->enabled = enabled;
+ emit enabledChanged();
+}
+
+/*!
+ \qmlproperty qreal QtQuick::BoundaryRule::minimum
+
+ This property holds the smallest unconstrained value that the property is
+ allowed to have. If the property is set to a smaller value, it will be
+ constrained by \l easing and \l minimumOvershoot.
+
+ The default is \c 0.
+*/
+qreal QQuickBoundaryRule::minimum() const
+{
+ Q_D(const QQuickBoundaryRule);
+ return d->minimum;
+}
+
+void QQuickBoundaryRule::setMinimum(qreal minimum)
+{
+ Q_D(QQuickBoundaryRule);
+ if (qFuzzyCompare(d->minimum, minimum))
+ return;
+ d->minimum = minimum;
+ emit minimumChanged();
+}
+
+/*!
+ \qmlproperty qreal QtQuick::BoundaryRule::minimumOvershoot
+
+ This property holds the amount that the property is allowed to be
+ less than \l minimum. Whenever the value is less than \l minimum
+ and greater than \c {minimum - minimumOvershoot}, it is constrained
+ by the \l easing curve. When the value attempts to go under
+ \c {minimum - minimumOvershoots} there is a hard stop.
+
+ The default is \c 0.
+*/
+qreal QQuickBoundaryRule::minimumOvershoot() const
+{
+ Q_D(const QQuickBoundaryRule);
+ return d->minimumOvershoot;
+}
+
+void QQuickBoundaryRule::setMinimumOvershoot(qreal minimumOvershoot)
+{
+ Q_D(QQuickBoundaryRule);
+ if (qFuzzyCompare(d->minimumOvershoot, minimumOvershoot))
+ return;
+ d->minimumOvershoot = minimumOvershoot;
+ emit minimumOvershootChanged();
+}
+
+/*!
+ \qmlproperty qreal QtQuick::BoundaryRule::maximum
+
+ This property holds the largest unconstrained value that the property is
+ allowed to have. If the property is set to a larger value, it will be
+ constrained by \l easing and \l maximumOvershoot.
+
+ The default is \c 1.
+*/
+qreal QQuickBoundaryRule::maximum() const
+{
+ Q_D(const QQuickBoundaryRule);
+ return d->maximum;
+}
+
+void QQuickBoundaryRule::setMaximum(qreal maximum)
+{
+ Q_D(QQuickBoundaryRule);
+ if (qFuzzyCompare(d->maximum, maximum))
+ return;
+ d->maximum = maximum;
+ emit maximumChanged();
+}
+
+/*!
+ \qmlproperty qreal QtQuick::BoundaryRule::maximumOvershoot
+
+ This property holds the amount that the property is allowed to be
+ more than \l maximum. Whenever the value is greater than \l maximum
+ and less than \c {maximum + maximumOvershoot}, it is constrained
+ by the \l easing curve. When the value attempts to exceed
+ \c {maximum + maximumOvershoot} there is a hard stop.
+
+ The default is 0.
+*/
+qreal QQuickBoundaryRule::maximumOvershoot() const
+{
+ Q_D(const QQuickBoundaryRule);
+ return d->maximumOvershoot;
+}
+
+void QQuickBoundaryRule::setMaximumOvershoot(qreal maximumOvershoot)
+{
+ Q_D(QQuickBoundaryRule);
+ if (qFuzzyCompare(d->maximumOvershoot, maximumOvershoot))
+ return;
+ d->maximumOvershoot = maximumOvershoot;
+ emit maximumOvershootChanged();
+}
+
+/*!
+ \qmlproperty qreal QtQuick::BoundaryRule::overshootScale
+
+ This property holds the amount by which the \l easing is scaled during the
+ overshoot condition. For example if an Item is restricted from moving more
+ than 100 pixels beyond some limit, and the user (by means of some Input
+ Handler) is trying to drag it 100 pixels past the limit, if overshootScale
+ is set to 1, the user will succeed: the only effect of the easing curve is
+ to change the rate at which the item moves from overshoot 0 to overshoot
+ 100. But if it is set to 0.5, the BoundaryRule provides resistance such
+ that when the user tries to move 100 pixels, the Item will only move 50
+ pixels; and the easing curve modulates the rate of movement such that it
+ may move in sync with the user's attempted movement at the beginning, and
+ then slows down, depending on the shape of the easing curve.
+
+ The default is 0.5.
+*/
+qreal QQuickBoundaryRule::overshootScale() const
+{
+ Q_D(const QQuickBoundaryRule);
+ return d->overshootScale;
+}
+
+void QQuickBoundaryRule::setOvershootScale(qreal overshootScale)
+{
+ Q_D(QQuickBoundaryRule);
+ if (qFuzzyCompare(d->overshootScale, overshootScale))
+ return;
+ d->overshootScale = overshootScale;
+ emit overshootScaleChanged();
+}
+
+/*!
+ \qmlproperty qreal QtQuick::BoundaryRule::currentOvershoot
+
+ This property holds the amount by which the most recently set value of the
+ intercepted property exceeds \l maximum or is less than \l minimum.
+
+ It is positive if the property value exceeds \l maximum, negative if the
+ property value is less than \l minimum, or 0 if the property value is
+ within both boundaries.
+*/
+qreal QQuickBoundaryRule::currentOvershoot() const
+{
+ Q_D(const QQuickBoundaryRule);
+ return d->currentOvershoot;
+}
+
+/*!
+ \qmlproperty qreal QtQuick::BoundaryRule::peakOvershoot
+
+ This property holds the most-positive or most-negative value of
+ \l currentOvershoot that has been seen, until \l returnToBounds() is called.
+
+ This can be useful when the intercepted property value is known to
+ fluctuate, and you want to find and react to the maximum amount of
+ overshoot rather than to the fluctuations.
+
+ \sa overshootFilter
+*/
+qreal QQuickBoundaryRule::peakOvershoot() const
+{
+ Q_D(const QQuickBoundaryRule);
+ return d->peakOvershoot;
+}
+
+/*!
+ \qmlproperty enum QtQuick::BoundaryRule::overshootFilter
+
+ This property specifies the aggregation function that will be applied to
+ the intercepted property value.
+
+ If this is set to \c BoundaryRule.None (the default), the intercepted
+ property will hold a value whose overshoot is limited to \l currentOvershoot.
+ If this is set to \c BoundaryRule.Peak, the intercepted property will hold
+ a value whose overshoot is limited to \l peakOvershoot.
+*/
+QQuickBoundaryRule::OvershootFilter QQuickBoundaryRule::overshootFilter() const
+{
+ Q_D(const QQuickBoundaryRule);
+ return d->overshootFilter;
+}
+
+void QQuickBoundaryRule::setOvershootFilter(OvershootFilter overshootFilter)
+{
+ Q_D(QQuickBoundaryRule);
+ if (d->overshootFilter == overshootFilter)
+ return;
+ d->overshootFilter = overshootFilter;
+ emit overshootFilterChanged();
+}
+
+/*!
+ \qmlmethod bool QtQuick::BoundaryRule::returnToBounds
+
+ Returns the intercepted property to a value between \l minimum and
+ \l maximum, such that \l currentOvershoot and \l peakOvershoot are both
+ zero. This will be animated if \l returnDuration is greater than zero.
+
+ Returns true if the value needed to be adjusted, or false if it was already
+ within bounds.
+*/
+bool QQuickBoundaryRule::returnToBounds()
+{
+ Q_D(QQuickBoundaryRule);
+ if (d->returnAnimationJob) {
+ qCDebug(lcBR) << "animation already in progress";
+ return true;
+ }
+ if (currentOvershoot() > 0) {
+ if (d->returnDuration > 0)
+ d->returnAnimationJob = new QQuickBoundaryReturnJob(d, maximum());
+ else
+ write(maximum());
+ } else if (currentOvershoot() < 0) {
+ if (d->returnDuration > 0)
+ d->returnAnimationJob = new QQuickBoundaryReturnJob(d, minimum());
+ else
+ write(minimum());
+ } else {
+ return false;
+ }
+ if (d->returnAnimationJob) {
+ qCDebug(lcBR) << "animating from" << d->returnAnimationJob->fromValue << "to" << d->returnAnimationJob->toValue;
+ d->returnAnimationJob->start();
+ } else {
+ d->resetOvershoot();
+ qCDebug(lcBR) << "returned to" << d->property.read();
+ }
+ return true;
+}
+
+/*!
+ \qmlproperty qreal QtQuick::BoundaryRule::easing
+
+ This property holds the easing curve to be applied in overshoot mode
+ (whenever the \l minimum or \l maximum constraint is violated, while
+ the value is still within the respective overshoot range).
+
+ The default easing curve is \l QEasingCurve::OutQuad.
+*/
+QEasingCurve QQuickBoundaryRule::easing() const
+{
+ Q_D(const QQuickBoundaryRule);
+ return d->easing;
+}
+
+void QQuickBoundaryRule::setEasing(const QEasingCurve &easing)
+{
+ Q_D(QQuickBoundaryRule);
+ if (d->easing == easing)
+ return;
+ d->easing = easing;
+ emit easingChanged();
+}
+
+/*!
+ \qmlproperty int QtQuick::BoundaryRule::returnDuration
+
+ This property holds the amount of time in milliseconds that
+ \l returnToBounds() will take to return the target property to the nearest bound.
+ If it is set to 0, returnToBounds() will set the property immediately
+ rather than creating an animation job.
+
+ The default is 100 ms.
+*/
+int QQuickBoundaryRule::returnDuration() const
+{
+ Q_D(const QQuickBoundaryRule);
+ return d->returnDuration;
+}
+
+void QQuickBoundaryRule::setReturnDuration(int duration)
+{
+ Q_D(QQuickBoundaryRule);
+ if (d->returnDuration == duration)
+ return;
+ d->returnDuration = duration;
+ emit returnDurationChanged();
+}
+
+void QQuickBoundaryRule::write(const QVariant &value)
+{
+ bool conversionOk = false;
+ qreal rValue = value.toReal(&conversionOk);
+ if (!conversionOk) {
+ qWarning() << "BoundaryRule doesn't work with non-numeric values:" << value;
+ return;
+ }
+ Q_D(QQuickBoundaryRule);
+ bool bypass = !d->enabled || !d->finalized || QQmlEnginePrivate::designerMode();
+ if (bypass) {
+ QQmlPropertyPrivate::write(d->property, value,
+ QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
+ return;
+ }
+
+ qmlExecuteDeferred(this);
+ d->targetValue = d->easedOvershoot(rValue);
+ QQmlPropertyPrivate::write(d->property, d->targetValue,
+ QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
+}
+
+void QQuickBoundaryRule::setTarget(const QQmlProperty &property)
+{
+ Q_D(QQuickBoundaryRule);
+ d->property = property;
+
+ QQmlEnginePrivate *engPriv = QQmlEnginePrivate::get(qmlEngine(this));
+ static int finalizedIdx = -1;
+ if (finalizedIdx < 0)
+ finalizedIdx = metaObject()->indexOfSlot("componentFinalized()");
+ engPriv->registerFinalizeCallback(this, finalizedIdx);
+}
+
+void QQuickBoundaryRule::componentFinalized()
+{
+ Q_D(QQuickBoundaryRule);
+ d->finalized = true;
+}
+
+/*!
+ \internal
+ Given that something is trying to set the target property to \a value,
+ this function applies the easing curve and returns the value that the
+ property should actually get instead.
+*/
+qreal QQuickBoundaryRulePrivate::easedOvershoot(qreal value)
+{
+ qreal ret = value;
+ Q_Q(QQuickBoundaryRule);
+ if (value > maximum) {
+ qreal overshootWas = currentOvershoot;
+ currentOvershoot = value - maximum;
+ if (!qFuzzyCompare(overshootWas, currentOvershoot))
+ emit q->currentOvershootChanged();
+ overshootWas = peakOvershoot;
+ peakOvershoot = qMax(currentOvershoot, peakOvershoot);
+ if (!qFuzzyCompare(overshootWas, peakOvershoot))
+ emit q->peakOvershootChanged();
+ ret = maximum + maximumOvershoot * easing.valueForProgress(
+ (overshootFilter == QQuickBoundaryRule::OvershootFilter::Peak ? peakOvershoot : currentOvershoot)
+ * overshootScale / maximumOvershoot);
+ qCDebug(lcBR).nospace() << value << " overshoots maximum " << maximum << " by "
+ << currentOvershoot << " (peak " << peakOvershoot << "): eased to " << ret;
+ } else if (value < minimum) {
+ qreal overshootWas = currentOvershoot;
+ currentOvershoot = value - minimum;
+ if (!qFuzzyCompare(overshootWas, currentOvershoot))
+ emit q->currentOvershootChanged();
+ overshootWas = peakOvershoot;
+ peakOvershoot = qMin(currentOvershoot, peakOvershoot);
+ if (!qFuzzyCompare(overshootWas, peakOvershoot))
+ emit q->peakOvershootChanged();
+ ret = minimum - minimumOvershoot * easing.valueForProgress(
+ -(overshootFilter == QQuickBoundaryRule::OvershootFilter::Peak ? peakOvershoot : currentOvershoot)
+ * overshootScale / minimumOvershoot);
+ qCDebug(lcBR).nospace() << value << " overshoots minimum " << minimum << " by "
+ << currentOvershoot << " (peak " << peakOvershoot << "): eased to " << ret;
+ } else {
+ resetOvershoot();
+ }
+ return ret;
+}
+
+/*!
+ \internal
+ Resets the currentOvershoot and peakOvershoot
+ properties to zero.
+*/
+void QQuickBoundaryRulePrivate::resetOvershoot()
+{
+ Q_Q(QQuickBoundaryRule);
+ if (!qFuzzyCompare(peakOvershoot, 0)) {
+ peakOvershoot = 0;
+ emit q->peakOvershootChanged();
+ }
+ if (!qFuzzyCompare(currentOvershoot, 0)) {
+ currentOvershoot = 0;
+ emit q->currentOvershootChanged();
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickboundaryrule_p.cpp"
diff --git a/src/quick/util/qquickboundaryrule_p.h b/src/quick/util/qquickboundaryrule_p.h
new file mode 100644
index 0000000000..3325b675c5
--- /dev/null
+++ b/src/quick/util/qquickboundaryrule_p.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 QQUICKBOUNDARYRULE_H
+#define QQUICKBOUNDARYRULE_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 <private/qtquickglobal_p.h>
+
+#include <private/qqmlpropertyvalueinterceptor_p.h>
+#include <qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickAbstractAnimation;
+class QQuickBoundaryRulePrivate;
+class Q_QUICK_PRIVATE_EXPORT QQuickBoundaryRule : public QObject, public QQmlPropertyValueInterceptor
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQuickBoundaryRule)
+
+ Q_INTERFACES(QQmlPropertyValueInterceptor)
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(qreal minimum READ minimum WRITE setMinimum NOTIFY minimumChanged)
+ Q_PROPERTY(qreal minimumOvershoot READ minimumOvershoot WRITE setMinimumOvershoot NOTIFY minimumOvershootChanged)
+ Q_PROPERTY(qreal maximum READ maximum WRITE setMaximum NOTIFY maximumChanged)
+ Q_PROPERTY(qreal maximumOvershoot READ maximumOvershoot WRITE setMaximumOvershoot NOTIFY maximumOvershootChanged)
+ Q_PROPERTY(qreal overshootScale READ overshootScale WRITE setOvershootScale NOTIFY overshootScaleChanged)
+ Q_PROPERTY(qreal currentOvershoot READ currentOvershoot NOTIFY currentOvershootChanged)
+ Q_PROPERTY(qreal peakOvershoot READ peakOvershoot NOTIFY peakOvershootChanged)
+ Q_PROPERTY(OvershootFilter overshootFilter READ overshootFilter WRITE setOvershootFilter NOTIFY overshootFilterChanged)
+ Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing NOTIFY easingChanged)
+ Q_PROPERTY(int returnDuration READ returnDuration WRITE setReturnDuration NOTIFY returnDurationChanged)
+
+public:
+ enum OvershootFilter {
+ None,
+ Peak
+ };
+ Q_ENUM(OvershootFilter)
+
+ QQuickBoundaryRule(QObject *parent=nullptr);
+ ~QQuickBoundaryRule();
+
+ void setTarget(const QQmlProperty &) override;
+ void write(const QVariant &value) override;
+
+ bool enabled() const;
+ void setEnabled(bool enabled);
+
+ qreal minimum() const;
+ void setMinimum(qreal minimum);
+ qreal minimumOvershoot() const;
+ void setMinimumOvershoot(qreal minimum);
+
+ qreal maximum() const;
+ void setMaximum(qreal maximum);
+ qreal maximumOvershoot() const;
+ void setMaximumOvershoot(qreal maximum);
+
+ qreal overshootScale() const;
+ void setOvershootScale(qreal scale);
+
+ qreal currentOvershoot() const;
+ qreal peakOvershoot() const;
+
+ OvershootFilter overshootFilter() const;
+ void setOvershootFilter(OvershootFilter overshootFilter);
+
+ Q_INVOKABLE bool returnToBounds();
+
+ QEasingCurve easing() const;
+ void setEasing(const QEasingCurve &easing);
+
+ int returnDuration() const;
+ void setReturnDuration(int duration);
+
+Q_SIGNALS:
+ void enabledChanged();
+ void minimumChanged();
+ void minimumOvershootChanged();
+ void maximumChanged();
+ void maximumOvershootChanged();
+ void overshootScaleChanged();
+ void currentOvershootChanged();
+ void peakOvershootChanged();
+ void overshootFilterChanged();
+ void easingChanged();
+ void returnDurationChanged();
+
+private Q_SLOTS:
+ void componentFinalized();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickBoundaryRule)
+
+#endif // QQUICKBOUNDARYRULE_H
diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri
index c51f082d03..63d995e34c 100644
--- a/src/quick/util/util.pri
+++ b/src/quick/util/util.pri
@@ -15,6 +15,7 @@ SOURCES += \
$$PWD/qquicktimeline.cpp \
$$PWD/qquickpixmapcache.cpp \
$$PWD/qquickbehavior.cpp \
+ $$PWD/qquickboundaryrule.cpp \
$$PWD/qquickfontloader.cpp \
$$PWD/qquickstyledtext.cpp \
$$PWD/qquickimageprovider.cpp \
@@ -50,6 +51,7 @@ HEADERS += \
$$PWD/qquicktimeline_p_p.h \
$$PWD/qquickpixmapcache_p.h \
$$PWD/qquickbehavior_p.h \
+ $$PWD/qquickboundaryrule_p.h \
$$PWD/qquickfontloader_p.h \
$$PWD/qquickstyledtext_p.h \
$$PWD/qquickimageprovider.h \
diff --git a/src/src.pro b/src/src.pro
index 1b2b4ef6f8..bd634247e7 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -4,7 +4,9 @@ include($$OUT_PWD/qml/qtqml-config.pri)
include($$OUT_PWD/quick/qtquick-config.pri)
QT_FOR_CONFIG += qml qml-private quick-private
SUBDIRS += \
- qml
+ qml \
+ qmlmodels
+
qtHaveModule(gui):qtConfig(qml-animation) {
SUBDIRS += \