aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2017-04-25 09:40:04 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2017-04-25 09:40:04 +0200
commitb334a92493c9e4956b0fc631610857d1b1cf5f6d (patch)
treebdc85d9b49f4b8d666b34e4d87abf629f579f1e2
parent0eeb7ada04cc81d0ab1b61747bdf92fd7c33e1ec (diff)
parent27079f9168463b5b27aeb2d1f93f867bf714e71a (diff)
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
-rw-r--r--examples/quick/customitems/painteditem/textballoon.cpp15
-rw-r--r--examples/quick/demos/photoviewer/main.cpp4
-rw-r--r--examples/quick/demos/photoviewer/photoviewer.pro2
-rw-r--r--examples/quick/scenegraph/customgeometry/beziercurve.cpp6
-rw-r--r--src/3rdparty/masm/masm-defs.pri7
-rw-r--r--src/3rdparty/masm/wtf/Assertions.h2
-rw-r--r--src/imports/imports.pro4
-rw-r--r--src/imports/localstorage/plugin.cpp2
-rw-r--r--src/imports/testlib/TestCase.qml61
-rw-r--r--src/particles/qquickimageparticle.cpp7
-rw-r--r--src/particles/qquickparticlesystem.cpp14
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp13
-rw-r--r--src/plugins/qmltooling/qmltooling.pro29
-rw-r--r--src/qml/compiler/compiler.pri6
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp343
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h80
-rw-r--r--src/qml/compiler/qv4codegen.cpp37
-rw-r--r--src/qml/compiler/qv4compileddata.cpp19
-rw-r--r--src/qml/compiler/qv4compileddata_p.h2
-rw-r--r--src/qml/compiler/qv4compiler.cpp2
-rw-r--r--src/qml/compiler/qv4isel_util_p.h76
-rw-r--r--src/qml/compiler/qv4jsir_p.h1
-rw-r--r--src/qml/compiler/qv4jssimplifier.cpp384
-rw-r--r--src/qml/compiler/qv4jssimplifier_p.h154
-rw-r--r--src/qml/compiler/qv4ssa.cpp2
-rw-r--r--src/qml/doc/src/cppintegration/data.qdoc18
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc2
-rw-r--r--src/qml/doc/src/cppintegration/exposecppattributes.qdoc2
-rw-r--r--src/qml/jit/qv4assembler.cpp27
-rw-r--r--src/qml/jit/qv4assembler_p.h121
-rw-r--r--src/qml/jit/qv4isel_masm.cpp44
-rw-r--r--src/qml/jit/qv4isel_masm_p.h2
-rw-r--r--src/qml/jit/qv4regalloc.cpp2
-rw-r--r--src/qml/jit/qv4targetplatform_p.h2
-rw-r--r--src/qml/jsapi/qjsengine.cpp2
-rw-r--r--src/qml/jsapi/qjsvalue.h6
-rw-r--r--src/qml/jsruntime/qv4context.cpp5
-rw-r--r--src/qml/jsruntime/qv4engine.cpp55
-rw-r--r--src/qml/jsruntime/qv4engine_p.h35
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp1
-rw-r--r--src/qml/jsruntime/qv4identifiertable.cpp1
-rw-r--r--src/qml/jsruntime/qv4identifiertable_p.h4
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp4
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h2
-rw-r--r--src/qml/jsruntime/qv4managed_p.h3
-rw-r--r--src/qml/jsruntime/qv4objectiterator.cpp8
-rw-r--r--src/qml/jsruntime/qv4objectiterator_p.h2
-rw-r--r--src/qml/jsruntime/qv4persistent.cpp12
-rw-r--r--src/qml/jsruntime/qv4persistent_p.h4
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp32
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h17
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp2
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h2
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp77
-rw-r--r--src/qml/jsruntime/qv4string.cpp6
-rw-r--r--src/qml/jsruntime/qv4string_p.h2
-rw-r--r--src/qml/jsruntime/qv4value.cpp3
-rw-r--r--src/qml/jsruntime/qv4value_p.h60
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp29
-rw-r--r--src/qml/memory/qv4heap_p.h6
-rw-r--r--src/qml/memory/qv4mm.cpp295
-rw-r--r--src/qml/memory/qv4mm_p.h18
-rw-r--r--src/qml/memory/qv4mmdefs_p.h26
-rw-r--r--src/qml/memory/qv4writebarrier_p.h38
-rw-r--r--src/qml/parser/qqmljsglobal_p.h16
-rw-r--r--src/qml/qml.pro4
-rw-r--r--src/qml/qml/qqmldata_p.h8
-rw-r--r--src/qml/qml/qqmlengine.cpp34
-rw-r--r--src/qml/qml/qqmlerror.cpp3
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp4
-rw-r--r--src/qml/qml/qqmlproperty.cpp2
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp8
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h2
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp2
-rw-r--r--src/qml/types/qqmlconnections.cpp5
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp11
-rw-r--r--src/qml/types/types.pri10
-rw-r--r--src/quick/accessible/qaccessiblequickitem.cpp3
-rw-r--r--src/quick/designer/qquickdesignersupport.cpp5
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp21
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp8
-rw-r--r--src/quick/items/qquickdrag_p.h2
-rw-r--r--src/quick/items/qquickevents.cpp17
-rw-r--r--src/quick/items/qquickflickable.cpp122
-rw-r--r--src/quick/items/qquickflickable_p.h11
-rw-r--r--src/quick/items/qquickflickable_p_p.h1
-rw-r--r--src/quick/items/qquickimage.cpp3
-rw-r--r--src/quick/items/qquickitem.cpp40
-rw-r--r--src/quick/items/qquickitem_p.h7
-rw-r--r--src/quick/items/qquickitemsmodule.cpp2
-rw-r--r--src/quick/items/qquickmultipointtoucharea.cpp2
-rw-r--r--src/quick/items/qquickpositioners.cpp100
-rw-r--r--src/quick/items/qquickpositioners_p.h35
-rw-r--r--src/quick/items/qquickpositioners_p_p.h41
-rw-r--r--src/quick/items/qquickrendercontrol.cpp3
-rw-r--r--src/quick/items/qquicktext.cpp10
-rw-r--r--src/quick/items/qquicktextcontrol.cpp46
-rw-r--r--src/quick/items/qquicktextinput.cpp3
-rw-r--r--src/quick/items/qquickwindow.cpp5
-rw-r--r--src/quick/items/qquickwindow.h4
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.cpp4
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp1
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp1
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp1
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp1
-rw-r--r--src/quick/scenegraph/util/qsgengine.cpp2
-rw-r--r--src/quick/scenegraph/util/qsgshadersourcebuilder.cpp4
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp2
-rw-r--r--src/quick/util/qquickanimatorjob.cpp39
-rw-r--r--src/quick/util/qquickanimatorjob_p.h1
-rw-r--r--src/quick/util/qquickfontloader.cpp4
-rw-r--r--src/quick/util/qquickglobal.cpp1
-rw-r--r--src/quick/util/qquickimageprovider.cpp45
-rw-r--r--src/quick/util/qquickimageprovider.h1
-rw-r--r--src/quick/util/qquickpixmapcache.cpp59
-rw-r--r--src/quick/util/qquickpixmapcache_p.h3
-rw-r--r--src/quick/util/qquickshortcut_p.h1
-rw-r--r--src/quickwidgets/qquickwidget.cpp14
-rw-r--r--tests/auto/particles/qquickparticlesystem/data/crashaffectors.qml43
-rw-r--r--tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp7
-rw-r--r--tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp71
-rw-r--r--tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp68
-rw-r--r--tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp1
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp15
-rw-r--r--tests/auto/qml/qml.pro1
-rw-r--r--tests/auto/qml/qmlcachegen/qmlcachegen.pro7
-rw-r--r--tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp163
-rw-r--r--tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp8
-rw-r--r--tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml15
-rw-r--r--tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp10
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceSort.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.cpp24
-rw-r--r--tests/auto/qml/qqmlengine/data/testGCCorruption.qml29
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp11
-rw-r--r--tests/auto/qmltest/animatedimage/animatedimage.pro1
-rw-r--r--tests/auto/qmltest/animations/animations.pro1
-rw-r--r--tests/auto/qmltest/borderimage/borderimage.pro1
-rw-r--r--tests/auto/qmltest/buttonclick/buttonclick.pro1
-rw-r--r--tests/auto/qmltest/createbenchmark/createbenchmark.pro1
-rw-r--r--tests/auto/qmltest/events/events.pro1
-rw-r--r--tests/auto/qmltest/fontloader/fontloader.pro1
-rw-r--r--tests/auto/qmltest/gradient/gradient.pro1
-rw-r--r--tests/auto/qmltest/image/image.pro1
-rw-r--r--tests/auto/qmltest/itemgrabber/itemgrabber.pro1
-rw-r--r--tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml4
-rw-r--r--tests/auto/qmltest/layout/layout.pro1
-rw-r--r--tests/auto/qmltest/listmodel/listmodel.pro1
-rw-r--r--tests/auto/qmltest/listview/BLACKLIST4
-rw-r--r--tests/auto/qmltest/listview/listview.pro1
-rw-r--r--tests/auto/qmltest/objectmodel/objectmodel.pro1
-rw-r--r--tests/auto/qmltest/pathview/pathview.pro1
-rw-r--r--tests/auto/qmltest/pixel/pixel.pro1
-rw-r--r--tests/auto/qmltest/positioners/positioners.pro1
-rw-r--r--tests/auto/qmltest/qmltest.pro44
-rw-r--r--tests/auto/qmltest/qqmlbinding/qqmlbinding.pro1
-rw-r--r--tests/auto/qmltest/qtbug46798/qtbug46798.pro1
-rw-r--r--tests/auto/qmltest/rectangle/rectangle.pro1
-rw-r--r--tests/auto/qmltest/selftests/BLACKLIST (renamed from tests/auto/qmltest/BLACKLIST)6
-rw-r--r--tests/auto/qmltest/selftests/selftests.pro1
-rw-r--r--tests/auto/qmltest/selftests/tst_grabImage.qml2
-rw-r--r--tests/auto/qmltest/selftests/tst_selftests.qml10
-rw-r--r--tests/auto/qmltest/shadersource/BLACKLIST3
-rw-r--r--tests/auto/qmltest/shadersource/shadersource.pro1
-rw-r--r--tests/auto/qmltest/stability/stability.pro1
-rw-r--r--tests/auto/qmltest/statemachine/statemachine.pro1
-rw-r--r--tests/auto/qmltest/text/text.pro1
-rw-r--r--tests/auto/qmltest/textedit/BLACKLIST6
-rw-r--r--tests/auto/qmltest/textedit/textedit.pro1
-rw-r--r--tests/auto/qmltest/textinput/textinput.pro1
-rw-r--r--tests/auto/qmltest/tst_qmltest.cpp30
-rw-r--r--tests/auto/qmltest/window/window.pro1
-rw-r--r--tests/auto/quick/qquickapplication/BLACKLIST2
-rw-r--r--tests/auto/quick/qquickflickable/BLACKLIST2
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp155
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/BLACKLIST4
-rw-r--r--tests/auto/quick/qquickpositioners/data/implicitGridOneItem.qml12
-rw-r--r--tests/auto/quick/qquickpositioners/data/implicitRowOneItem.qml9
-rw-r--r--tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp44
-rw-r--r--tests/auto/quick/qquickwindow/BLACKLIST4
-rw-r--r--tools/qml/main.cpp11
-rw-r--r--tools/qmlcachegen/qmlcache.prf5
-rw-r--r--tools/qmlcachegen/qmlcachegen.cpp23
-rw-r--r--tools/qmlprofiler/qmlprofilerdata.cpp10
-rw-r--r--tools/qmlscene/main.cpp87
-rw-r--r--tools/tools.pro5
187 files changed, 2399 insertions, 1635 deletions
diff --git a/examples/quick/customitems/painteditem/textballoon.cpp b/examples/quick/customitems/painteditem/textballoon.cpp
index 1713cc762f..bd8248e65e 100644
--- a/examples/quick/customitems/painteditem/textballoon.cpp
+++ b/examples/quick/customitems/painteditem/textballoon.cpp
@@ -67,23 +67,24 @@ void TextBalloon::paint(QPainter *painter)
painter->setPen(Qt::NoPen);
painter->setRenderHint(QPainter::Antialiasing);
- painter->drawRoundedRect(0, 0, boundingRect().width(), boundingRect().height() - 10, 10, 10);
+ QSizeF itemSize = size();
+ painter->drawRoundedRect(0, 0, itemSize.width(), itemSize.height() - 10, 10, 10);
if (rightAligned)
{
const QPointF points[3] = {
- QPointF(boundingRect().width() - 10.0, boundingRect().height() - 10.0),
- QPointF(boundingRect().width() - 20.0, boundingRect().height()),
- QPointF(boundingRect().width() - 30.0, boundingRect().height() - 10.0),
+ QPointF(itemSize.width() - 10.0, itemSize.height() - 10.0),
+ QPointF(itemSize.width() - 20.0, itemSize.height()),
+ QPointF(itemSize.width() - 30.0, itemSize.height() - 10.0),
};
painter->drawConvexPolygon(points, 3);
}
else
{
const QPointF points[3] = {
- QPointF(10.0, boundingRect().height() - 10.0),
- QPointF(20.0, boundingRect().height()),
- QPointF(30.0, boundingRect().height() - 10.0),
+ QPointF(10.0, itemSize.height() - 10.0),
+ QPointF(20.0, itemSize.height()),
+ QPointF(30.0, itemSize.height() - 10.0),
};
painter->drawConvexPolygon(points, 3);
}
diff --git a/examples/quick/demos/photoviewer/main.cpp b/examples/quick/demos/photoviewer/main.cpp
index 172d14307e..a269a61dcb 100644
--- a/examples/quick/demos/photoviewer/main.cpp
+++ b/examples/quick/demos/photoviewer/main.cpp
@@ -48,14 +48,14 @@
**
****************************************************************************/
-#include <QApplication>
+#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QTranslator>
#include <QDebug>
int main(int argc, char *argv[])
{
- QApplication app(argc, argv);
+ QGuiApplication app(argc, argv);
QTranslator qtTranslator;
qtTranslator.load("qml_" + QLocale::system().name(), ":/i18n/");
diff --git a/examples/quick/demos/photoviewer/photoviewer.pro b/examples/quick/demos/photoviewer/photoviewer.pro
index 4bfdb86f31..68e43e13f9 100644
--- a/examples/quick/demos/photoviewer/photoviewer.pro
+++ b/examples/quick/demos/photoviewer/photoviewer.pro
@@ -1,6 +1,6 @@
TEMPLATE = app
-QT += qml quick widgets xmlpatterns
+QT += qml quick xmlpatterns
SOURCES += main.cpp
diff --git a/examples/quick/scenegraph/customgeometry/beziercurve.cpp b/examples/quick/scenegraph/customgeometry/beziercurve.cpp
index ca3c6f524b..750ff6aa3b 100644
--- a/examples/quick/scenegraph/customgeometry/beziercurve.cpp
+++ b/examples/quick/scenegraph/customgeometry/beziercurve.cpp
@@ -152,7 +152,7 @@ QSGNode *BezierCurve::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
//! [7]
//! [8]
- QRectF bounds = boundingRect();
+ QSizeF itemSize = size();
QSGGeometry::Point2D *vertices = geometry->vertexDataAsPoint2D();
for (int i = 0; i < m_segmentCount; ++i) {
qreal t = i / qreal(m_segmentCount - 1);
@@ -163,8 +163,8 @@ QSGNode *BezierCurve::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+ 3 * invt * t * t * m_p3
+ t * t * t * m_p4;
- float x = bounds.x() + pos.x() * bounds.width();
- float y = bounds.y() + pos.y() * bounds.height();
+ float x = pos.x() * itemSize.width();
+ float y = pos.y() * itemSize.height();
vertices[i].set(x, y);
}
diff --git a/src/3rdparty/masm/masm-defs.pri b/src/3rdparty/masm/masm-defs.pri
index fa0d3d3c55..c0c5f3d114 100644
--- a/src/3rdparty/masm/masm-defs.pri
+++ b/src/3rdparty/masm/masm-defs.pri
@@ -40,3 +40,10 @@ INCLUDEPATH += $$PWD/disassembler/udis86
INCLUDEPATH += $$_OUT_PWD
CONFIG(release, debug|release): DEFINES += NDEBUG
+
+!intel_icc:!clang:gcc {
+ greaterThan(QT_GCC_MAJOR_VERSION, 6) { # GCC 7
+ QMAKE_CXXFLAGS_WARN_ON += -Wno-expansion-to-defined
+ QMAKE_CXXFLAGS += -Wno-expansion-to-defined
+ }
+}
diff --git a/src/3rdparty/masm/wtf/Assertions.h b/src/3rdparty/masm/wtf/Assertions.h
index 6263e50ed9..af65f5325c 100644
--- a/src/3rdparty/masm/wtf/Assertions.h
+++ b/src/3rdparty/masm/wtf/Assertions.h
@@ -233,7 +233,7 @@ WTF_EXPORT_PRIVATE void WTFInstallReportBacktraceOnCrashHook();
#define ASSERT_NOT_REACHED() ((void)0)
#define NO_RETURN_DUE_TO_ASSERT
-#if COMPILER(INTEL) && !OS(WINDOWS) || COMPILER(RVCT)
+#if COMPILER(RVCT)
template<typename T>
inline void assertUnused(T& x) { (void)x; }
#define ASSERT_UNUSED(variable, assertion) (assertUnused(variable))
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index d16ac05669..c03224958c 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -6,9 +6,9 @@ SUBDIRS += \
builtins \
qtqml \
folderlistmodel \
- localstorage \
models
+qtHaveModule(sql): SUBDIRS += localstorage
qtConfig(settings): SUBDIRS += settings
qtConfig(statemachine): SUBDIRS += statemachine
@@ -17,9 +17,9 @@ qtHaveModule(quick) {
layouts \
qtquick2 \
window \
- sharedimage \
testlib
+ qtConfig(systemsemaphore): SUBDIRS += sharedimage
qtConfig(quick-particles): \
SUBDIRS += particles
}
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index 8679750842..40682dd6a8 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -770,6 +770,8 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
}
args->setReturnValue(db.asReturnedValue());
+#else
+ Q_UNUSED(args)
#endif // settings
}
diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml
index 18c70e1169..8c1744a2b2 100644
--- a/src/imports/testlib/TestCase.qml
+++ b/src/imports/testlib/TestCase.qml
@@ -38,6 +38,7 @@
****************************************************************************/
import QtQuick 2.0
+import QtQuick.Window 2.0 // used for qtest_verifyItem
import QtTest 1.1
import "testlogger.js" as TestLogger
import Qt.test.qtestroot 1.0
@@ -443,6 +444,9 @@ Item {
or \c{QVERIFY2(condition, message)} in C++.
*/
function verify(cond, msg) {
+ if (arguments.length > 2)
+ qtest_fail("More than two arguments given to verify(). Did you mean tryVerify() or tryCompare()?", 1)
+
if (msg === undefined)
msg = "";
if (!qtest_results.verify(cond, msg, util.callerFile(), util.callerLine()))
@@ -1085,8 +1089,8 @@ Item {
function waitForRendering(item, timeout) {
if (timeout === undefined)
timeout = 5000
- if (!item)
- qtest_fail("No item given to waitForRendering", 1)
+ if (!qtest_verifyItem(item, "waitForRendering"))
+ return
return qtest_results.waitForRendering(item, timeout)
}
@@ -1198,8 +1202,8 @@ Item {
\sa mouseRelease(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel()
*/
function mousePress(item, x, y, button, modifiers, delay) {
- if (!item)
- qtest_fail("No item given to mousePress", 1)
+ if (!qtest_verifyItem(item, "mousePress"))
+ return
if (button === undefined)
button = Qt.LeftButton
@@ -1232,8 +1236,8 @@ Item {
\sa mousePress(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel()
*/
function mouseRelease(item, x, y, button, modifiers, delay) {
- if (!item)
- qtest_fail("No item given to mouseRelease", 1)
+ if (!qtest_verifyItem(item, "mouseRelease"))
+ return
if (button === undefined)
button = Qt.LeftButton
@@ -1268,8 +1272,8 @@ Item {
\sa mousePress(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseRelease(), mouseWheel()
*/
function mouseDrag(item, x, y, dx, dy, button, modifiers, delay) {
- if (!item)
- qtest_fail("No item given to mouseDrag", 1)
+ if (!qtest_verifyItem(item, "mouseDrag"))
+ return
if (item.x === undefined || item.y === undefined)
return
@@ -1319,8 +1323,8 @@ Item {
\sa mousePress(), mouseRelease(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel()
*/
function mouseClick(item, x, y, button, modifiers, delay) {
- if (!item)
- qtest_fail("No item given to mouseClick", 1)
+ if (!qtest_verifyItem(item, "mouseClick"))
+ return
if (button === undefined)
button = Qt.LeftButton
@@ -1353,8 +1357,8 @@ Item {
\sa mouseDoubleClickSequence(), mousePress(), mouseRelease(), mouseClick(), mouseMove(), mouseDrag(), mouseWheel()
*/
function mouseDoubleClick(item, x, y, button, modifiers, delay) {
- if (!item)
- qtest_fail("No item given to mouseDoubleClick", 1)
+ if (!qtest_verifyItem(item, "mouseDoubleClick"))
+ return
if (button === undefined)
button = Qt.LeftButton
@@ -1394,8 +1398,8 @@ Item {
\sa mouseDoubleClick(), mousePress(), mouseRelease(), mouseClick(), mouseMove(), mouseDrag(), mouseWheel()
*/
function mouseDoubleClickSequence(item, x, y, button, modifiers, delay) {
- if (!item)
- qtest_fail("No item given to mouseDoubleClickSequence", 1)
+ if (!qtest_verifyItem(item, "mouseDoubleClickSequence"))
+ return
if (button === undefined)
button = Qt.LeftButton
@@ -1426,8 +1430,8 @@ Item {
\sa mousePress(), mouseRelease(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseDrag(), mouseWheel()
*/
function mouseMove(item, x, y, delay, buttons) {
- if (!item)
- qtest_fail("No item given to mouseMove", 1)
+ if (!qtest_verifyItem(item, "mouseMove"))
+ return
if (delay == undefined)
delay = -1
@@ -1454,8 +1458,8 @@ Item {
\sa mousePress(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseRelease(), mouseDrag(), QWheelEvent::angleDelta()
*/
function mouseWheel(item, x, y, xDelta, yDelta, buttons, modifiers, delay) {
- if (!item)
- qtest_fail("No item given to mouseWheel", 1)
+ if (!qtest_verifyItem(item, "mouseWheel"))
+ return
if (delay == undefined)
delay = -1
@@ -1515,8 +1519,8 @@ Item {
*/
function touchEvent(item) {
- if (!item)
- qtest_fail("No item given to touchEvent", 1)
+ if (!qtest_verifyItem(item, "touchEvent"))
+ return
return {
_defaultItem: item,
@@ -1625,6 +1629,23 @@ Item {
function cleanup() {}
/*! \internal */
+ function qtest_verifyItem(item, method) {
+ try {
+ if (!(item instanceof Item) &&
+ !(item instanceof Window)) {
+ // it's a QObject, but not a type
+ qtest_fail("TypeError: %1 requires an Item or Window type".arg(method), 2);
+ return false;
+ }
+ } catch (e) { // it's not a QObject
+ qtest_fail("TypeError: %1 requires an Item or Window type".arg(method), 3);
+ return false;
+ }
+
+ return true;
+ }
+
+ /*! \internal */
function qtest_runInternal(prop, arg) {
try {
qtest_testCaseResult = testCase[prop](arg)
diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp
index fde491b1ef..e388b52db3 100644
--- a/src/particles/qquickimageparticle.cpp
+++ b/src/particles/qquickimageparticle.cpp
@@ -1323,6 +1323,7 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
getState<ImageMaterialData>(m_material)->animSheetSize = QSizeF(image.size());
if (m_spriteEngine)
m_spriteEngine->setCount(m_count);
+ Q_FALLTHROUGH();
case Tabled:
if (!m_material)
m_material = TabledMaterial::createMaterial();
@@ -1355,12 +1356,15 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node)
getState<ImageMaterialData>(m_material)->colorTable = QSGPlainTexture::fromImage(colortable);
fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->sizeTable, sizetable, UNIFORM_ARRAY_SIZE);
fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE);
+ Q_FALLTHROUGH();
case Deformable:
if (!m_material)
m_material = DeformableMaterial::createMaterial();
+ Q_FALLTHROUGH();
case Colored:
if (!m_material)
m_material = ColoredMaterial::createMaterial();
+ Q_FALLTHROUGH();
default://Also Simple
if (!m_material)
m_material = SimpleMaterial::createMaterial();
@@ -1530,6 +1534,7 @@ void QQuickImageParticle::prepareNextFrame(QSGNode **node)
if (m_spriteEngine)
m_spriteEngine->updateSprites(timeStamp);//fires signals if anim changed
spritesUpdate(time);
+ Q_FALLTHROUGH();
case Tabled:
case Deformable:
case Colored:
@@ -1691,6 +1696,7 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx)
writeTo->animWidth = getState<ImageMaterialData>(m_material)->animSheetSize.width();
writeTo->animHeight = getState<ImageMaterialData>(m_material)->animSheetSize.height();
}
+ Q_FALLTHROUGH();
case Tabled:
case Deformable:
//Initial Rotation
@@ -1737,6 +1743,7 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx)
getShadowDatum(datum)->autoRotate = autoRotate;
}
}
+ Q_FALLTHROUGH();
case Colored:
//Color initialization
// Particle color
diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp
index 99e278238b..6f134f08df 100644
--- a/src/particles/qquickparticlesystem.cpp
+++ b/src/particles/qquickparticlesystem.cpp
@@ -668,8 +668,11 @@ void QQuickParticleSystem::setPaused(bool arg) {
if (m_animation && m_animation->state() != QAbstractAnimation::Stopped)
m_paused ? m_animation->pause() : m_animation->resume();
if (!m_paused) {
- foreach (QQuickParticlePainter *p, m_painters)
- p->update();
+ foreach (QQuickParticlePainter *p, m_painters) {
+ if (p) {
+ p->update();
+ }
+ }
}
emit pausedChanged(arg);
}
@@ -873,8 +876,11 @@ void QQuickParticleSystem::emittersChanged()
if (particleCount > bySysIdx.size())//New datum requests haven't updated it
bySysIdx.resize(particleCount);
- foreach (QQuickParticleAffector *a, m_affectors)//Groups may have changed
- a->m_updateIntSet = true;
+ foreach (QQuickParticleAffector *a, m_affectors) {//Groups may have changed
+ if (a) {
+ a->m_updateIntSet = true;
+ }
+ }
foreach (QQuickParticlePainter *p, m_painters)
loadPainter(p);
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
index 151e44c4d4..3fb0522cd1 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
@@ -409,18 +409,7 @@ QQmlEngineDebugServiceImpl::objectData(QObject *object)
rv.objectId = QQmlDebugService::idForObject(object);
rv.contextId = QQmlDebugService::idForObject(qmlContext(object));
rv.parentId = QQmlDebugService::idForObject(object->parent());
- QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
- if (type) {
- QString typeName = type->qmlTypeName();
- int lastSlash = typeName.lastIndexOf(QLatin1Char('/'));
- rv.objectType = lastSlash < 0 ? typeName : typeName.mid(lastSlash+1);
- } else {
- rv.objectType = QString::fromUtf8(object->metaObject()->className());
- int marker = rv.objectType.indexOf(QLatin1String("_QMLTYPE_"));
- if (marker != -1)
- rv.objectType = rv.objectType.left(marker);
- }
-
+ rv.objectType = QQmlMetaType::prettyTypeName(object);
return rv;
}
diff --git a/src/plugins/qmltooling/qmltooling.pro b/src/plugins/qmltooling/qmltooling.pro
index 8123e2999e..27c51b53c8 100644
--- a/src/plugins/qmltooling/qmltooling.pro
+++ b/src/plugins/qmltooling/qmltooling.pro
@@ -1,5 +1,5 @@
TEMPLATE = subdirs
-QT_FOR_CONFIG += qml
+QT_FOR_CONFIG += qml-private
# Utilities
SUBDIRS += \
@@ -10,25 +10,28 @@ SUBDIRS += \
qmldbg_native \
qmldbg_server
+qmldbg_native.depends = packetprotocol
+qmldbg_server.depends = packetprotocol
+
qtConfig(qml-network) {
SUBDIRS += \
qmldbg_local \
qmldbg_tcp
}
-# Services
-SUBDIRS += \
- qmldbg_debugger \
- qmldbg_profiler \
- qmldbg_messages \
- qmldbg_nativedebugger
+qtConfig(qml-interpreter) {
+ # Services
+ SUBDIRS += \
+ qmldbg_debugger \
+ qmldbg_profiler \
+ qmldbg_messages \
+ qmldbg_nativedebugger
-qmldbg_server.depends = packetprotocol
-qmldbg_native.depends = packetprotocol
-qmldbg_debugger.depends = packetprotocol
-qmldbg_profiler.depends = packetprotocol
-qmldbg_messages.depends = packetprotocol
-qmldbg_nativedebugger.depends = packetprotocol
+ qmldbg_debugger.depends = packetprotocol
+ qmldbg_profiler.depends = packetprotocol
+ qmldbg_messages.depends = packetprotocol
+ qmldbg_nativedebugger.depends = packetprotocol
+}
qtHaveModule(quick) {
SUBDIRS += \
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index fa66d3a6e3..871f28f2d0 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -10,7 +10,8 @@ HEADERS += \
$$PWD/qv4isel_util_p.h \
$$PWD/qv4ssa_p.h \
$$PWD/qqmlirbuilder_p.h \
- $$PWD/qqmltypecompiler_p.h
+ $$PWD/qqmltypecompiler_p.h \
+ $$PWD/qv4jssimplifier_p.h
SOURCES += \
$$PWD/qv4compileddata.cpp \
@@ -19,7 +20,8 @@ SOURCES += \
$$PWD/qv4isel_p.cpp \
$$PWD/qv4jsir.cpp \
$$PWD/qv4ssa.cpp \
- $$PWD/qqmlirbuilder.cpp
+ $$PWD/qqmlirbuilder.cpp \
+ $$PWD/qv4jssimplifier.cpp
!qmldevtools_build {
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index a3b8784fc8..d1d22be0ac 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -47,6 +47,7 @@
#include <private/qv4ssa_p.h>
#include "qqmlpropertycachecreator_p.h"
+#include "qv4jssimplifier_p.h"
#define COMPILE_EXCEPTION(token, desc) \
{ \
@@ -144,7 +145,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile()
if (!jsCodeGen.generateCodeForComponents())
return nullptr;
- QQmlJavaScriptBindingExpressionSimplificationPass pass(this);
+ QQmlJavaScriptBindingExpressionSimplificationPass pass(document->objects, &document->jsModule, &document->jsGenerator);
pass.reduceTranslationBindings();
QV4::ExecutionEngine *v4 = engine->v4engine();
@@ -1429,344 +1430,4 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
}
}
-QQmlJavaScriptBindingExpressionSimplificationPass::QQmlJavaScriptBindingExpressionSimplificationPass(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , qmlObjects(*typeCompiler->qmlObjects())
- , jsModule(typeCompiler->jsIRModule())
-{
-
-}
-
-void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings()
-{
- for (int i = 0; i < qmlObjects.count(); ++i)
- reduceTranslationBindings(i);
- if (!irFunctionsToRemove.isEmpty()) {
- QQmlIRFunctionCleanser cleanser(compiler, irFunctionsToRemove);
- cleanser.clean();
- }
-}
-
-void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings(int objectIndex)
-{
- const QmlIR::Object *obj = qmlObjects.at(objectIndex);
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
- continue;
-
- const int irFunctionIndex = obj->runtimeFunctionIndices.at(binding->value.compiledScriptIndex);
- QV4::IR::Function *irFunction = jsModule->functions.at(irFunctionIndex);
- if (simplifyBinding(irFunction, binding)) {
- irFunctionsToRemove.append(irFunctionIndex);
- jsModule->functions[irFunctionIndex] = 0;
- delete irFunction;
- }
- }
-}
-
-void QQmlJavaScriptBindingExpressionSimplificationPass::visitMove(QV4::IR::Move *move)
-{
- QV4::IR::Temp *target = move->target->asTemp();
- if (!target || target->kind != QV4::IR::Temp::VirtualRegister) {
- discard();
- return;
- }
-
- if (QV4::IR::Call *call = move->source->asCall()) {
- if (QV4::IR::Name *n = call->base->asName()) {
- if (n->builtin == QV4::IR::Name::builtin_invalid) {
- visitFunctionCall(n->id, call->args, target);
- return;
- }
- }
- discard();
- return;
- }
-
- if (QV4::IR::Name *n = move->source->asName()) {
- if (n->builtin == QV4::IR::Name::builtin_qml_context
- || n->builtin == QV4::IR::Name::builtin_qml_imported_scripts_object) {
- // these are free of side-effects
- return;
- }
- discard();
- return;
- }
-
- if (!move->source->asTemp() && !move->source->asString() && !move->source->asConst()) {
- discard();
- return;
- }
-
- _temps[target->index] = move->source;
-}
-
-void QQmlJavaScriptBindingExpressionSimplificationPass::visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target)
-{
- // more than one function call?
- if (_nameOfFunctionCalled) {
- discard();
- return;
- }
-
- _nameOfFunctionCalled = name;
-
- _functionParameters.clear();
- while (args) {
- int slot;
- if (QV4::IR::Temp *param = args->expr->asTemp()) {
- if (param->kind != QV4::IR::Temp::VirtualRegister) {
- discard();
- return;
- }
- slot = param->index;
- _functionParameters.append(slot);
- } else if (QV4::IR::Const *param = args->expr->asConst()) {
- slot = --_synthesizedConsts;
- Q_ASSERT(!_temps.contains(slot));
- _temps[slot] = param;
- _functionParameters.append(slot);
- }
- args = args->next;
- }
-
- _functionCallReturnValue = target->index;
-}
-
-void QQmlJavaScriptBindingExpressionSimplificationPass::visitRet(QV4::IR::Ret *ret)
-{
- // nothing initialized earlier?
- if (_returnValueOfBindingExpression != -1) {
- discard();
- return;
- }
- QV4::IR::Temp *target = ret->expr->asTemp();
- if (!target || target->kind != QV4::IR::Temp::VirtualRegister) {
- discard();
- return;
- }
- _returnValueOfBindingExpression = target->index;
-}
-
-bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding)
-{
- _canSimplify = true;
- _nameOfFunctionCalled = 0;
- _functionParameters.clear();
- _functionCallReturnValue = -1;
- _temps.clear();
- _returnValueOfBindingExpression = -1;
- _synthesizedConsts = 0;
-
- // It would seem unlikely that function with some many basic blocks (after optimization)
- // consists merely of a qsTr call or a constant value return ;-)
- if (function->basicBlockCount() > 10)
- return false;
-
- for (QV4::IR::BasicBlock *bb : function->basicBlocks()) {
- for (QV4::IR::Stmt *s : bb->statements()) {
- visit(s);
- if (!_canSimplify)
- return false;
- }
- }
-
- if (_returnValueOfBindingExpression == -1)
- return false;
-
- if (_nameOfFunctionCalled) {
- if (_functionCallReturnValue != _returnValueOfBindingExpression)
- return false;
- return detectTranslationCallAndConvertBinding(binding);
- }
-
- return false;
-}
-
-bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAndConvertBinding(QmlIR::Binding *binding)
-{
- if (*_nameOfFunctionCalled == QLatin1String("qsTr")) {
- QString translation;
- QV4::CompiledData::TranslationData translationData;
- translationData.number = -1;
- translationData.commentIndex = 0; // empty string
-
- QVector<int>::ConstIterator param = _functionParameters.constBegin();
- QVector<int>::ConstIterator end = _functionParameters.constEnd();
- if (param == end)
- return false;
-
- QV4::IR::String *stringParam = _temps[*param]->asString();
- if (!stringParam)
- return false;
-
- translation = *stringParam->value;
-
- ++param;
- if (param != end) {
- stringParam = _temps[*param]->asString();
- if (!stringParam)
- return false;
- translationData.commentIndex = compiler->registerString(*stringParam->value);
- ++param;
-
- if (param != end) {
- QV4::IR::Const *constParam = _temps[*param]->asConst();
- if (!constParam || constParam->type != QV4::IR::SInt32Type)
- return false;
-
- translationData.number = int(constParam->value);
- ++param;
- }
- }
-
- if (param != end)
- return false;
-
- binding->type = QV4::CompiledData::Binding::Type_Translation;
- binding->stringIndex = compiler->registerString(translation);
- binding->value.translationData = translationData;
- return true;
- } else if (*_nameOfFunctionCalled == QLatin1String("qsTrId")) {
- QString id;
- QV4::CompiledData::TranslationData translationData;
- translationData.number = -1;
- translationData.commentIndex = 0; // empty string, but unused
-
- QVector<int>::ConstIterator param = _functionParameters.constBegin();
- QVector<int>::ConstIterator end = _functionParameters.constEnd();
- if (param == end)
- return false;
-
- QV4::IR::String *stringParam = _temps[*param]->asString();
- if (!stringParam)
- return false;
-
- id = *stringParam->value;
-
- ++param;
- if (param != end) {
- QV4::IR::Const *constParam = _temps[*param]->asConst();
- if (!constParam || constParam->type != QV4::IR::SInt32Type)
- return false;
-
- translationData.number = int(constParam->value);
- ++param;
- }
-
- if (param != end)
- return false;
-
- binding->type = QV4::CompiledData::Binding::Type_TranslationById;
- binding->stringIndex = compiler->registerString(id);
- binding->value.translationData = translationData;
- return true;
- } else if (*_nameOfFunctionCalled == QLatin1String("QT_TR_NOOP") || *_nameOfFunctionCalled == QLatin1String("QT_TRID_NOOP")) {
- QVector<int>::ConstIterator param = _functionParameters.constBegin();
- QVector<int>::ConstIterator end = _functionParameters.constEnd();
- if (param == end)
- return false;
-
- QV4::IR::String *stringParam = _temps[*param]->asString();
- if (!stringParam)
- return false;
-
- ++param;
- if (param != end)
- return false;
-
- binding->type = QV4::CompiledData::Binding::Type_String;
- binding->stringIndex = compiler->registerString(*stringParam->value);
- return true;
- } else if (*_nameOfFunctionCalled == QLatin1String("QT_TRANSLATE_NOOP")) {
- QVector<int>::ConstIterator param = _functionParameters.constBegin();
- QVector<int>::ConstIterator end = _functionParameters.constEnd();
- if (param == end)
- return false;
-
- ++param;
- if (param == end)
- return false;
-
- QV4::IR::String *stringParam = _temps[*param]->asString();
- if (!stringParam)
- return false;
-
- ++param;
- if (param != end)
- return false;
-
- binding->type = QV4::CompiledData::Binding::Type_String;
- binding->stringIndex = compiler->registerString(*stringParam->value);
- return true;
- }
- return false;
-}
-
-QQmlIRFunctionCleanser::QQmlIRFunctionCleanser(QQmlTypeCompiler *typeCompiler, const QVector<int> &functionsToRemove)
- : QQmlCompilePass(typeCompiler)
- , module(typeCompiler->jsIRModule())
- , functionsToRemove(functionsToRemove)
-{
-}
-
-void QQmlIRFunctionCleanser::clean()
-{
- QVector<QV4::IR::Function*> newFunctions;
- newFunctions.reserve(module->functions.count() - functionsToRemove.count());
-
- newFunctionIndices.resize(module->functions.count());
-
- for (int i = 0; i < module->functions.count(); ++i) {
- QV4::IR::Function *f = module->functions.at(i);
- Q_ASSERT(f || functionsToRemove.contains(i));
- if (f) {
- newFunctionIndices[i] = newFunctions.count();
- newFunctions << f;
- }
- }
-
- module->functions = newFunctions;
-
- for (QV4::IR::Function *function : qAsConst(module->functions)) {
- for (QV4::IR::BasicBlock *block : function->basicBlocks()) {
- for (QV4::IR::Stmt *s : block->statements()) {
- visit(s);
- }
- }
- }
-
- for (QmlIR::Object *obj : qAsConst(*compiler->qmlObjects())) {
- for (int i = 0; i < obj->runtimeFunctionIndices.count; ++i)
- obj->runtimeFunctionIndices[i] = newFunctionIndices[obj->runtimeFunctionIndices.at(i)];
- }
-}
-
-void QQmlIRFunctionCleanser::visit(QV4::IR::Stmt *s)
-{
-
- switch (s->stmtKind) {
- case QV4::IR::Stmt::PhiStmt:
- // nothing to do
- break;
- default:
- STMT_VISIT_ALL_KINDS(s);
- break;
- }
-}
-
-void QQmlIRFunctionCleanser::visit(QV4::IR::Expr *e)
-{
- switch (e->exprKind) {
- case QV4::IR::Expr::ClosureExpr: {
- auto closure = e->asClosure();
- closure->value = newFunctionIndices.at(closure->value);
- } break;
- default:
- EXPR_VISIT_ALL_KINDS(e);
- break;
- }
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index 11261e3099..79fc073d8b 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -345,86 +345,6 @@ private:
const QQmlPropertyCacheVector * const propertyCaches;
};
-class QQmlJavaScriptBindingExpressionSimplificationPass : public QQmlCompilePass
-{
-public:
- QQmlJavaScriptBindingExpressionSimplificationPass(QQmlTypeCompiler *typeCompiler);
-
- void reduceTranslationBindings();
-
-private:
- void reduceTranslationBindings(int objectIndex);
-
- void visit(QV4::IR::Stmt *s)
- {
- switch (s->stmtKind) {
- case QV4::IR::Stmt::MoveStmt:
- visitMove(s->asMove());
- break;
- case QV4::IR::Stmt::RetStmt:
- visitRet(s->asRet());
- break;
- case QV4::IR::Stmt::CJumpStmt:
- discard();
- break;
- case QV4::IR::Stmt::ExpStmt:
- discard();
- break;
- case QV4::IR::Stmt::JumpStmt:
- break;
- case QV4::IR::Stmt::PhiStmt:
- break;
- }
- }
-
- void visitMove(QV4::IR::Move *move);
- void visitRet(QV4::IR::Ret *ret);
-
- void visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target);
-
- void discard() { _canSimplify = false; }
-
- bool simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding);
- bool detectTranslationCallAndConvertBinding(QmlIR::Binding *binding);
-
- const QVector<QmlIR::Object*> &qmlObjects;
- QV4::IR::Module *jsModule;
-
- bool _canSimplify;
- const QString *_nameOfFunctionCalled;
- QVector<int> _functionParameters;
- int _functionCallReturnValue;
-
- QHash<int, QV4::IR::Expr*> _temps;
- int _returnValueOfBindingExpression;
- int _synthesizedConsts;
-
- QVector<int> irFunctionsToRemove;
-};
-
-class QQmlIRFunctionCleanser : public QQmlCompilePass
-{
-public:
- QQmlIRFunctionCleanser(QQmlTypeCompiler *typeCompiler, const QVector<int> &functionsToRemove);
-
- void clean();
-
-private:
- virtual void visitMove(QV4::IR::Move *s) {
- visit(s->source);
- visit(s->target);
- }
-
- void visit(QV4::IR::Stmt *s);
- void visit(QV4::IR::Expr *e);
-
-private:
- QV4::IR::Module *module;
- const QVector<int> &functionsToRemove;
-
- QVector<int> newFunctionIndices;
-};
-
QT_END_NAMESPACE
#endif // QQMLTYPECOMPILER_P_H
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 3234e7ee63..693a4230ba 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -92,6 +92,27 @@ static bool cjumpCanHandle(IR::AluOp op)
}
}
+static inline void setJumpOutLocation(IR::Stmt *s, const Statement *body,
+ const SourceLocation &fallback)
+{
+ switch (body->kind) {
+ // Statements where we might never execute the last line.
+ // Use the fallback.
+ case Statement::Kind_ConditionalExpression:
+ case Statement::Kind_ForEachStatement:
+ case Statement::Kind_ForStatement:
+ case Statement::Kind_IfStatement:
+ case Statement::Kind_LocalForEachStatement:
+ case Statement::Kind_LocalForStatement:
+ case Statement::Kind_WhileStatement:
+ setLocation(s, fallback);
+ break;
+ default:
+ setLocation(s, body->lastSourceLocation());
+ break;
+ }
+}
+
Codegen::ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode)
: _cg(cg)
, _sourceCode(sourceCode)
@@ -2269,7 +2290,7 @@ bool Codegen::visit(DoWhileStatement *ast)
_block = loopbody;
statement(ast->statement);
- setLocation(_block->JUMP(loopcond), ast->statement->lastSourceLocation());
+ setJumpOutLocation(_block->JUMP(loopcond), ast->statement, ast->semicolonToken);
_block = loopcond;
condition(ast->expression, loopbody, loopend);
@@ -2334,7 +2355,7 @@ bool Codegen::visit(ForEachStatement *ast)
return false;
move(*init, _block->TEMP(temp));
statement(ast->statement);
- setLocation(_block->JUMP(foreachin), ast->lastSourceLocation());
+ setJumpOutLocation(_block->JUMP(foreachin), ast->statement, ast->forToken);
_block = foreachin;
@@ -2373,7 +2394,7 @@ bool Codegen::visit(ForStatement *ast)
_block = forbody;
statement(ast->statement);
- setLocation(_block->JUMP(forstep), ast->lastSourceLocation());
+ setJumpOutLocation(_block->JUMP(forstep), ast->statement, ast->forToken);
_block = forstep;
statement(ast->expression);
@@ -2399,12 +2420,12 @@ bool Codegen::visit(IfStatement *ast)
_block = iftrue;
statement(ast->ok);
- _block->JUMP(endif);
+ setJumpOutLocation(_block->JUMP(endif), ast->ok, ast->ifToken);
if (ast->ko) {
_block = iffalse;
statement(ast->ko);
- _block->JUMP(endif);
+ setJumpOutLocation(_block->JUMP(endif), ast->ko, ast->elseToken);
}
_block = endif;
@@ -2473,7 +2494,7 @@ bool Codegen::visit(LocalForEachStatement *ast)
int temp = _block->newTemp();
move(identifier(ast->declaration->name.toString()), _block->TEMP(temp));
statement(ast->statement);
- setLocation(_block->JUMP(foreachin), ast->lastSourceLocation());
+ setJumpOutLocation(_block->JUMP(foreachin), ast->statement, ast->forToken);
_block = foreachin;
@@ -2512,7 +2533,7 @@ bool Codegen::visit(LocalForStatement *ast)
_block = forbody;
statement(ast->statement);
- setLocation(_block->JUMP(forstep), ast->lastSourceLocation());
+ setJumpOutLocation(_block->JUMP(forstep), ast->statement, ast->forToken);
_block = forstep;
statement(ast->expression);
@@ -2813,7 +2834,7 @@ bool Codegen::visit(WhileStatement *ast)
_block = whilebody;
statement(ast->statement);
- setLocation(_block->JUMP(whilecond), ast->lastSourceLocation());
+ setJumpOutLocation(_block->JUMP(whilecond), ast->statement, ast->whileToken);
_block = whileend;
leaveLoop();
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index c56f08c2f0..9832e1c49b 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -125,10 +125,8 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
runtimeStrings = (QV4::Heap::String **)malloc(data->stringTableSize * sizeof(QV4::Heap::String*));
// memset the strings to 0 in case a GC run happens while we're within the loop below
memset(runtimeStrings, 0, data->stringTableSize * sizeof(QV4::Heap::String*));
- for (uint i = 0; i < data->stringTableSize; ++i) {
+ for (uint i = 0; i < data->stringTableSize; ++i)
runtimeStrings[i] = engine->newIdentifier(data->stringAt(i));
- runtimeStrings[i]->setMarkBit();
- }
runtimeRegularExpressions = new QV4::Value[data->regexpTableSize];
// memset the regexps to 0 in case a GC run happens while we're within the loop below
@@ -144,12 +142,6 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
flags |= IR::RegExp::RegExp_Multiline;
QV4::Heap::RegExpObject *ro = engine->newRegExpObject(data->stringAt(re->stringIndex), flags);
runtimeRegularExpressions[i] = ro;
-#if WRITEBARRIER(steele)
- if (engine->memoryManager->nextGCIsIncremental) {
- ro->setMarkBit();
- ro->setGrayBit();
- }
-#endif
}
if (data->lookupTableSize) {
@@ -249,14 +241,14 @@ void CompilationUnit::unlink()
#endif
}
-void CompilationUnit::markObjects(QV4::ExecutionEngine *e)
+void CompilationUnit::markObjects(QV4::MarkStack *markStack)
{
for (uint i = 0; i < data->stringTableSize; ++i)
if (runtimeStrings[i])
- runtimeStrings[i]->mark(e);
+ runtimeStrings[i]->mark(markStack);
if (runtimeRegularExpressions) {
for (uint i = 0; i < data->regexpTableSize; ++i)
- runtimeRegularExpressions[i].mark(e);
+ runtimeRegularExpressions[i].mark(markStack);
}
}
@@ -461,6 +453,7 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
return true;
#else
+ Q_UNUSED(outputFileName)
*errorString = QStringLiteral("features.temporaryfile is disabled.");
return false;
#endif // QT_CONFIG(temporaryfile)
@@ -745,7 +738,7 @@ static QByteArray ownLibraryChecksum()
if (dladdr(reinterpret_cast<const void *>(&ownLibraryChecksum), &libInfo) != 0) {
QFile library(QFile::decodeName(libInfo.dli_fname));
if (library.open(QIODevice::ReadOnly)) {
- QCryptographicHash hash(QCryptographicHash::Sha1);
+ QCryptographicHash hash(QCryptographicHash::Md5);
hash.addData(&library);
libraryChecksum = hash.result();
}
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 6e9121b5e3..f4ba257cf5 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -897,7 +897,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase, public
QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
void unlink();
- void markObjects(QV4::ExecutionEngine *e);
+ void markObjects(MarkStack *markStack);
void destroy() Q_DECL_OVERRIDE;
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index b81d724fe7..f7e63437e1 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -376,7 +376,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.version = QV4_DATA_STRUCTURE_VERSION;
unit.qtVersion = QT_VERSION;
memset(unit.md5Checksum, 0, sizeof(unit.md5Checksum));
- unit.architectureIndex = registerString(QSysInfo::buildAbi());
+ unit.architectureIndex = registerString(irModule->targetABI.isEmpty() ? QSysInfo::buildAbi() : irModule->targetABI);
unit.codeGeneratorIndex = registerString(codeGeneratorName);
memset(unit.dependencyMD5Checksum, 0, sizeof(unit.dependencyMD5Checksum));
diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h
index 1755193d32..e949e6f0ad 100644
--- a/src/qml/compiler/qv4isel_util_p.h
+++ b/src/qml/compiler/qv4isel_util_p.h
@@ -58,6 +58,59 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+struct TargetPrimitive32 {
+ static TargetPrimitive32 emptyValue() { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Empty) << 32; return p; }
+ static TargetPrimitive32 nullValue() { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Null) << 32; return p; }
+ static TargetPrimitive32 undefinedValue() { TargetPrimitive32 p; p._val = quint64(Value::Managed_Type_Internal_32) << 32; return p; }
+ static TargetPrimitive32 fromBoolean(bool b) { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Boolean) << 32 | quint64(b); return p; }
+ static TargetPrimitive32 fromInt32(int v) { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Integer) << 32 | quint32(v); return p; }
+ static TargetPrimitive32 fromDouble(double v) {
+ TargetPrimitive32 p;
+ memcpy(&p._val, &v, 8);
+ return p;
+ }
+ static TargetPrimitive32 fromUInt32(uint v) {
+ if (v < INT_MAX)
+ return fromInt32(qint32(v));
+ return fromDouble(double(v));
+ }
+
+ quint32 value() const { return _val & quint64(~quint32(0)); }
+ quint32 tag() const { return _val >> 32; }
+
+ quint64 rawValue() const { return _val; }
+
+private:
+ quint64 _val;
+};
+
+struct TargetPrimitive64 {
+ static TargetPrimitive64 emptyValue() { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Empty) << 32; return p; }
+ static TargetPrimitive64 nullValue() { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Null) << 32; return p; }
+ static TargetPrimitive64 undefinedValue() { TargetPrimitive64 p; p._val = 0; return p; }
+ static TargetPrimitive64 fromBoolean(bool b) { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Boolean) << 32 | quint64(b); return p; }
+ static TargetPrimitive64 fromInt32(int v) { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Integer) << 32 | quint32(v); return p; }
+ static TargetPrimitive64 fromDouble(double v) {
+ TargetPrimitive64 p;
+ memcpy(&p._val, &v, 8);
+ p._val ^= Value::NaNEncodeMask;
+ return p;
+ }
+ static TargetPrimitive64 fromUInt32(uint v) {
+ if (v < INT_MAX)
+ return fromInt32(qint32(v));
+ return fromDouble(double(v));
+ }
+
+ quint32 value() const { return _val & quint64(~quint32(0)); }
+ quint32 tag() const { return _val >> 32; }
+
+ quint64 rawValue() const { return _val; }
+
+private:
+ quint64 _val;
+};
+
inline bool canConvertToSignedInteger(double value)
{
int ival = (int) value;
@@ -72,36 +125,37 @@ inline bool canConvertToUnsignedInteger(double value)
return uval == value && !(value == 0 && isNegative(value));
}
-inline Primitive convertToValue(IR::Const *c)
+template <typename PrimitiveType = Primitive>
+inline PrimitiveType convertToValue(IR::Const *c)
{
switch (c->type) {
case IR::MissingType:
- return Primitive::emptyValue();
+ return PrimitiveType::emptyValue();
case IR::NullType:
- return Primitive::nullValue();
+ return PrimitiveType::nullValue();
case IR::UndefinedType:
- return Primitive::undefinedValue();
+ return PrimitiveType::undefinedValue();
case IR::BoolType:
- return Primitive::fromBoolean(c->value != 0);
+ return PrimitiveType::fromBoolean(c->value != 0);
case IR::SInt32Type:
- return Primitive::fromInt32(int(c->value));
+ return PrimitiveType::fromInt32(int(c->value));
case IR::UInt32Type:
- return Primitive::fromUInt32(unsigned(c->value));
+ return PrimitiveType::fromUInt32(unsigned(c->value));
case IR::DoubleType:
- return Primitive::fromDouble(c->value);
+ return PrimitiveType::fromDouble(c->value);
case IR::NumberType: {
int ival = (int)c->value;
if (canConvertToSignedInteger(c->value)) {
- return Primitive::fromInt32(ival);
+ return PrimitiveType::fromInt32(ival);
} else {
- return Primitive::fromDouble(c->value);
+ return PrimitiveType::fromDouble(c->value);
}
}
default:
Q_UNREACHABLE();
}
// unreachable, but the function must return something
- return Primitive::undefinedValue();
+ return PrimitiveType::undefinedValue();
}
class ConvertTemps
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index f7c7b76ea8..35cf0fc174 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -946,6 +946,7 @@ struct Q_QML_PRIVATE_EXPORT Module {
QDateTime sourceTimeStamp;
bool isQmlModule; // implies rootFunction is always 0
uint unitFlags; // flags merged into CompiledData::Unit::flags
+ QString targetABI; // fallback to QSysInfo::buildAbi() if empty
#ifdef QT_NO_QML_DEBUGGER
static const bool debugMode = false;
#else
diff --git a/src/qml/compiler/qv4jssimplifier.cpp b/src/qml/compiler/qv4jssimplifier.cpp
new file mode 100644
index 0000000000..7d09218fe6
--- /dev/null
+++ b/src/qml/compiler/qv4jssimplifier.cpp
@@ -0,0 +1,384 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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 "qv4jssimplifier_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlJavaScriptBindingExpressionSimplificationPass::QQmlJavaScriptBindingExpressionSimplificationPass(const QVector<QmlIR::Object*> &qmlObjects, QV4::IR::Module *jsModule, QV4::Compiler::JSUnitGenerator *unitGenerator)
+ : qmlObjects(qmlObjects)
+ , jsModule(jsModule)
+ , unitGenerator(unitGenerator)
+{
+
+}
+
+void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings()
+{
+ for (int i = 0; i < qmlObjects.count(); ++i)
+ reduceTranslationBindings(i);
+ if (!irFunctionsToRemove.isEmpty()) {
+ QQmlIRFunctionCleanser cleanser(jsModule, qmlObjects, irFunctionsToRemove);
+ cleanser.clean();
+ }
+}
+
+void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings(int objectIndex)
+{
+ const QmlIR::Object *obj = qmlObjects.at(objectIndex);
+
+ for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
+ if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ continue;
+
+ const int irFunctionIndex = obj->runtimeFunctionIndices.at(binding->value.compiledScriptIndex);
+ QV4::IR::Function *irFunction = jsModule->functions.at(irFunctionIndex);
+ if (simplifyBinding(irFunction, binding)) {
+ irFunctionsToRemove.append(irFunctionIndex);
+ jsModule->functions[irFunctionIndex] = 0;
+ delete irFunction;
+ }
+ }
+}
+
+void QQmlJavaScriptBindingExpressionSimplificationPass::visitMove(QV4::IR::Move *move)
+{
+ QV4::IR::Temp *target = move->target->asTemp();
+ if (!target || target->kind != QV4::IR::Temp::VirtualRegister) {
+ discard();
+ return;
+ }
+
+ if (QV4::IR::Call *call = move->source->asCall()) {
+ if (QV4::IR::Name *n = call->base->asName()) {
+ if (n->builtin == QV4::IR::Name::builtin_invalid) {
+ visitFunctionCall(n->id, call->args, target);
+ return;
+ }
+ }
+ discard();
+ return;
+ }
+
+ if (QV4::IR::Name *n = move->source->asName()) {
+ if (n->builtin == QV4::IR::Name::builtin_qml_context
+ || n->builtin == QV4::IR::Name::builtin_qml_imported_scripts_object) {
+ // these are free of side-effects
+ return;
+ }
+ discard();
+ return;
+ }
+
+ if (!move->source->asTemp() && !move->source->asString() && !move->source->asConst()) {
+ discard();
+ return;
+ }
+
+ _temps[target->index] = move->source;
+}
+
+void QQmlJavaScriptBindingExpressionSimplificationPass::visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target)
+{
+ // more than one function call?
+ if (_nameOfFunctionCalled) {
+ discard();
+ return;
+ }
+
+ _nameOfFunctionCalled = name;
+
+ _functionParameters.clear();
+ while (args) {
+ int slot;
+ if (QV4::IR::Temp *param = args->expr->asTemp()) {
+ if (param->kind != QV4::IR::Temp::VirtualRegister) {
+ discard();
+ return;
+ }
+ slot = param->index;
+ _functionParameters.append(slot);
+ } else if (QV4::IR::Const *param = args->expr->asConst()) {
+ slot = --_synthesizedConsts;
+ Q_ASSERT(!_temps.contains(slot));
+ _temps[slot] = param;
+ _functionParameters.append(slot);
+ }
+ args = args->next;
+ }
+
+ _functionCallReturnValue = target->index;
+}
+
+void QQmlJavaScriptBindingExpressionSimplificationPass::visitRet(QV4::IR::Ret *ret)
+{
+ // nothing initialized earlier?
+ if (_returnValueOfBindingExpression != -1) {
+ discard();
+ return;
+ }
+ QV4::IR::Temp *target = ret->expr->asTemp();
+ if (!target || target->kind != QV4::IR::Temp::VirtualRegister) {
+ discard();
+ return;
+ }
+ _returnValueOfBindingExpression = target->index;
+}
+
+bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding)
+{
+ _canSimplify = true;
+ _nameOfFunctionCalled = 0;
+ _functionParameters.clear();
+ _functionCallReturnValue = -1;
+ _temps.clear();
+ _returnValueOfBindingExpression = -1;
+ _synthesizedConsts = 0;
+
+ // It would seem unlikely that function with some many basic blocks (after optimization)
+ // consists merely of a qsTr call or a constant value return ;-)
+ if (function->basicBlockCount() > 10)
+ return false;
+
+ for (QV4::IR::BasicBlock *bb : function->basicBlocks()) {
+ for (QV4::IR::Stmt *s : bb->statements()) {
+ visit(s);
+ if (!_canSimplify)
+ return false;
+ }
+ }
+
+ if (_returnValueOfBindingExpression == -1)
+ return false;
+
+ if (_nameOfFunctionCalled) {
+ if (_functionCallReturnValue != _returnValueOfBindingExpression)
+ return false;
+ return detectTranslationCallAndConvertBinding(binding);
+ }
+
+ return false;
+}
+
+bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAndConvertBinding(QmlIR::Binding *binding)
+{
+ if (*_nameOfFunctionCalled == QLatin1String("qsTr")) {
+ QString translation;
+ QV4::CompiledData::TranslationData translationData;
+ translationData.number = -1;
+ translationData.commentIndex = 0; // empty string
+
+ QVector<int>::ConstIterator param = _functionParameters.constBegin();
+ QVector<int>::ConstIterator end = _functionParameters.constEnd();
+ if (param == end)
+ return false;
+
+ QV4::IR::String *stringParam = _temps[*param]->asString();
+ if (!stringParam)
+ return false;
+
+ translation = *stringParam->value;
+
+ ++param;
+ if (param != end) {
+ stringParam = _temps[*param]->asString();
+ if (!stringParam)
+ return false;
+ translationData.commentIndex = unitGenerator->registerString(*stringParam->value);
+ ++param;
+
+ if (param != end) {
+ QV4::IR::Const *constParam = _temps[*param]->asConst();
+ if (!constParam || constParam->type != QV4::IR::SInt32Type)
+ return false;
+
+ translationData.number = int(constParam->value);
+ ++param;
+ }
+ }
+
+ if (param != end)
+ return false;
+
+ binding->type = QV4::CompiledData::Binding::Type_Translation;
+ binding->stringIndex = unitGenerator->registerString(translation);
+ binding->value.translationData = translationData;
+ return true;
+ } else if (*_nameOfFunctionCalled == QLatin1String("qsTrId")) {
+ QString id;
+ QV4::CompiledData::TranslationData translationData;
+ translationData.number = -1;
+ translationData.commentIndex = 0; // empty string, but unused
+
+ QVector<int>::ConstIterator param = _functionParameters.constBegin();
+ QVector<int>::ConstIterator end = _functionParameters.constEnd();
+ if (param == end)
+ return false;
+
+ QV4::IR::String *stringParam = _temps[*param]->asString();
+ if (!stringParam)
+ return false;
+
+ id = *stringParam->value;
+
+ ++param;
+ if (param != end) {
+ QV4::IR::Const *constParam = _temps[*param]->asConst();
+ if (!constParam || constParam->type != QV4::IR::SInt32Type)
+ return false;
+
+ translationData.number = int(constParam->value);
+ ++param;
+ }
+
+ if (param != end)
+ return false;
+
+ binding->type = QV4::CompiledData::Binding::Type_TranslationById;
+ binding->stringIndex = unitGenerator->registerString(id);
+ binding->value.translationData = translationData;
+ return true;
+ } else if (*_nameOfFunctionCalled == QLatin1String("QT_TR_NOOP") || *_nameOfFunctionCalled == QLatin1String("QT_TRID_NOOP")) {
+ QVector<int>::ConstIterator param = _functionParameters.constBegin();
+ QVector<int>::ConstIterator end = _functionParameters.constEnd();
+ if (param == end)
+ return false;
+
+ QV4::IR::String *stringParam = _temps[*param]->asString();
+ if (!stringParam)
+ return false;
+
+ ++param;
+ if (param != end)
+ return false;
+
+ binding->type = QV4::CompiledData::Binding::Type_String;
+ binding->stringIndex = unitGenerator->registerString(*stringParam->value);
+ return true;
+ } else if (*_nameOfFunctionCalled == QLatin1String("QT_TRANSLATE_NOOP")) {
+ QVector<int>::ConstIterator param = _functionParameters.constBegin();
+ QVector<int>::ConstIterator end = _functionParameters.constEnd();
+ if (param == end)
+ return false;
+
+ ++param;
+ if (param == end)
+ return false;
+
+ QV4::IR::String *stringParam = _temps[*param]->asString();
+ if (!stringParam)
+ return false;
+
+ ++param;
+ if (param != end)
+ return false;
+
+ binding->type = QV4::CompiledData::Binding::Type_String;
+ binding->stringIndex = unitGenerator->registerString(*stringParam->value);
+ return true;
+ }
+ return false;
+}
+
+QQmlIRFunctionCleanser::QQmlIRFunctionCleanser(QV4::IR::Module *module, const QVector<QmlIR::Object *> &qmlObjects, const QVector<int> &functionsToRemove)
+ : module(module)
+ , qmlObjects(qmlObjects)
+ , functionsToRemove(functionsToRemove)
+{
+}
+
+void QQmlIRFunctionCleanser::clean()
+{
+ QVector<QV4::IR::Function*> newFunctions;
+ newFunctions.reserve(module->functions.count() - functionsToRemove.count());
+
+ newFunctionIndices.resize(module->functions.count());
+
+ for (int i = 0; i < module->functions.count(); ++i) {
+ QV4::IR::Function *f = module->functions.at(i);
+ Q_ASSERT(f || functionsToRemove.contains(i));
+ if (f) {
+ newFunctionIndices[i] = newFunctions.count();
+ newFunctions << f;
+ }
+ }
+
+ module->functions = newFunctions;
+
+ for (QV4::IR::Function *function : qAsConst(module->functions)) {
+ for (QV4::IR::BasicBlock *block : function->basicBlocks()) {
+ for (QV4::IR::Stmt *s : block->statements()) {
+ visit(s);
+ }
+ }
+ }
+
+ for (QmlIR::Object *obj : qmlObjects) {
+ for (int i = 0; i < obj->runtimeFunctionIndices.count; ++i)
+ obj->runtimeFunctionIndices[i] = newFunctionIndices[obj->runtimeFunctionIndices.at(i)];
+ }
+}
+
+void QQmlIRFunctionCleanser::visit(QV4::IR::Stmt *s)
+{
+
+ switch (s->stmtKind) {
+ case QV4::IR::Stmt::PhiStmt:
+ // nothing to do
+ break;
+ default:
+ STMT_VISIT_ALL_KINDS(s);
+ break;
+ }
+}
+
+void QQmlIRFunctionCleanser::visit(QV4::IR::Expr *e)
+{
+ switch (e->exprKind) {
+ case QV4::IR::Expr::ClosureExpr: {
+ auto closure = e->asClosure();
+ closure->value = newFunctionIndices.at(closure->value);
+ } break;
+ default:
+ EXPR_VISIT_ALL_KINDS(e);
+ break;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4jssimplifier_p.h b/src/qml/compiler/qv4jssimplifier_p.h
new file mode 100644
index 0000000000..ae8d74135c
--- /dev/null
+++ b/src/qml/compiler/qv4jssimplifier_p.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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 QV4JSSIMPLIFIER
+#define QV4JSSIMPLIFIER
+
+//
+// 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 "qqmlirbuilder_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QmlIR {
+struct Document;
+}
+
+namespace QV4 {
+namespace CompiledData {
+struct QmlUnit;
+struct Location;
+}
+}
+
+class QQmlJavaScriptBindingExpressionSimplificationPass
+{
+public:
+ QQmlJavaScriptBindingExpressionSimplificationPass(const QVector<QmlIR::Object*> &qmlObjects, QV4::IR::Module *jsModule, QV4::Compiler::JSUnitGenerator *unitGenerator);
+
+ void reduceTranslationBindings();
+
+private:
+ void reduceTranslationBindings(int objectIndex);
+
+ void visit(QV4::IR::Stmt *s)
+ {
+ switch (s->stmtKind) {
+ case QV4::IR::Stmt::MoveStmt:
+ visitMove(s->asMove());
+ break;
+ case QV4::IR::Stmt::RetStmt:
+ visitRet(s->asRet());
+ break;
+ case QV4::IR::Stmt::CJumpStmt:
+ discard();
+ break;
+ case QV4::IR::Stmt::ExpStmt:
+ discard();
+ break;
+ case QV4::IR::Stmt::JumpStmt:
+ break;
+ case QV4::IR::Stmt::PhiStmt:
+ break;
+ }
+ }
+
+ void visitMove(QV4::IR::Move *move);
+ void visitRet(QV4::IR::Ret *ret);
+
+ void visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target);
+
+ void discard() { _canSimplify = false; }
+
+ bool simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding);
+ bool detectTranslationCallAndConvertBinding(QmlIR::Binding *binding);
+
+ const QVector<QmlIR::Object*> &qmlObjects;
+ QV4::IR::Module *jsModule;
+ QV4::Compiler::JSUnitGenerator *unitGenerator;
+
+ bool _canSimplify;
+ const QString *_nameOfFunctionCalled;
+ QVector<int> _functionParameters;
+ int _functionCallReturnValue;
+
+ QHash<int, QV4::IR::Expr*> _temps;
+ int _returnValueOfBindingExpression;
+ int _synthesizedConsts;
+
+ QVector<int> irFunctionsToRemove;
+};
+
+class QQmlIRFunctionCleanser
+{
+public:
+ QQmlIRFunctionCleanser(QV4::IR::Module *module, const QVector<QmlIR::Object*> &qmlObjects, const QVector<int> &functionsToRemove);
+
+ void clean();
+
+private:
+ virtual void visitMove(QV4::IR::Move *s) {
+ visit(s->source);
+ visit(s->target);
+ }
+
+ void visit(QV4::IR::Stmt *s);
+ void visit(QV4::IR::Expr *e);
+
+private:
+ QV4::IR::Module *module;
+ const QVector<QmlIR::Object*> &qmlObjects;
+ const QVector<int> &functionsToRemove;
+
+ QVector<int> newFunctionIndices;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV4JSSIMPLIFIER
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index cc542e94e7..62e2833089 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -2345,6 +2345,7 @@ private:
case OpIncrement:
case OpDecrement:
Q_ASSERT(!"Inplace operators should have been removed!");
+ Q_UNREACHABLE();
default:
Q_UNIMPLEMENTED();
Q_UNREACHABLE();
@@ -2645,6 +2646,7 @@ private:
case OpMul:
if (!targetTemp || !knownOk.contains(*targetTemp))
return false;
+ Q_FALLTHROUGH();
case OpBitAnd:
case OpBitOr:
case OpBitXor:
diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc
index 4523ee39d8..9cc7291583 100644
--- a/src/qml/doc/src/cppintegration/data.qdoc
+++ b/src/qml/doc/src/cppintegration/data.qdoc
@@ -273,10 +273,17 @@ In particular, QML currently supports:
\li \c {QList<qreal>}
\li \c {QList<bool>}
\li \c {QList<QString>} and \c{QStringList}
+ \li \c {QVector<QString>}
+ \li \c {std::vector<QString>}
\li \c {QList<QUrl>}
+ \li \c {QVector<QUrl>}
+ \li \c {std::vector<QUrl>}
\li \c {QVector<int>}
\li \c {QVector<qreal>}
\li \c {QVector<bool>}
+ \li \c {std::vector<int>}
+ \li \c {std::vector<qreal>}
+ \li \c {std::vector<bool>}
\endlist
These sequence types are implemented directly in terms of the underlying C++
@@ -296,6 +303,10 @@ If the sequence is returned from a Q_INVOKABLE function, access and mutation
is much cheaper, as no QObject property read or write occurs; instead, the
C++ sequence data is accessed and modified directly.
+In both the Q_PROPERTY and return from Q_INVOKABLE cases, the elements
+of a std::vector are copied. This copying may be an expensive operation,
+so std::vector should be used judiciously.
+
Other sequence types are not supported transparently, and instead an
instance of any other sequence type will be passed between QML and C++ as an
opaque QVariantList.
@@ -318,10 +329,17 @@ The default-constructed values for each sequence type are as follows:
\row \li QList<qreal> \li real value 0.0
\row \li QList<bool> \li boolean value \c {false}
\row \li QList<QString> and QStringList \li empty QString
+\row \li QVector<QString> \li empty QString
+\row \li std::vector<QString> \li empty QString
\row \li QList<QUrl> \li empty QUrl
+\row \li QVector<QUrl> \li empty QUrl
+\row \li std::vector<QUrl> \li empty QUrl
\row \li QVector<int> \li integer value 0
\row \li QVector<qreal> \li real value 0.0
\row \li QVector<bool> \li boolean value \c {false}
+\row \li std::vector<int> \li integer value 0
+\row \li std::vector<qreal> \li real value 0.0
+\row \li std::vector<bool> \li boolean value \c {false}
\endtable
If you wish to remove elements from a sequence rather than simply replace
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index 7d4a543089..32084bd308 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -687,7 +687,7 @@ class MessageBoard : public QObject
Q_PROPERTY(QQmlListProperty<Message> messages READ messages)
Q_CLASSINFO("DefaultProperty", "messages")
public:
- QQmlListProperty<Message> messages() const;
+ QQmlListProperty<Message> messages();
private:
QList<Message *> messages;
diff --git a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
index 3bffd2eb6f..c4c58c2821 100644
--- a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
+++ b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
@@ -267,7 +267,7 @@ class MessageBoard : public QObject
Q_OBJECT
Q_PROPERTY(QQmlListProperty<Message> messages READ messages)
public:
- QQmlListProperty<Message> messages() const;
+ QQmlListProperty<Message> messages();
private:
static void append_message(QQmlListProperty<Message> *list, Message *msg);
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index 583719a3c7..d062f3bbb2 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -156,9 +156,6 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
}
template <typename TargetConfiguration>
-const typename Assembler<TargetConfiguration>::VoidType Assembler<TargetConfiguration>::Void;
-
-template <typename TargetConfiguration>
Assembler<TargetConfiguration>::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator)
: _function(function)
, _nextBlock(0)
@@ -324,21 +321,21 @@ typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>:
loadPtr(Address(Assembler::ScratchRegister, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, compilationUnit))), Assembler::ScratchRegister);
loadPtr(Address(Assembler::ScratchRegister, offsetof(CompiledData::CompilationUnitBase, runtimeStrings)), reg);
const int id = _jsGenerator->registerString(string);
- return Pointer(reg, id * sizeof(QV4::String*));
+ return Pointer(reg, id * RegisterSize);
}
template <typename TargetConfiguration>
typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(IR::Const *c, RegisterID baseReg)
{
- return loadConstant(convertToValue(c), baseReg);
+ return loadConstant(convertToValue<TargetPrimitive>(c), baseReg);
}
template <typename TargetConfiguration>
-typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(const Primitive &v, RegisterID baseReg)
+typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(const TargetPrimitive &v, RegisterID baseReg)
{
loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), baseReg);
loadPtr(Address(baseReg, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, constantTable))), baseReg);
- const int index = _jsGenerator->registerConstant(v.asReturnedValue());
+ const int index = _jsGenerator->registerConstant(v.rawValue());
return Address(baseReg, index * sizeof(QV4::Value));
}
@@ -350,7 +347,7 @@ void Assembler<TargetConfiguration>::loadStringRef(RegisterID reg, const QString
}
template <typename TargetConfiguration>
-void Assembler<TargetConfiguration>::storeValue(QV4::Primitive value, IR::Expr *destination)
+void Assembler<TargetConfiguration>::storeValue(TargetPrimitive value, IR::Expr *destination)
{
WriteBarrier::Type barrier;
Address addr = loadAddressForWriting(ScratchRegister, destination, &barrier);
@@ -449,19 +446,13 @@ typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::ge
// check if it's an int32:
Assembler::Jump isNoInt = branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(Value::Integer_Type_Internal));
+ Assembler::TrustedImm32(quint32(ValueTypeInternal::Integer)));
convertInt32ToDouble(toInt32Register(src, Assembler::ScratchRegister), dest);
Assembler::Jump intDone = jump();
// not an int, check if it's a double:
isNoInt.link(this);
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- rshift32(TrustedImm32(Value::IsDoubleTag_Shift), ScratchRegister);
- Assembler::Jump isNoDbl = branch32(RelationalCondition::Equal, JITTargetPlatform::ScratchRegister, TrustedImm32(0));
-#else
- and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister);
- Assembler::Jump isNoDbl = branch32(RelationalCondition::Equal, JITTargetPlatform::ScratchRegister, TrustedImm32(Value::NotDouble_Mask));
-#endif
+ Assembler::Jump isNoDbl = RegisterSizeDependentOps::checkIfTagRegisterIsDouble(this, ScratchRegister);
toDoubleRegister(src, dest);
intDone.link(this);
@@ -530,7 +521,7 @@ void Assembler<TargetConfiguration>::returnFromFunction(IR::Ret *s, RegisterInfo
} else if (IR::Temp *t = s->expr->asTemp()) {
RegisterSizeDependentOps::setFunctionReturnValueFromTemp(this, t);
} else if (IR::Const *c = s->expr->asConst()) {
- QV4::Primitive retVal = convertToValue(c);
+ auto retVal = convertToValue<TargetPrimitive>(c);
RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal);
} else {
Q_UNREACHABLE();
@@ -547,7 +538,7 @@ void Assembler<TargetConfiguration>::returnFromFunction(IR::Ret *s, RegisterInfo
ret();
exceptionReturnLabel = label();
- QV4::Primitive retVal = Primitive::undefinedValue();
+ auto retVal = TargetPrimitive::undefinedValue();
RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal);
jump(leaveStackFrame);
}
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index d4a18ae886..9e38696d7a 100644
--- a/src/qml/jit/qv4assembler_p.h
+++ b/src/qml/jit/qv4assembler_p.h
@@ -153,6 +153,8 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
using TrustedImm64 = typename JITAssembler::TrustedImm64;
using Jump = typename JITAssembler::Jump;
using Label = typename JITAssembler::Label;
+ using ValueTypeInternal = Value::ValueTypeInternal_32;
+ using TargetPrimitive = TargetPrimitive32;
static void emitSetGrayBit(JITAssembler *as, RegisterID base)
{
@@ -189,18 +191,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
as->pop(TargetPlatform::EngineRegister);
}
-#if WRITEBARRIER(steele)
- static void emitWriteBarrier(JITAssembler *as, Address addr)
- {
-// RegisterID test = addr.base == TargetPlatform::ReturnValueRegister ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister;
- // if (engine->writeBarrier)
-// as->load8(Address(TargetPlatform::EngineRegister, offsetof(EngineBase, writeBarrierActive)), test);
-// typename JITAssembler::Jump jump = as->branch32(JITAssembler::Equal, test, TrustedImm32(0));
- // ### emit fence
- emitSetGrayBit(as, addr.base);
-// jump.link(as);
- }
-#elif WRITEBARRIER(none)
+#if WRITEBARRIER(none)
static Q_ALWAYS_INLINE void emitWriteBarrier(JITAssembler *, Address) {}
#endif
@@ -223,9 +214,9 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
as->storeDouble(source, ptr, barrier);
}
- static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination, WriteBarrier::Type barrier)
+ static void storeValue(JITAssembler *as, TargetPrimitive value, Address destination, WriteBarrier::Type barrier)
{
- as->store32(TrustedImm32(value.int_32()), destination);
+ as->store32(TrustedImm32(value.value()), destination);
destination.offset += 4;
as->store32(TrustedImm32(value.tag()), destination);
if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
@@ -282,16 +273,16 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Jump done = as->jump();
intRange.link(as);
as->move(srcReg, lowReg);
- as->move(TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
+ as->move(TrustedImm32(quint32(QV4::Value::ValueTypeInternal_32::Integer)), highReg);
done.link(as);
} break;
case IR::SInt32Type:
as->move((RegisterID) t->index, lowReg);
- as->move(TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
+ as->move(TrustedImm32(quint32(QV4::Value::ValueTypeInternal_32::Integer)), highReg);
break;
case IR::BoolType:
as->move((RegisterID) t->index, lowReg);
- as->move(TrustedImm32(QV4::Value::Boolean_Type_Internal), highReg);
+ as->move(TrustedImm32(quint32(QV4::Value::ValueTypeInternal_32::Boolean)), highReg);
break;
default:
Q_UNREACHABLE();
@@ -304,9 +295,9 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
}
}
- static void setFunctionReturnValueFromConst(JITAssembler *as, QV4::Primitive retVal)
+ static void setFunctionReturnValueFromConst(JITAssembler *as, TargetPrimitive retVal)
{
- as->move(TrustedImm32(retVal.int_32()), TargetPlatform::LowReturnValueRegister);
+ as->move(TrustedImm32(retVal.value()), TargetPlatform::LowReturnValueRegister);
as->move(TrustedImm32(retVal.tag()), TargetPlatform::HighReturnValueRegister);
}
@@ -382,7 +373,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
// check if it's an int32:
Jump fallback = as->branch32(RelationalCondition::NotEqual, TargetPlatform::ReturnValueRegister,
- TrustedImm32(Value::Integer_Type_Internal));
+ TrustedImm32(quint32(Value::ValueTypeInternal_32::Integer)));
IR::Temp *targetTemp = target->asTemp();
if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
as->load32(addr, TargetPlatform::ReturnValueRegister);
@@ -390,7 +381,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier);
as->store32(TargetPlatform::ReturnValueRegister, targetAddr);
targetAddr.offset += 4;
- as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr);
+ as->store32(TrustedImm32(quint32(Value::ValueTypeInternal_32::Integer)), targetAddr);
if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
emitWriteBarrier(as, targetAddr);
} else {
@@ -435,6 +426,13 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Jump jump = as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), TargetPlatform::ScratchRegister);
jump.linkTo(loop, as);
}
+
+ static Jump checkIfTagRegisterIsDouble(JITAssembler *as, RegisterID tagRegister)
+ {
+ as->and32(TrustedImm32(Value::NotDouble_Mask), tagRegister);
+ Jump isNoDbl = as->branch32(RelationalCondition::Equal, tagRegister, TrustedImm32(Value::NotDouble_Mask));
+ return isNoDbl;
+ }
};
template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform>
@@ -451,6 +449,8 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
using BranchTruncateType = typename JITAssembler::BranchTruncateType;
using Jump = typename JITAssembler::Jump;
using Label = typename JITAssembler::Label;
+ using ValueTypeInternal = Value::ValueTypeInternal_64;
+ using TargetPrimitive = TargetPrimitive64;
static void emitSetGrayBit(JITAssembler *as, RegisterID base)
{
@@ -487,18 +487,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
as->pop(TargetPlatform::EngineRegister);
}
-#if WRITEBARRIER(steele)
- static void emitWriteBarrier(JITAssembler *as, Address addr)
- {
-// RegisterID test = addr.base == TargetPlatform::ReturnValueRegister ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister;
- // if (engine->writeBarrier)
-// as->load8(Address(TargetPlatform::EngineRegister, offsetof(EngineBase, writeBarrierActive)), test);
-// typename JITAssembler::Jump jump = as->branch32(JITAssembler::Equal, test, TrustedImm32(0));
- // ### emit fence
- emitSetGrayBit(as, addr.base);
-// jump.link(as);
- }
-#elif WRITEBARRIER(none)
+#if WRITEBARRIER(none)
static Q_ALWAYS_INLINE void emitWriteBarrier(JITAssembler *, Address) {}
#endif
@@ -558,7 +547,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Jump done = as->jump();
intRange.link(as);
as->zeroExtend32ToPtr(srcReg, TargetPlatform::ReturnValueRegister);
- quint64 tag = QV4::Value::Integer_Type_Internal;
+ quint64 tag = quint64(QV4::Value::ValueTypeInternal_64::Integer);
as->or64(TrustedImm64(tag << 32),
TargetPlatform::ReturnValueRegister);
done.link(as);
@@ -567,10 +556,10 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
quint64 tag;
switch (t->type) {
case IR::SInt32Type:
- tag = QV4::Value::Integer_Type_Internal;
+ tag = quint64(QV4::Value::ValueTypeInternal_64::Integer);
break;
case IR::BoolType:
- tag = QV4::Value::Boolean_Type_Internal;
+ tag = quint64(QV4::Value::ValueTypeInternal_64::Boolean);
break;
default:
tag = 31337; // bogus value
@@ -584,12 +573,12 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
}
}
- static void setFunctionReturnValueFromConst(JITAssembler *as, QV4::Primitive retVal)
+ static void setFunctionReturnValueFromConst(JITAssembler *as, TargetPrimitive retVal)
{
as->move(TrustedImm64(retVal.rawValue()), TargetPlatform::ReturnValueRegister);
}
- static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination, WriteBarrier::Type barrier)
+ static void storeValue(JITAssembler *as, TargetPrimitive value, Address destination, WriteBarrier::Type barrier)
{
as->store64(TrustedImm64(value.rawValue()), destination);
if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
@@ -628,7 +617,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Pointer addr = as->loadTempAddress(temp);
as->load64(addr, dest);
} else {
- QV4::Value undefined = QV4::Primitive::undefinedValue();
+ auto undefined = TargetPrimitive::undefinedValue();
as->move(TrustedImm64(undefined.rawValue()), dest);
}
}
@@ -641,7 +630,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Pointer addr = as->loadArgLocalAddressForReading(dest, al);
as->load64(addr, dest);
} else {
- QV4::Value undefined = QV4::Primitive::undefinedValue();
+ auto undefined = TargetPrimitive::undefinedValue();
as->move(TrustedImm64(undefined.rawValue()), dest);
}
}
@@ -650,7 +639,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
{
Q_UNUSED(argumentNumber);
- QV4::Value v = convertToValue(c);
+ auto v = convertToValue<TargetPrimitive64>(c);
as->move(TrustedImm64(v.rawValue()), dest);
}
@@ -659,7 +648,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Q_UNUSED(argumentNumber);
if (!expr) {
- QV4::Value undefined = QV4::Primitive::undefinedValue();
+ auto undefined = TargetPrimitive::undefinedValue();
as->move(TrustedImm64(undefined.rawValue()), dest);
} else if (IR::Temp *t = expr->asTemp()){
loadArgumentInRegister(as, t, dest, argumentNumber);
@@ -751,7 +740,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier);
as->store32(TargetPlatform::ReturnValueRegister, targetAddr);
targetAddr.offset += 4;
- as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr);
+ as->store32(TrustedImm32(quint32(Value::ValueTypeInternal_64::Integer)), targetAddr);
if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
emitWriteBarrier(as, targetAddr);
} else {
@@ -783,6 +772,13 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Jump jump = as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), TargetPlatform::ScratchRegister);
jump.linkTo(loop, as);
}
+
+ static Jump checkIfTagRegisterIsDouble(JITAssembler *as, RegisterID tagRegister)
+ {
+ as->rshift32(TrustedImm32(Value::IsDoubleTag_Shift), tagRegister);
+ Jump isNoDbl = as->branch32(RelationalCondition::Equal, tagRegister, TrustedImm32(0));
+ return isNoDbl;
+ }
};
template <typename TargetConfiguration>
@@ -851,8 +847,6 @@ public:
return (hostOffset * RegisterSize) / QT_POINTER_SIZE;
}
- using RegisterSizeDependentOps = RegisterSizeDependentAssembler<Assembler<TargetConfiguration>, MacroAssembler, JITTargetPlatform, RegisterSize>;
-
struct LookupCall {
Address addr;
uint getterSetterOffset;
@@ -883,6 +877,10 @@ public:
{}
};
+ using RegisterSizeDependentOps = RegisterSizeDependentAssembler<Assembler<TargetConfiguration>, MacroAssembler, JITTargetPlatform, RegisterSize>;
+ using ValueTypeInternal = typename RegisterSizeDependentOps::ValueTypeInternal;
+ using TargetPrimitive = typename RegisterSizeDependentOps::TargetPrimitive;
+
// V4 uses two stacks: one stack with QV4::Value items, which is checked by the garbage
// collector, and one stack used by the native C/C++/ABI code. This C++ stack is not scanned
// by the garbage collector, so if any JS object needs to be retained, it should be put on the
@@ -1112,7 +1110,7 @@ public:
}
Pointer loadStringAddress(RegisterID reg, const QString &string);
Address loadConstant(IR::Const *c, RegisterID baseReg);
- Address loadConstant(const Primitive &v, RegisterID baseReg);
+ Address loadConstant(const TargetPrimitive &v, RegisterID baseReg);
void loadStringRef(RegisterID reg, const QString &string);
Pointer stackSlotPointer(IR::Temp *t) const
{
@@ -1387,12 +1385,12 @@ public:
RegisterSizeDependentOps::emitWriteBarrier(this, dest);
}
- void storeValue(QV4::Primitive value, Address destination, WriteBarrier::Type barrier)
+ void storeValue(TargetPrimitive value, Address destination, WriteBarrier::Type barrier)
{
RegisterSizeDependentOps::storeValue(this, value, destination, barrier);
}
- void storeValue(QV4::Primitive value, IR::Expr* temp);
+ void storeValue(TargetPrimitive value, IR::Expr* temp);
void emitWriteBarrier(Address addr, WriteBarrier::Type barrier) {
if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
@@ -1426,13 +1424,7 @@ public:
if (argumentNumber < RegisterArgumentCount)
loadArgumentInRegister(value, registerForArgument(argumentNumber), argumentNumber);
else
-#if OS(WINDOWS) && CPU(X86_64)
- loadArgumentOnStack<argumentNumber>(value, argumentNumber);
-#elif CPU(MIPS) // Stack space for 4 arguments needs to be allocated for MIPS platforms.
- loadArgumentOnStack<argumentNumber>(value, argumentNumber + 4);
-#else // Sanity:
- loadArgumentOnStack<argumentNumber - RegisterArgumentCount>(value, argumentNumber);
-#endif
+ loadArgumentOnStack<argumentNumber - RegisterArgumentCount + (StackShadowSpace / RegisterSize)>(value, argumentNumber);
}
template <int argumentNumber>
@@ -1576,8 +1568,8 @@ public:
Address tagAddr = addr;
tagAddr.offset += 4;
- QV4::Primitive v = convertToValue(c);
- store32(TrustedImm32(v.int_32()), addr);
+ auto v = convertToValue<TargetPrimitive>(c);
+ store32(TrustedImm32(v.value()), addr);
store32(TrustedImm32(v.tag()), tagAddr);
return Pointer(addr);
}
@@ -1593,7 +1585,7 @@ public:
{
store32(reg, addr);
addr.offset += 4;
- store32(TrustedImm32(QV4::Primitive::fromBoolean(0).tag()), addr);
+ store32(TrustedImm32(TargetPrimitive::fromBoolean(0).tag()), addr);
if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
RegisterSizeDependentOps::emitWriteBarrier(this, addr);
}
@@ -1640,7 +1632,7 @@ public:
{
store32(reg, addr);
addr.offset += 4;
- store32(TrustedImm32(QV4::Primitive::fromInt32(0).tag()), addr);
+ store32(TrustedImm32(TargetPrimitive::fromInt32(0).tag()), addr);
if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
RegisterSizeDependentOps::emitWriteBarrier(this, addr);
}
@@ -1709,7 +1701,7 @@ public:
RegisterID toInt32Register(IR::Expr *e, RegisterID scratchReg)
{
if (IR::Const *c = e->asConst()) {
- move(TrustedImm32(convertToValue(c).int_32()), scratchReg);
+ move(TrustedImm32(convertToValue<Primitive>(c).int_32()), scratchReg);
return scratchReg;
}
@@ -1748,11 +1740,11 @@ public:
Pointer tagAddr = addr;
tagAddr.offset += 4;
load32(tagAddr, scratchReg);
- Jump inIntRange = branch32(RelationalCondition::Equal, scratchReg, TrustedImm32(QV4::Value::Integer_Type_Internal));
+ Jump inIntRange = branch32(RelationalCondition::Equal, scratchReg, TrustedImm32(quint32(ValueTypeInternal::Integer)));
// it's not in signed int range, so load it as a double, and truncate it down
loadDouble(addr, FPGpr0);
- Address inversionAddress = loadConstant(QV4::Primitive::fromDouble(double(INT_MAX) + 1), scratchReg);
+ Address inversionAddress = loadConstant(TargetPrimitive::fromDouble(double(INT_MAX) + 1), scratchReg);
subDouble(inversionAddress, FPGpr0);
Jump canNeverHappen = branchTruncateDoubleToUint32(FPGpr0, scratchReg);
canNeverHappen.link(this);
@@ -1808,6 +1800,9 @@ private:
};
template <typename TargetConfiguration>
+const typename Assembler<TargetConfiguration>::VoidType Assembler<TargetConfiguration>::Void;
+
+template <typename TargetConfiguration>
template <typename Result, typename Source>
void Assembler<TargetConfiguration>::copyValue(Result result, Source source, WriteBarrier::Type barrier)
{
@@ -1832,7 +1827,7 @@ void Assembler<TargetConfiguration>::copyValue(Result result, IR::Expr* source,
} else if (source->asTemp() || source->asArgLocal()) {
RegisterSizeDependentOps::copyValueViaRegisters(this, source, result, barrier);
} else if (IR::Const *c = source->asConst()) {
- QV4::Primitive v = convertToValue(c);
+ auto v = convertToValue<TargetPrimitive>(c);
storeValue(v, result, barrier);
} else {
Q_UNREACHABLE();
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index 9841620481..c2853a39d2 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -256,7 +256,7 @@ void InstructionSelection<JITAssembler>::callBuiltinDeleteName(const QString &na
template <typename JITAssembler>
void InstructionSelection<JITAssembler>::callBuiltinDeleteValue(IR::Expr *result)
{
- _as->storeValue(Primitive::fromBoolean(false), result);
+ _as->storeValue(JITAssembler::TargetPrimitive::fromBoolean(false), result);
}
template <typename JITAssembler>
@@ -376,7 +376,7 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr
++arrayValueCount;
// Index
- _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier);
+ _as->storeValue(JITAssembler::TargetPrimitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier);
// Value
_as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
@@ -400,7 +400,7 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr
++arrayGetterSetterCount;
// Index
- _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier);
+ _as->storeValue(JITAssembler::TargetPrimitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier);
// Getter
_as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
@@ -488,7 +488,7 @@ void InstructionSelection<JITAssembler>::loadConst(IR::Const *sourceConst, IR::E
_as->toUInt32Register(sourceConst, (RegisterID) targetTemp->index);
} else if (targetTemp->type == IR::BoolType) {
Q_ASSERT(sourceConst->type == IR::BoolType);
- _as->move(TrustedImm32(convertToValue(sourceConst).int_32()),
+ _as->move(TrustedImm32(convertToValue<Primitive>(sourceConst).int_32()),
(RegisterID) targetTemp->index);
} else {
Q_UNREACHABLE();
@@ -497,7 +497,7 @@ void InstructionSelection<JITAssembler>::loadConst(IR::Const *sourceConst, IR::E
}
}
- _as->storeValue(convertToValue(sourceConst), target);
+ _as->storeValue(convertToValue<typename JITAssembler::TargetPrimitive>(sourceConst), target);
}
template <typename JITAssembler>
@@ -781,10 +781,10 @@ void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr *
quint32 tag;
switch (regTemp->type) {
case IR::BoolType:
- tag = QV4::Value::Boolean_Type_Internal;
+ tag = quint32(JITAssembler::ValueTypeInternal::Boolean);
break;
case IR::SInt32Type:
- tag = QV4::Value::Integer_Type_Internal;
+ tag = quint32(JITAssembler::ValueTypeInternal::Integer);
break;
default:
tag = 31337; // bogus value
@@ -933,7 +933,7 @@ void InstructionSelection<JITAssembler>::convertTypeToDouble(IR::Expr *source, I
// check if it's an int32:
Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
- TrustedImm32(Value::Integer_Type_Internal));
+ TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer)));
convertIntToDouble(source, target);
Jump intDone = _as->jump();
@@ -1002,6 +1002,7 @@ void InstructionSelection<JITAssembler>::convertTypeToBool(IR::Expr *source, IR:
generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean,
PointerToValue(source));
_as->storeBool(JITTargetPlatform::ReturnValueRegister, target);
+ Q_FALLTHROUGH();
case IR::VarType:
default:
Pointer addr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
@@ -1011,13 +1012,13 @@ void InstructionSelection<JITAssembler>::convertTypeToBool(IR::Expr *source, IR:
// checkif it's a bool:
Jump notBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister,
- TrustedImm32(Value::Boolean_Type_Internal));
+ TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Boolean)));
_as->load32(addr, JITTargetPlatform::ReturnValueRegister);
Jump boolDone = _as->jump();
// check if it's an int32:
notBool.link(_as);
Jump fallback = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister,
- TrustedImm32(Value::Integer_Type_Internal));
+ TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer)));
_as->load32(addr, JITTargetPlatform::ReturnValueRegister);
Jump isZero = _as->branch32(RelationalCondition::Equal, JITTargetPlatform::ReturnValueRegister,
TrustedImm32(0));
@@ -1087,7 +1088,7 @@ void InstructionSelection<JITAssembler>::convertTypeToUInt32(IR::Expr *source, I
// check if it's an int32:
Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
- TrustedImm32(Value::Integer_Type_Internal));
+ TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer)));
Pointer addr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
_as->storeUInt32(_as->toInt32Register(addr, JITTargetPlatform::ScratchRegister), target);
Jump intDone = _as->jump();
@@ -1203,7 +1204,8 @@ void InstructionSelection<JITAssembler>::visitCJump(IR::CJump *s)
Address temp = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, s->cond);
Address tag = temp;
tag.offset += QV4::Value::tagOffset();
- Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag, TrustedImm32(QV4::Value::Boolean_Type_Internal));
+ Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag,
+ TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Boolean)));
Address data = temp;
data.offset += QV4::Value::valueOffset();
@@ -1322,12 +1324,12 @@ int InstructionSelection<JITAssembler>::prepareCallData(IR::ExprList* args, IR::
}
Pointer p = _as->stackLayout().callDataAddress(offsetof(CallData, tag));
- _as->store32(TrustedImm32(QV4::Value::Integer_Type_Internal), p);
+ _as->store32(TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer)), p);
p = _as->stackLayout().callDataAddress(offsetof(CallData, argc));
_as->store32(TrustedImm32(argc), p);
p = _as->stackLayout().callDataAddress(offsetof(CallData, thisObject));
if (!thisObject)
- _as->storeValue(QV4::Primitive::undefinedValue(), p, WriteBarrier::NoBarrier);
+ _as->storeValue(JITAssembler::TargetPrimitive::undefinedValue(), p, WriteBarrier::NoBarrier);
else
_as->copyValue(p, thisObject, WriteBarrier::NoBarrier);
@@ -1464,7 +1466,7 @@ bool InstructionSelection<JITAssembler>::visitCJumpStrictNull(IR::Binop *binop,
RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal
: RelationalCondition::NotEqual;
- const TrustedImm32 tag(QV4::Value::Null_Type_Internal);
+ const TrustedImm32 tag{quint32(JITAssembler::ValueTypeInternal::Null)};
_as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock);
return true;
}
@@ -1546,7 +1548,7 @@ bool InstructionSelection<JITAssembler>::visitCJumpStrictBool(IR::Binop *binop,
// check if the tag of the var operand is indicates 'boolean'
_as->load32(otherAddr, JITTargetPlatform::ScratchRegister);
Jump noBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
- TrustedImm32(QV4::Value::Boolean_Type_Internal));
+ TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Boolean)));
if (binop->op == IR::OpStrictEqual)
_as->addPatch(falseBlock, noBool);
else
@@ -1596,7 +1598,7 @@ bool InstructionSelection<JITAssembler>::visitCJumpNullUndefined(IR::Type nullOr
if (binop->op == IR::OpNotEqual)
qSwap(trueBlock, falseBlock);
- Jump isNull = _as->branch32(RelationalCondition::Equal, tagReg, TrustedImm32(int(QV4::Value::Null_Type_Internal)));
+ Jump isNull = _as->branch32(RelationalCondition::Equal, tagReg, TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Null)));
Jump isNotUndefinedTag = _as->branch32(RelationalCondition::NotEqual, tagReg, TrustedImm32(int(QV4::Value::Managed_Type_Internal)));
tagAddr.offset -= 4;
_as->load32(tagAddr, tagReg);
@@ -1648,18 +1650,18 @@ Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &arch
using ARMv7CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>;
using ARM64CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>;
- if (architecture == QLatin1String("armv7"))
+ if (architecture == QLatin1String("arm"))
return new ISelFactory<ARMv7CrossAssembler>;
- else if (architecture == QLatin1String("armv8"))
+ else if (architecture == QLatin1String("arm64"))
return new ISelFactory<ARM64CrossAssembler>;
QString hostArch;
#if CPU(ARM_THUMB2)
- hostArch = QStringLiteral("armv7");
+ hostArch = QStringLiteral("arm");
#elif CPU(MIPS)
hostArch = QStringLiteral("mips");
#elif CPU(X86)
- hostArch = QStringLiteral("x86");
+ hostArch = QStringLiteral("i386");
#elif CPU(X86_64)
hostArch = QStringLiteral("x86_64");
#endif
diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h
index 0d02284539..7019a117a2 100644
--- a/src/qml/jit/qv4isel_masm_p.h
+++ b/src/qml/jit/qv4isel_masm_p.h
@@ -160,7 +160,7 @@ protected:
// FramePointerRegister points to its old value on the stack, and above
// it we have the return address, hence the need to step over two
// values before reaching the first argument.
- return Address(JITTargetPlatform::FramePointerRegister, (index + 2) * sizeof(void*));
+ return Address(JITTargetPlatform::FramePointerRegister, (index + 2) * JITTargetPlatform::RegisterSize);
}
Pointer baseAddressForCallArguments()
diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp
index 8eafaaaa8a..d418b050c4 100644
--- a/src/qml/jit/qv4regalloc.cpp
+++ b/src/qml/jit/qv4regalloc.cpp
@@ -125,6 +125,7 @@ protected:
*out << ri->prettyName();
break;
}
+ Q_FALLTHROUGH();
}
default:
IRPrinterWithPositions::visitTemp(e);
@@ -662,6 +663,7 @@ protected: // IRDecoder
addUses(rightSource->asTemp(), Use::MustHaveRegister);
break;
}
+ Q_FALLTHROUGH();
#endif
case OpBitAnd:
case OpBitOr:
diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h
index ce6156802d..6d788f4a93 100644
--- a/src/qml/jit/qv4targetplatform_p.h
+++ b/src/qml/jit/qv4targetplatform_p.h
@@ -405,7 +405,7 @@ public:
<< RI(JSC::ARMRegisters::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
#endif
<< RI(JSC::ARMRegisters::r10, QStringLiteral("r10"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
-#if CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP)
+#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP)
<< RI(JSC::ARMRegisters::r11, QStringLiteral("r11"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
#endif
<< RI(JSC::ARMRegisters::d2, QStringLiteral("d2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index b52c859ecb..e4c150057a 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -333,7 +333,7 @@ QJSEngine::~QJSEngine()
*/
void QJSEngine::collectGarbage()
{
- d->m_v4Engine->memoryManager->runGC(/* forceFullCollection = */ true);
+ d->m_v4Engine->memoryManager->runGC();
}
#if QT_DEPRECATED_SINCE(5, 6)
diff --git a/src/qml/jsapi/qjsvalue.h b/src/qml/jsapi/qjsvalue.h
index ab20a2607d..56bd64eec1 100644
--- a/src/qml/jsapi/qjsvalue.h
+++ b/src/qml/jsapi/qjsvalue.h
@@ -133,9 +133,9 @@ public:
bool deleteProperty(const QString &name);
bool isCallable() const;
- QJSValue call(const QJSValueList &args = QJSValueList());
- QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &args = QJSValueList());
- QJSValue callAsConstructor(const QJSValueList &args = QJSValueList());
+ QJSValue call(const QJSValueList &args = QJSValueList()); // ### Qt6: Make const
+ QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &args = QJSValueList()); // ### Qt6: Make const
+ QJSValue callAsConstructor(const QJSValueList &args = QJSValueList()); // ### Qt6: Make const
#ifdef QT_DEPRECATED
QT_DEPRECATED QJSEngine *engine() const;
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index b71e71b92f..02d3af619e 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -62,9 +62,8 @@ DEFINE_MANAGED_VTABLE(GlobalContext);
Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData *callData)
{
- uint localsAndFormals = function->compiledFunction->nLocals + qMax(static_cast<uint>(callData->argc), function->nFormals);
- size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + \
- sizeof(Value) * (localsAndFormals) + sizeof(CallData) - sizeof(Value);
+ uint localsAndFormals = function->compiledFunction->nLocals + sizeof(CallData)/sizeof(Value) - 1 + qMax(static_cast<uint>(callData->argc), function->nFormals);
+ size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * (localsAndFormals);
Heap::CallContext *c = d()->engine->memoryManager->allocManaged<CallContext>(requiredMemory);
c->init(d()->engine, Heap::ExecutionContext::Type_CallContext);
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 679cd41ce0..2735883603 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -136,6 +136,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
, currentContext(0)
, bumperPointerAllocator(new WTF::BumpPointerAllocator)
, jsStack(new WTF::PageAllocation)
+ , gcStack(new WTF::PageAllocation)
, globalCode(0)
, v8Engine(0)
, argumentsAccessors(0)
@@ -148,8 +149,6 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
, m_profiler(0)
#endif
{
- writeBarrierActive = true;
-
memoryManager = new QV4::MemoryManager(this);
if (maxCallDepth == -1) {
@@ -184,24 +183,28 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
"solutions for your platform.");
}
#else
- factory = new JIT::ISelFactory;
+ factory = new JIT::ISelFactory<>;
#endif
}
iselFactory.reset(factory);
// reserve space for the JS stack
- // we allow it to grow to 2 times JSStackLimit, as we can overshoot due to garbage collection
- // and ScopedValues allocated outside of JIT'ed methods.
- *jsStack = WTF::PageAllocation::allocate(2 * JSStackLimit, WTF::OSAllocator::JSVMStackPages,
+ // we allow it to grow to a bit more than JSStackLimit, as we can overshoot due to ScopedValues
+ // allocated outside of JIT'ed methods.
+ *jsStack = WTF::PageAllocation::allocate(JSStackLimit + 256*1024, WTF::OSAllocator::JSVMStackPages,
/* writable */ true, /* executable */ false,
/* includesGuardPages */ true);
jsStackBase = (Value *)jsStack->base();
#ifdef V4_USE_VALGRIND
- VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, 2*JSStackLimit);
+ VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, JSStackLimit + 256*1024);
#endif
jsStackTop = jsStackBase;
+ *gcStack = WTF::PageAllocation::allocate(GCStackLimit, WTF::OSAllocator::JSVMStackPages,
+ /* writable */ true, /* executable */ false,
+ /* includesGuardPages */ true);
+
exceptionValue = jsAlloca(1);
globalObject = static_cast<Object *>(jsAlloca(1));
jsObjects = jsAlloca(NJSObjects);
@@ -495,6 +498,8 @@ ExecutionEngine::~ExecutionEngine()
delete executableAllocator;
jsStack->deallocate();
delete jsStack;
+ gcStack->deallocate();
+ delete gcStack;
delete [] argumentsAccessors;
}
@@ -519,7 +524,7 @@ void ExecutionEngine::initRootContext()
sizeof(GlobalContext::Data) + sizeof(CallData)));
r->d_unchecked()->init(this);
r->d()->callData = reinterpret_cast<CallData *>(r->d() + 1);
- r->d()->callData->tag = QV4::Value::Integer_Type_Internal;
+ r->d()->callData->tag = quint32(Value::ValueTypeInternal::Integer);
r->d()->callData->argc = 0;
r->d()->callData->thisObject = globalObject;
r->d()->callData->args[0] = Encode::undefined();
@@ -932,25 +937,23 @@ void ExecutionEngine::requireArgumentsAccessors(int n)
}
}
-void ExecutionEngine::markObjects(bool incremental)
+void ExecutionEngine::markObjects(MarkStack *markStack)
{
- if (!incremental) {
- identifierTable->mark(this);
+ identifierTable->mark(markStack);
- for (int i = 0; i < nArgumentsAccessors; ++i) {
- const Property &pd = argumentsAccessors[i];
- if (Heap::FunctionObject *getter = pd.getter())
- getter->mark(this);
- if (Heap::FunctionObject *setter = pd.setter())
- setter->mark(this);
- }
+ for (int i = 0; i < nArgumentsAccessors; ++i) {
+ const Property &pd = argumentsAccessors[i];
+ if (Heap::FunctionObject *getter = pd.getter())
+ getter->mark(markStack);
+ if (Heap::FunctionObject *setter = pd.setter())
+ setter->mark(markStack);
+ }
- classPool->markObjects(this);
+ classPool->markObjects(markStack);
- for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd();
- it != end; ++it)
- (*it)->markObjects(this);
- }
+ for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd();
+ it != end; ++it)
+ (*it)->markObjects(markStack);
}
ReturnedValue ExecutionEngine::throwError(const Value &value)
@@ -1568,12 +1571,6 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
return 0;
}
-void ExecutionEngine::assertObjectBelongsToEngine(const Heap::Base &baseObject)
-{
- Q_ASSERT(!baseObject.vtable()->isObject || static_cast<const Heap::Object&>(baseObject).internalClass->engine == this);
- Q_UNUSED(baseObject);
-}
-
void ExecutionEngine::failStackLimitCheck(Scope &scope)
{
scope.result = throwRangeError(QStringLiteral("Maximum call stack size exceeded."));
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 1160d69c6c..a2c774c295 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -108,18 +108,14 @@ public:
WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine.
- enum { JSStackLimit = 4*1024*1024 };
+ enum {
+ JSStackLimit = 4*1024*1024,
+ GCStackLimit = 2*1024*1024
+ };
WTF::PageAllocation *jsStack;
Value *jsStackBase;
- void pushForGC(Heap::Base *m) {
- *jsStackTop = m;
- ++jsStackTop;
- }
- Heap::Base *popForGC() {
- --jsStackTop;
- return jsStackTop->m();
- }
+ WTF::PageAllocation *gcStack;
QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) {
Value *ptr = jsStackTop;
@@ -446,7 +442,7 @@ public:
void requireArgumentsAccessors(int n);
- void markObjects(bool incremental);
+ void markObjects(MarkStack *markStack);
void initRootContext();
@@ -483,8 +479,6 @@ public:
bool metaTypeFromJS(const Value *value, int type, void *data);
QV4::ReturnedValue metaTypeToJS(int type, const void *data);
- void assertObjectBelongsToEngine(const Heap::Base &baseObject);
-
bool checkStackLimits(Scope &scope);
private:
@@ -543,7 +537,7 @@ inline ExecutionContext *ExecutionEngine::parentContext(ExecutionContext *contex
}
inline
-void Heap::Base::mark(QV4::ExecutionEngine *engine)
+void Heap::Base::mark(QV4::MarkStack *markStack)
{
Q_ASSERT(inUse());
const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
@@ -553,19 +547,22 @@ void Heap::Base::mark(QV4::ExecutionEngine *engine)
quintptr *bitmap = c->blackBitmap + Chunk::bitmapIndex(index);
quintptr bit = Chunk::bitForIndex(index);
if (!(*bitmap & bit)) {
-#ifndef QT_NO_DEBUG
- engine->assertObjectBelongsToEngine(*this);
-#endif
*bitmap |= bit;
- engine->pushForGC(this);
+ markStack->push(this);
}
}
-inline void Value::mark(ExecutionEngine *e)
+inline void Value::mark(MarkStack *markStack)
{
Heap::Base *o = heapObject();
if (o)
- o->mark(e);
+ o->mark(markStack);
+}
+
+inline void Managed::mark(MarkStack *markStack)
+{
+ Q_ASSERT(m());
+ m()->mark(markStack);
}
#define CHECK_STACK_LIMITS(v4, scope) if ((v4)->checkStackLimits(scope)) return; \
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 1bc91f832b..f0630660d4 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -394,6 +394,7 @@ void EvalFunction::evalCall(Scope &scope, CallData *callData, bool directCall) c
// set the correct strict mode flag on the context
ctx->d()->strictMode = false;
ctx->d()->compilationUnit = function->compilationUnit;
+ ctx->d()->constantTable = function->compilationUnit->constants;
scope.result = Q_V4_PROFILE(ctx->engine(), function);
}
diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp
index d3ef238716..3def6defbf 100644
--- a/src/qml/jsruntime/qv4identifiertable.cpp
+++ b/src/qml/jsruntime/qv4identifiertable.cpp
@@ -81,7 +81,6 @@ void IdentifierTable::addEntry(Heap::String *str)
str->identifier = new Identifier;
str->identifier->string = str->toQString();
str->identifier->hashValue = hash;
- str->setMarkBit();
bool grow = (alloc <= size*2);
diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h
index 89af5db731..b0b08f1e54 100644
--- a/src/qml/jsruntime/qv4identifiertable_p.h
+++ b/src/qml/jsruntime/qv4identifiertable_p.h
@@ -93,14 +93,14 @@ public:
Heap::String *stringFromIdentifier(Identifier *i);
- void mark(ExecutionEngine *e) {
+ void mark(MarkStack *markStack) {
for (int i = 0; i < alloc; ++i) {
Heap::String *entry = entries[i];
if (!entry || entry->isMarked())
continue;
entry->setMarkBit();
Q_ASSERT(entry->vtable()->markObjects);
- entry->vtable()->markObjects(entry, e);
+ entry->vtable()->markObjects(entry, markStack);
}
}
};
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 9b18a5566e..3d9a672f2f 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -388,9 +388,9 @@ void InternalClass::destroy()
}
}
-void InternalClassPool::markObjects(ExecutionEngine *engine)
+void InternalClassPool::markObjects(MarkStack *markStack)
{
- Q_UNUSED(engine);
+ Q_UNUSED(markStack);
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index 1d8ef4b0fb..a29ce5b5ff 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -291,7 +291,7 @@ inline uint InternalClass::find(const String *string)
struct InternalClassPool : public QQmlJS::MemoryPool
{
- void markObjects(ExecutionEngine *engine);
+ void markObjects(MarkStack *markStack);
};
}
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 3dc54b13da..f97771831c 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -207,9 +207,10 @@ public:
bool inUse() const { return d()->inUse(); }
bool markBit() const { return d()->isMarked(); }
+ inline void mark(MarkStack *markStack);
static void destroy(Heap::Base *) {}
- static void markObjects(Heap::Base *, ExecutionEngine *) {}
+ static void markObjects(Heap::Base *, MarkStack *) {}
Q_ALWAYS_INLINE Heap::Base *heapObject() const {
return m();
diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp
index 59115dfe21..3427ee89fe 100644
--- a/src/qml/jsruntime/qv4objectiterator.cpp
+++ b/src/qml/jsruntime/qv4objectiterator.cpp
@@ -177,10 +177,10 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString()
DEFINE_OBJECT_VTABLE(ForEachIteratorObject);
-void ForEachIteratorObject::markObjects(Heap::Base *that, ExecutionEngine *e)
+void ForEachIteratorObject::markObjects(Heap::Base *that, MarkStack *markStack)
{
ForEachIteratorObject::Data *o = static_cast<ForEachIteratorObject::Data *>(that);
- o->workArea[0].mark(e);
- o->workArea[1].mark(e);
- Object::markObjects(that, e);
+ o->workArea[0].mark(markStack);
+ o->workArea[1].mark(markStack);
+ Object::markObjects(that, markStack);
}
diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h
index 98e94a95ea..6168d59914 100644
--- a/src/qml/jsruntime/qv4objectiterator_p.h
+++ b/src/qml/jsruntime/qv4objectiterator_p.h
@@ -129,7 +129,7 @@ struct ForEachIteratorObject: Object {
ReturnedValue nextPropertyName() { return d()->it().nextPropertyNameAsString(); }
protected:
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
+ static void markObjects(Heap::Base *that, MarkStack *markStack);
};
inline
diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp
index de82bf835f..0b31c971f9 100644
--- a/src/qml/jsruntime/qv4persistent.cpp
+++ b/src/qml/jsruntime/qv4persistent.cpp
@@ -215,17 +215,15 @@ void PersistentValueStorage::free(Value *v)
freePage(p);
}
-void PersistentValueStorage::mark(ExecutionEngine *e)
+void PersistentValueStorage::mark(MarkStack *markStack)
{
- Value *markBase = e->jsStackTop;
-
Page *p = static_cast<Page *>(firstPage);
while (p) {
for (int i = 0; i < kEntriesPerPage; ++i) {
if (Managed *m = p->values[i].as<Managed>())
- m->mark(e);
+ m->mark(markStack);
}
- e->memoryManager->drainMarkStack(markBase);
+ markStack->drain();
p = p->header.next;
}
@@ -384,11 +382,11 @@ void WeakValue::allocVal(ExecutionEngine *engine)
val = engine->memoryManager->m_weakValues->allocate();
}
-void WeakValue::markOnce(ExecutionEngine *e)
+void WeakValue::markOnce(MarkStack *markStack)
{
if (!val)
return;
- val->mark(e);
+ val->mark(markStack);
}
void WeakValue::free()
diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h
index c1cd1f34df..1f838f5531 100644
--- a/src/qml/jsruntime/qv4persistent_p.h
+++ b/src/qml/jsruntime/qv4persistent_p.h
@@ -65,7 +65,7 @@ struct Q_QML_EXPORT PersistentValueStorage
Value *allocate();
static void free(Value *e);
- void mark(ExecutionEngine *e);
+ void mark(MarkStack *markStack);
struct Iterator {
Iterator(void *p, int idx);
@@ -203,7 +203,7 @@ public:
bool isNullOrUndefined() const { return !val || val->isNullOrUndefined(); }
void clear() { free(); }
- void markOnce(ExecutionEngine *e);
+ void markOnce(MarkStack *markStack);
private:
Value *val;
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 4f6c179026..1dd90995d3 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -539,7 +539,7 @@ ReturnedValue QObjectWrapper::wrap_slowPath(ExecutionEngine *engine, QObject *ob
}
}
-void QObjectWrapper::markWrapper(QObject *object, ExecutionEngine *engine)
+void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack)
{
if (QQmlData::wasDeleted(object))
return;
@@ -548,10 +548,10 @@ void QObjectWrapper::markWrapper(QObject *object, ExecutionEngine *engine)
if (!ddata)
return;
- if (ddata->jsEngineId == engine->m_engineId)
- ddata->jsWrapper.markOnce(engine);
- else if (engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object)
- engine->m_multiplyWrappedQObjects->mark(object, engine);
+ if (ddata->jsEngineId == markStack->engine->m_engineId)
+ ddata->jsWrapper.markOnce(markStack);
+ else if (markStack->engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object)
+ markStack->engine->m_multiplyWrappedQObjects->mark(object, markStack);
}
ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired)
@@ -938,36 +938,36 @@ void QObjectWrapper::method_disconnect(const BuiltinFunction *, Scope &scope, Ca
RETURN_UNDEFINED();
}
-static void markChildQObjectsRecursively(QObject *parent, QV4::ExecutionEngine *e)
+static void markChildQObjectsRecursively(QObject *parent, QV4::MarkStack *markStack)
{
const QObjectList &children = parent->children();
for (int i = 0; i < children.count(); ++i) {
QObject *child = children.at(i);
if (!child)
continue;
- QObjectWrapper::markWrapper(child, e);
- markChildQObjectsRecursively(child, e);
+ QObjectWrapper::markWrapper(child, markStack);
+ markChildQObjectsRecursively(child, markStack);
}
}
-void QObjectWrapper::markObjects(Heap::Base *that, QV4::ExecutionEngine *e)
+void QObjectWrapper::markObjects(Heap::Base *that, QV4::MarkStack *markStack)
{
QObjectWrapper::Data *This = static_cast<QObjectWrapper::Data *>(that);
if (QObject *o = This->object()) {
QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
if (vme)
- vme->mark(e);
+ vme->mark(markStack);
// Children usually don't need to be marked, the gc keeps them alive.
// But in the rare case of a "floating" QObject without a parent that
// _gets_ marked (we've been called here!) then we also need to
// propagate the marking down to the children recursively.
if (!o->parent())
- markChildQObjectsRecursively(o, e);
+ markChildQObjectsRecursively(o, markStack);
}
- QV4::Object::markObjects(that, e);
+ QV4::Object::markObjects(that, markStack);
}
void QObjectWrapper::destroyObject(bool lastCall)
@@ -992,6 +992,10 @@ void QObjectWrapper::destroyObject(bool lastCall)
// If the object is C++-owned, we still have to release the weak reference we have
// to it.
ddata->jsWrapper.clear();
+ if (lastCall && ddata->propertyCache) {
+ ddata->propertyCache->release();
+ ddata->propertyCache = nullptr;
+ }
}
}
}
@@ -2066,12 +2070,12 @@ void MultiplyWrappedQObjectMap::remove(QObject *key)
erase(it);
}
-void MultiplyWrappedQObjectMap::mark(QObject *key, ExecutionEngine *engine)
+void MultiplyWrappedQObjectMap::mark(QObject *key, MarkStack *markStack)
{
Iterator it = find(key);
if (it == end())
return;
- it->markOnce(engine);
+ it->markOnce(markStack);
}
void MultiplyWrappedQObjectMap::removeDestroyedObject(QObject *object)
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index c031a40211..55700d17c1 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -171,7 +171,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object
static bool setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const Value &value);
static ReturnedValue wrap(ExecutionEngine *engine, QObject *object);
- static void markWrapper(QObject *object, ExecutionEngine *engine);
+ static void markWrapper(QObject *object, MarkStack *markStack);
using Object::get;
@@ -195,7 +195,7 @@ protected:
static bool put(Managed *m, String *name, const Value &value);
static PropertyAttributes query(const Managed *, String *name);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
- static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
+ static void markObjects(Heap::Base *that, QV4::MarkStack *markStack);
static void method_connect(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_disconnect(const BuiltinFunction *, Scope &scope, CallData *callData);
@@ -209,13 +209,10 @@ inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *obje
if (Q_UNLIKELY(QQmlData::wasDeleted(object)))
return QV4::Encode::null();
- QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
- if (Q_LIKELY(priv->declarativeData)) {
- auto ddata = static_cast<QQmlData *>(priv->declarativeData);
- if (Q_LIKELY(ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isUndefined())) {
- // We own the JS object
- return ddata->jsWrapper.value();
- }
+ auto ddata = QQmlData::get(object);
+ if (Q_LIKELY(ddata && ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isUndefined())) {
+ // We own the JS object
+ return ddata->jsWrapper.value();
}
return wrap_slowPath(engine, object);
@@ -295,7 +292,7 @@ public:
ReturnedValue value(QObject *key) const { return QHash<QObject*, QV4::WeakValue>::value(key).value(); }
Iterator erase(Iterator it);
void remove(QObject *key);
- void mark(QObject *key, ExecutionEngine *engine);
+ void mark(QObject *key, MarkStack *markStack);
private Q_SLOTS:
void removeDestroyedObject(QObject*);
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index b28a5f9000..9da0df326f 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -472,6 +472,7 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, const Val
switch (value.type()) {
case Value::Empty_Type:
Q_ASSERT(!"empty Value encountered");
+ Q_UNREACHABLE();
case Value::Undefined_Type:
return engine->id_undefined()->d();
case Value::Null_Type:
@@ -504,6 +505,7 @@ static Heap::String *convert_to_string_add(ExecutionEngine *engine, const Value
switch (value.type()) {
case Value::Empty_Type:
Q_ASSERT(!"empty Value encountered");
+ Q_UNREACHABLE();
case Value::Undefined_Type:
return engine->id_undefined()->d();
case Value::Null_Type:
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index 894434be16..e9dcc9172f 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -368,7 +368,7 @@ struct ScopedCallData {
{
int size = qMax(argc, QV4::Global::ReservedArgumentCount + int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)));
ptr = reinterpret_cast<CallData *>(scope.alloc(size));
- ptr->tag = QV4::Value::Integer_Type_Internal;
+ ptr->tag = quint32(QV4::Value::ValueTypeInternal::Integer);
ptr->argc = argc;
}
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 6d3110771e..2281fa22b6 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -78,13 +78,22 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description
F(int, IntVector, QVector<int>, 0) \
F(qreal, RealVector, QVector<qreal>, 0.0) \
F(bool, BoolVector, QVector<bool>, false) \
+ F(int, IntStdVector, std::vector<int>, 0) \
+ F(qreal, RealStdVector, std::vector<qreal>, 0.0) \
+ F(bool, BoolStdVector, std::vector<bool>, false) \
F(int, Int, QList<int>, 0) \
F(qreal, Real, QList<qreal>, 0.0) \
F(bool, Bool, QList<bool>, false) \
F(QString, String, QList<QString>, QString()) \
F(QString, QString, QStringList, QString()) \
+ F(QString, StringVector, QVector<QString>, QString()) \
+ F(QString, StringStdVector, std::vector<QString>, QString()) \
F(QUrl, Url, QList<QUrl>, QUrl()) \
+ F(QUrl, UrlVector, QVector<QUrl>, QUrl()) \
+ F(QUrl, UrlStdVector, std::vector<QUrl>, QUrl()) \
F(QModelIndex, QModelIndex, QModelIndexList, QModelIndex()) \
+ F(QModelIndex, QModelIndexVector, QVector<QModelIndex>, QModelIndex()) \
+ F(QModelIndex, QModelIndexStdVector, std::vector<QModelIndex>, QModelIndex()) \
F(QItemSelectionRange, QItemSelectionRange, QItemSelection, QItemSelectionRange())
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QString &element)
@@ -263,11 +272,10 @@ public:
}
loadReference();
}
- qint32 signedIdx = static_cast<qint32>(index);
- if (signedIdx < d()->container->count()) {
+ if (index < size_t(d()->container->size())) {
if (hasProperty)
*hasProperty = true;
- return convertElementToValue(engine(), d()->container->at(signedIdx));
+ return convertElementToValue(engine(), qAsConst(*(d()->container))[index]);
}
if (hasProperty)
*hasProperty = false;
@@ -291,24 +299,22 @@ public:
loadReference();
}
- qint32 signedIdx = static_cast<qint32>(index);
-
- int count = d()->container->count();
+ size_t count = size_t(d()->container->size());
typename Container::value_type element = convertValueToElement<typename Container::value_type>(value);
- if (signedIdx == count) {
- d()->container->append(element);
- } else if (signedIdx < count) {
- (*d()->container)[signedIdx] = element;
+ if (index == count) {
+ d()->container->push_back(element);
+ } else if (index < count) {
+ (*d()->container)[index] = element;
} else {
/* according to ECMA262r3 we need to insert */
/* the value at the given index, increasing length to index+1. */
- d()->container->reserve(signedIdx + 1);
- while (signedIdx > count++) {
- d()->container->append(typename Container::value_type());
+ d()->container->reserve(index + 1);
+ while (index > count++) {
+ d()->container->push_back(typename Container::value_type());
}
- d()->container->append(element);
+ d()->container->push_back(element);
}
if (d()->isReference)
@@ -328,8 +334,7 @@ public:
return QV4::Attr_Invalid;
loadReference();
}
- qint32 signedIdx = static_cast<qint32>(index);
- return (signedIdx < d()->container->count()) ? QV4::Attr_Data : QV4::Attr_Invalid;
+ return (index < size_t(d()->container->size())) ? QV4::Attr_Data : QV4::Attr_Invalid;
}
void containerAdvanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs)
@@ -345,7 +350,7 @@ public:
loadReference();
}
- if (it->arrayIndex < static_cast<uint>(d()->container->count())) {
+ if (it->arrayIndex < static_cast<uint>(d()->container->size())) {
*index = it->arrayIndex;
++it->arrayIndex;
*attrs = QV4::Attr_Data;
@@ -365,14 +370,13 @@ public:
return false;
loadReference();
}
- qint32 signedIdx = static_cast<qint32>(index);
- if (signedIdx >= d()->container->count())
+ if (index >= size_t(d()->container->size()))
return false;
/* according to ECMA262r3 it should be Undefined, */
/* but we cannot, so we insert a default-value instead. */
- d()->container->replace(signedIdx, typename Container::value_type());
+ (*d()->container)[index] = typename Container::value_type();
if (d()->isReference)
storeReference();
@@ -457,7 +461,7 @@ public:
RETURN_RESULT(Encode(0));
This->loadReference();
}
- RETURN_RESULT(Encode(This->d()->container->count()));
+ RETURN_RESULT(Encode(qint32(This->d()->container->size())));
}
static void method_set_length(const BuiltinFunction *, Scope &scope, CallData *callData)
@@ -479,8 +483,8 @@ public:
This->loadReference();
}
/* Determine whether we need to modify the sequence */
- qint32 newCount = static_cast<qint32>(newLength);
- qint32 count = This->d()->container->count();
+ quint32 newCount = static_cast<quint32>(newLength);
+ quint32 count = static_cast<quint32>(This->d()->container->size());
if (newCount == count) {
RETURN_UNDEFINED();
} else if (newCount > count) {
@@ -489,14 +493,13 @@ public:
/* We cannot, so we insert default-values instead. */
This->d()->container->reserve(newCount);
while (newCount > count++) {
- This->d()->container->append(typename Container::value_type());
+ This->d()->container->push_back(typename Container::value_type());
}
} else {
/* according to ECMA262r3 we need to remove */
/* elements until the sequence is the required length. */
- while (newCount < count) {
- count--;
- This->d()->container->removeAt(count);
+ if (newCount < count) {
+ This->d()->container->erase(This->d()->container->begin() + newCount, This->d()->container->end());
}
}
/* write back if required. */
@@ -517,7 +520,7 @@ public:
quint32 length = array->getLength();
QV4::ScopedValue v(scope);
for (quint32 i = 0; i < length; ++i)
- result << convertValueToElement<typename Container::value_type>((v = array->getIndexed(i)));
+ result.push_back(convertValueToElement<typename Container::value_type>((v = array->getIndexed(i))));
return QVariant::fromValue(result);
}
@@ -595,16 +598,34 @@ typedef QQmlSequence<QVector<qreal> > QQmlRealVectorList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlRealVectorList);
typedef QQmlSequence<QVector<bool> > QQmlBoolVectorList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlBoolVectorList);
+typedef QQmlSequence<std::vector<int> > QQmlIntStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlIntStdVectorList);
+typedef QQmlSequence<std::vector<qreal> > QQmlRealStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlRealStdVectorList);
+typedef QQmlSequence<std::vector<bool> > QQmlBoolStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlBoolStdVectorList);
typedef QQmlSequence<QStringList> QQmlQStringList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQStringList);
typedef QQmlSequence<QList<QString> > QQmlStringList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringList);
+typedef QQmlSequence<QVector<QString> > QQmlStringVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringVectorList);
+typedef QQmlSequence<std::vector<QString> > QQmlStringStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringStdVectorList);
typedef QQmlSequence<QList<int> > QQmlIntList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlIntList);
typedef QQmlSequence<QList<QUrl> > QQmlUrlList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlList);
+typedef QQmlSequence<QVector<QUrl> > QQmlUrlVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlVectorList);
+typedef QQmlSequence<std::vector<QUrl> > QQmlUrlStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlStdVectorList);
typedef QQmlSequence<QModelIndexList> QQmlQModelIndexList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexList);
+typedef QQmlSequence<QVector<QModelIndex> > QQmlQModelIndexVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexVectorList);
+typedef QQmlSequence<std::vector<QModelIndex> > QQmlQModelIndexStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexStdVectorList);
typedef QQmlSequence<QItemSelection> QQmlQItemSelectionRangeList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQItemSelectionRangeList);
typedef QQmlSequence<QList<bool> > QQmlBoolList;
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index cde2131aab..71f85c2d71 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -54,12 +54,12 @@ using namespace QV4;
DEFINE_MANAGED_VTABLE(String);
-void String::markObjects(Heap::Base *that, ExecutionEngine *e)
+void String::markObjects(Heap::Base *that, MarkStack *markStack)
{
String::Data *s = static_cast<String::Data *>(that);
if (s->largestSubLength) {
- s->left->mark(e);
- s->right->mark(e);
+ s->left->mark(markStack);
+ s->right->mark(markStack);
}
}
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index 5b0fd292d6..71e55cbcd4 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -204,7 +204,7 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
Identifier *identifier() const { return d()->identifier; }
protected:
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
+ static void markObjects(Heap::Base *that, MarkStack *markStack);
static bool isEqualTo(Managed *that, Managed *o);
static uint getLength(const Managed *m);
#endif
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp
index e34ac9c764..f41442df7a 100644
--- a/src/qml/jsruntime/qv4value.cpp
+++ b/src/qml/jsruntime/qv4value.cpp
@@ -113,6 +113,7 @@ double Value::toNumberImpl() const
case QV4::Value::Managed_Type:
#ifdef V4_BOOTSTRAP
Q_UNIMPLEMENTED();
+ Q_FALLTHROUGH();
#else
if (String *s = stringValue())
return RuntimeHelpers::stringToNumber(s->toQString());
@@ -140,6 +141,7 @@ QString Value::toQStringNoThrow() const
switch (type()) {
case Value::Empty_Type:
Q_ASSERT(!"empty Value encountered");
+ Q_UNREACHABLE();
case Value::Undefined_Type:
return QStringLiteral("undefined");
case Value::Null_Type:
@@ -193,6 +195,7 @@ QString Value::toQString() const
switch (type()) {
case Value::Empty_Type:
Q_ASSERT(!"empty Value encountered");
+ Q_UNREACHABLE();
case Value::Undefined_Type:
return QStringLiteral("undefined");
case Value::Null_Type:
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 11d75dde99..50cecb6598 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -207,23 +207,23 @@ public:
}
QML_NEARLY_ALWAYS_INLINE void setInt_32(int i)
{
- setTagValue(Integer_Type_Internal, quint32(i));
+ setTagValue(quint32(ValueTypeInternal::Integer), quint32(i));
}
QML_NEARLY_ALWAYS_INLINE uint uint_32() const { return value(); }
QML_NEARLY_ALWAYS_INLINE void setEmpty()
{
- setTagValue(Empty_Type_Internal, value());
+ setTagValue(quint32(ValueTypeInternal::Empty), value());
}
QML_NEARLY_ALWAYS_INLINE void setEmpty(int i)
{
- setTagValue(Empty_Type_Internal, quint32(i));
+ setTagValue(quint32(ValueTypeInternal::Empty), quint32(i));
}
QML_NEARLY_ALWAYS_INLINE void setEmpty(quint32 i)
{
- setTagValue(Empty_Type_Internal, i);
+ setTagValue(quint32(ValueTypeInternal::Empty), i);
}
QML_NEARLY_ALWAYS_INLINE quint32 emptyValue()
@@ -266,8 +266,17 @@ public:
IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift,
Managed_Type_Internal_64 = 0
};
+
static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49
+ enum class ValueTypeInternal_64 {
+ Empty = Immediate_Mask_64| 0,
+ ConvertibleToInt = Immediate_Mask_64| 0x10000u, // bit 48
+ Null = ConvertibleToInt | 0x08000u,
+ Boolean = ConvertibleToInt | 0x04000u,
+ Integer = ConvertibleToInt | 0x02000u
+ };
+
// Used only by 32-bit encoding
enum Masks {
SilentNaNBit = 0x00040000,
@@ -275,6 +284,14 @@ public:
};
static const quint64 Immediate_Mask_32 = NotDouble_Mask | 0x00020000u | SilentNaNBit;
+ enum class ValueTypeInternal_32 {
+ Empty = Immediate_Mask_32| 0,
+ ConvertibleToInt = Immediate_Mask_32| 0x10000u, // bit 48
+ Null = ConvertibleToInt | 0x08000u,
+ Boolean = ConvertibleToInt | 0x04000u,
+ Integer = ConvertibleToInt | 0x02000u
+ };
+
enum {
Managed_Type_Internal_32 = NotDouble_Mask
};
@@ -284,28 +301,23 @@ public:
Managed_Type_Internal = Managed_Type_Internal_64
};
static const quint64 Immediate_Mask = Immediate_Mask_64;
+ using ValueTypeInternal = ValueTypeInternal_64;
#else
enum {
Managed_Type_Internal = Managed_Type_Internal_32
};
static const quint64 Immediate_Mask = Immediate_Mask_32;
+ using ValueTypeInternal = ValueTypeInternal_32;
#endif
enum {
NaN_Mask = 0x7ff80000,
};
- enum ValueTypeInternal {
- Empty_Type_Internal = Immediate_Mask | 0,
- ConvertibleToInt = Immediate_Mask | 0x10000u, // bit 48
- Null_Type_Internal = ConvertibleToInt | 0x08000u,
- Boolean_Type_Internal = ConvertibleToInt | 0x04000u,
- Integer_Type_Internal = ConvertibleToInt | 0x02000u
- };
// used internally in property
- inline bool isEmpty() const { return tag() == Empty_Type_Internal; }
- inline bool isNull() const { return tag() == Null_Type_Internal; }
- inline bool isBoolean() const { return tag() == Boolean_Type_Internal; }
- inline bool isInteger() const { return tag() == Integer_Type_Internal; }
+ inline bool isEmpty() const { return tag() == quint32(ValueTypeInternal::Empty); }
+ inline bool isNull() const { return tag() == quint32(ValueTypeInternal::Null); }
+ inline bool isBoolean() const { return tag() == quint32(ValueTypeInternal::Boolean); }
+ inline bool isInteger() const { return tag() == quint32(ValueTypeInternal::Integer); }
inline bool isNullOrUndefined() const { return isNull() || isUndefined(); }
inline bool isNumber() const { return isDouble() || isInteger(); }
@@ -330,9 +342,9 @@ public:
inline bool isDouble() const { return (tag() & NotDouble_Mask) != NotDouble_Mask; }
inline bool isManaged() const { return tag() == Managed_Type_Internal && !isUndefined(); }
inline bool isManagedOrUndefined() const { return tag() == Managed_Type_Internal; }
- inline bool integerCompatible() const { return (tag() & ConvertibleToInt) == ConvertibleToInt; }
+ inline bool integerCompatible() const { return (tag() & quint32(ValueTypeInternal::ConvertibleToInt)) == quint32(ValueTypeInternal::ConvertibleToInt); }
static inline bool integerCompatible(Value a, Value b) {
- return ((a.tag() & b.tag()) & ConvertibleToInt) == ConvertibleToInt;
+ return ((a.tag() & b.tag()) & quint32(ValueTypeInternal::ConvertibleToInt)) == quint32(ValueTypeInternal::ConvertibleToInt);
}
static inline bool bothDouble(Value a, Value b) {
return ((a.tag() | b.tag()) & NotDouble_Mask) != NotDouble_Mask;
@@ -359,7 +371,7 @@ public:
inline bool isString() const;
inline bool isObject() const;
inline bool isInt32() {
- if (tag() == Integer_Type_Internal)
+ if (tag() == quint32(ValueTypeInternal::Integer))
return true;
if (isDouble()) {
double d = doubleValue();
@@ -372,7 +384,7 @@ public:
return false;
}
double asDouble() const {
- if (tag() == Integer_Type_Internal)
+ if (tag() == quint32(ValueTypeInternal::Integer))
return int_32();
return doubleValue();
}
@@ -427,7 +439,7 @@ public:
inline bool tryIntegerConversion() {
bool b = integerCompatible();
if (b)
- setTagValue(Integer_Type_Internal, value());
+ setTagValue(quint32(ValueTypeInternal::Integer), value());
return b;
}
@@ -475,7 +487,7 @@ public:
// Section 9.12
bool sameValue(Value other) const;
- inline void mark(ExecutionEngine *e);
+ inline void mark(MarkStack *markStack);
Value &operator =(const ScopedValue &v);
Value &operator=(ReturnedValue v) { _val = v; return *this; }
@@ -610,14 +622,14 @@ inline Primitive Primitive::emptyValue(uint e)
inline Primitive Primitive::nullValue()
{
Primitive v;
- v.setTagValue(Null_Type_Internal, 0);
+ v.setTagValue(quint32(ValueTypeInternal::Null), 0);
return v;
}
inline Primitive Primitive::fromBoolean(bool b)
{
Primitive v;
- v.setTagValue(Boolean_Type_Internal, b);
+ v.setTagValue(quint32(ValueTypeInternal::Boolean), b);
return v;
}
@@ -639,7 +651,7 @@ inline Primitive Primitive::fromUInt32(uint i)
{
Primitive v;
if (i < INT_MAX) {
- v.setTagValue(Integer_Type_Internal, i);
+ v.setTagValue(quint32(ValueTypeInternal::Integer), i);
} else {
v.setDouble(i);
}
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 8d523f17e9..e16df8dc60 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -251,6 +251,9 @@ int qt_v4DebuggerHook(const char *json)
static void qt_v4CheckForBreak(QV4::ExecutionContext *context)
{
+ if (!qt_v4IsStepping && !qt_v4Breakpoints.size())
+ return;
+
const int lineNumber = context->d()->lineNumber;
QV4::Function *function = qt_v4ExtractFunction(context);
QString engineName = function->sourceFile();
@@ -585,7 +588,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
#endif // DO_TRACE_INSTR
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = QV4::Value::Integer_Type_Internal;
+ callData->tag = quint32(Value::ValueTypeInternal::Integer);
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
STOREVALUE(instr.result, Runtime::method_callValue(engine, VALUE(instr.dest), callData));
@@ -595,7 +598,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData());
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = QV4::Value::Integer_Type_Internal;
+ callData->tag = quint32(Value::ValueTypeInternal::Integer);
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
STOREVALUE(instr.result, Runtime::method_callProperty(engine, instr.name, callData));
@@ -604,7 +607,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_BEGIN_INSTR(CallPropertyLookup)
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = QV4::Value::Integer_Type_Internal;
+ callData->tag = quint32(Value::ValueTypeInternal::Integer);
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
STOREVALUE(instr.result, Runtime::method_callPropertyLookup(engine, instr.lookupIndex, callData));
@@ -614,7 +617,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData());
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = QV4::Value::Integer_Type_Internal;
+ callData->tag = quint32(Value::ValueTypeInternal::Integer);
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
STOREVALUE(instr.result, Runtime::method_callQmlScopeObjectProperty(engine, instr.index, callData));
@@ -624,7 +627,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData());
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = QV4::Value::Integer_Type_Internal;
+ callData->tag = quint32(Value::ValueTypeInternal::Integer);
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
STOREVALUE(instr.result, Runtime::method_callQmlContextObjectProperty(engine, instr.index, callData));
@@ -633,7 +636,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_BEGIN_INSTR(CallElement)
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = QV4::Value::Integer_Type_Internal;
+ callData->tag = quint32(Value::ValueTypeInternal::Integer);
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
STOREVALUE(instr.result, Runtime::method_callElement(engine, VALUE(instr.index), callData));
@@ -642,7 +645,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_BEGIN_INSTR(CallActivationProperty)
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = QV4::Value::Integer_Type_Internal;
+ callData->tag = quint32(Value::ValueTypeInternal::Integer);
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
STOREVALUE(instr.result, Runtime::method_callActivationProperty(engine, instr.name, callData));
@@ -651,7 +654,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_BEGIN_INSTR(CallGlobalLookup)
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = QV4::Value::Integer_Type_Internal;
+ callData->tag = quint32(Value::ValueTypeInternal::Integer);
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
STOREVALUE(instr.result, Runtime::method_callGlobalLookup(engine, instr.index, callData));
@@ -757,7 +760,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_BEGIN_INSTR(CreateValue)
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = QV4::Value::Integer_Type_Internal;
+ callData->tag = quint32(Value::ValueTypeInternal::Integer);
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
STOREVALUE(instr.result, Runtime::method_constructValue(engine, VALUE(instr.func), callData));
@@ -766,7 +769,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_BEGIN_INSTR(CreateProperty)
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = QV4::Value::Integer_Type_Internal;
+ callData->tag = quint32(Value::ValueTypeInternal::Integer);
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
STOREVALUE(instr.result, Runtime::method_constructProperty(engine, instr.name, callData));
@@ -775,7 +778,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_BEGIN_INSTR(ConstructPropertyLookup)
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = QV4::Value::Integer_Type_Internal;
+ callData->tag = quint32(Value::ValueTypeInternal::Integer);
callData->argc = instr.argc;
callData->thisObject = VALUE(instr.base);
STOREVALUE(instr.result, Runtime::method_constructPropertyLookup(engine, instr.index, callData));
@@ -784,7 +787,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_BEGIN_INSTR(CreateActivationProperty)
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = QV4::Value::Integer_Type_Internal;
+ callData->tag = quint32(Value::ValueTypeInternal::Integer);
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
STOREVALUE(instr.result, Runtime::method_constructActivationProperty(engine, instr.name, callData));
@@ -793,7 +796,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code
MOTH_BEGIN_INSTR(ConstructGlobalLookup)
Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
- callData->tag = QV4::Value::Integer_Type_Internal;
+ callData->tag = quint32(Value::ValueTypeInternal::Integer);
callData->argc = instr.argc;
callData->thisObject = QV4::Primitive::undefinedValue();
STOREVALUE(instr.result, Runtime::method_constructGlobalLookup(engine, instr.index, callData));
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h
index 1347a9bd6e..a38a938588 100644
--- a/src/qml/memory/qv4heap_p.h
+++ b/src/qml/memory/qv4heap_p.h
@@ -83,7 +83,7 @@ struct VTable
uint type : 8;
const char *className;
void (*destroy)(Heap::Base *);
- void (*markObjects)(Heap::Base *, ExecutionEngine *e);
+ void (*markObjects)(Heap::Base *, MarkStack *markStack);
bool (*isEqualTo)(Managed *m, Managed *other);
};
@@ -97,7 +97,7 @@ struct Q_QML_EXPORT Base {
const VTable *vt;
inline ReturnedValue asReturnedValue() const;
- inline void mark(QV4::ExecutionEngine *engine);
+ inline void mark(QV4::MarkStack *markStack);
void setVtable(const VTable *v) { vt = v; }
const VTable *vtable() const { return vt; }
@@ -127,6 +127,8 @@ struct Q_QML_EXPORT Base {
return Chunk::testBit(c->objectBitmap, h - c->realBase());
}
+ inline void markChildren(MarkStack *markStack);
+
void *operator new(size_t, Managed *m) { return m; }
void *operator new(size_t, Heap::Base *m) { return m; }
void operator delete(void *, Heap::Base *) {}
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index c025dd09a4..c4bd1a733f 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -165,6 +165,13 @@ struct MemorySegment {
size_t pageSize = WTF::pageSize();
size = (size + pageSize - 1) & ~(pageSize - 1);
+#if !defined(Q_OS_LINUX) && !defined(Q_OS_WIN)
+ // Linux and Windows zero out pages that have been decommitted and get committed again.
+ // unfortunately that's not true on other OSes (e.g. BSD based ones), so zero out the
+ // memory before decommit, so that we can be sure that all chunks we allocate will be
+ // zero initialized.
+ memset(chunk, 0, size);
+#endif
pageReservation.decommit(chunk, size);
}
@@ -260,7 +267,76 @@ void ChunkAllocator::free(Chunk *chunk, size_t size)
}
-void Chunk::sweep()
+void Heap::Base::markChildren(MarkStack *markStack)
+{
+ if (vtable()->markObjects)
+ vtable()->markObjects(this, markStack);
+ if (quint64 m = vtable()->markTable) {
+// qDebug() << "using mark table:" << hex << m << "for" << h;
+ void **mem = reinterpret_cast<void **>(this);
+ while (m) {
+ MarkFlags mark = static_cast<MarkFlags>(m & 3);
+ switch (mark) {
+ case Mark_NoMark:
+ break;
+ case Mark_Value:
+// qDebug() << "marking value at " << mem;
+ reinterpret_cast<Value *>(mem)->mark(markStack);
+ break;
+ case Mark_Pointer: {
+// qDebug() << "marking pointer at " << mem;
+ Heap::Base *p = *reinterpret_cast<Heap::Base **>(mem);
+ if (p)
+ p->mark(markStack);
+ break;
+ }
+ case Mark_ValueArray: {
+ Q_ASSERT(m == Mark_ValueArray);
+// qDebug() << "marking Value Array at offset" << hex << (mem - reinterpret_cast<void **>(h));
+ ValueArray<0> *a = reinterpret_cast<ValueArray<0> *>(mem);
+ Value *v = a->values;
+ const Value *end = v + a->alloc;
+ if (a->alloc > 32*1024) {
+ // drain from time to time to avoid overflows in the js stack
+ Heap::Base **currentBase = markStack->top;
+ while (v < end) {
+ v->mark(markStack);
+ ++v;
+ if (markStack->top >= currentBase + 32*1024) {
+ Heap::Base **oldBase = markStack->base;
+ markStack->base = currentBase;
+ markStack->drain();
+ markStack->base = oldBase;
+ }
+ }
+ } else {
+ while (v < end) {
+ v->mark(markStack);
+ ++v;
+ }
+ }
+ break;
+ }
+ }
+
+ m >>= 2;
+ ++mem;
+ }
+ }
+}
+
+// Stores a classname -> freed count mapping.
+typedef QHash<const char*, int> MMStatsHash;
+Q_GLOBAL_STATIC(MMStatsHash, freedObjectStatsGlobal)
+
+// This indirection avoids sticking QHash code in each of the call sites, which
+// shaves off some instructions in the case that it's unused.
+static void increaseFreedCountForClass(const char *className)
+{
+ (*freedObjectStatsGlobal())[className]++;
+}
+
+void Chunk::sweep(ClassDestroyStatsCallback classCountPtr)
{
// DEBUG << "sweeping chunk" << this << (*freeList);
HeapItem *o = realBase();
@@ -290,8 +366,11 @@ void Chunk::sweep()
HeapItem *itemToFree = o + index;
Heap::Base *b = *itemToFree;
- if (b->vtable()->destroy) {
- b->vtable()->destroy(b);
+ const VTable *v = b->vtable();
+ if (Q_UNLIKELY(classCountPtr))
+ classCountPtr(v->className);
+ if (v->destroy) {
+ v->destroy(b);
b->_checkIsDestroyed();
}
}
@@ -351,7 +430,7 @@ void Chunk::resetBlackBits()
static uint nGrayItems = 0;
#endif
-void Chunk::collectGrayItems(ExecutionEngine *engine)
+void Chunk::collectGrayItems(MarkStack *markStack)
{
// DEBUG << "sweeping chunk" << this << (*freeList);
HeapItem *o = realBase();
@@ -372,7 +451,7 @@ void Chunk::collectGrayItems(ExecutionEngine *engine)
HeapItem *itemToFree = o + index;
Heap::Base *b = *itemToFree;
Q_ASSERT(b->inUse());
- engine->pushForGC(b);
+ markStack->push(b);
#ifdef MM_STATS
++nGrayItems;
// qDebug() << "adding gray item" << b << "to mark stack";
@@ -590,7 +669,7 @@ done:
return m;
}
-void BlockAllocator::sweep()
+void BlockAllocator::sweep(ClassDestroyStatsCallback classCountPtr)
{
nextFree = 0;
nFree = 0;
@@ -599,7 +678,7 @@ void BlockAllocator::sweep()
// qDebug() << "BlockAlloc: sweep";
usedSlotsAfterLastSweep = 0;
for (auto c : chunks) {
- c->sweep();
+ c->sweep(classCountPtr);
c->sortIntoBins(freeBins, NumBins);
// qDebug() << "used slots in chunk" << c << ":" << c->nUsedSlots();
usedSlotsAfterLastSweep += c->nUsedSlots();
@@ -620,10 +699,10 @@ void BlockAllocator::resetBlackBits()
c->resetBlackBits();
}
-void BlockAllocator::collectGrayItems(ExecutionEngine *engine)
+void BlockAllocator::collectGrayItems(MarkStack *markStack)
{
for (auto c : chunks)
- c->collectGrayItems(engine);
+ c->collectGrayItems(markStack);
}
@@ -665,22 +744,27 @@ HeapItem *HugeItemAllocator::allocate(size_t size) {
return c->first();
}
-static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocator::HugeChunk &c)
+static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocator::HugeChunk &c, ClassDestroyStatsCallback classCountPtr)
{
HeapItem *itemToFree = c.chunk->first();
Heap::Base *b = *itemToFree;
- if (b->vtable()->destroy) {
- b->vtable()->destroy(b);
+ const VTable *v = b->vtable();
+ if (Q_UNLIKELY(classCountPtr))
+ classCountPtr(v->className);
+
+ if (v->destroy) {
+ v->destroy(b);
b->_checkIsDestroyed();
}
chunkAllocator->free(c.chunk, c.size);
}
-void HugeItemAllocator::sweep() {
- auto isBlack = [this] (const HugeChunk &c) {
+void HugeItemAllocator::sweep(ClassDestroyStatsCallback classCountPtr)
+{
+ auto isBlack = [this, classCountPtr] (const HugeChunk &c) {
bool b = c.chunk->first()->isBlack();
if (!b)
- freeHugeChunk(chunkAllocator, c);
+ freeHugeChunk(chunkAllocator, c, classCountPtr);
return !b;
};
@@ -694,7 +778,7 @@ void HugeItemAllocator::resetBlackBits()
Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase());
}
-void HugeItemAllocator::collectGrayItems(ExecutionEngine *engine)
+void HugeItemAllocator::collectGrayItems(MarkStack *markStack)
{
for (auto c : chunks)
// Correct for a Steele type barrier
@@ -702,14 +786,14 @@ void HugeItemAllocator::collectGrayItems(ExecutionEngine *engine)
Chunk::testBit(c.chunk->grayBitmap, c.chunk->first() - c.chunk->realBase())) {
HeapItem *i = c.chunk->first();
Heap::Base *b = *i;
- b->mark(engine);
+ b->mark(markStack);
}
}
void HugeItemAllocator::freeAll()
{
for (auto &c : chunks) {
- freeHugeChunk(chunkAllocator, c);
+ freeHugeChunk(chunkAllocator, c, nullptr);
}
}
@@ -852,77 +936,34 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nM
static uint markStackSize = 0;
-void MemoryManager::drainMarkStack(Value *markBase)
+MarkStack::MarkStack(ExecutionEngine *engine)
+ : engine(engine)
+{
+ base = (Heap::Base **)engine->gcStack->base();
+ top = base;
+ limit = base + ExecutionEngine::GCStackLimit/sizeof(Heap::Base)*3/4;
+}
+
+void MarkStack::drain()
{
- while (engine->jsStackTop > markBase) {
- Heap::Base *h = engine->popForGC();
+ while (top > base) {
+ Heap::Base *h = pop();
++markStackSize;
Q_ASSERT(h); // at this point we should only have Heap::Base objects in this area on the stack. If not, weird things might happen.
- if (h->vtable()->markObjects)
- h->vtable()->markObjects(h, engine);
- if (quint64 m = h->vtable()->markTable) {
-// qDebug() << "using mark table:" << hex << m << "for" << h;
- void **mem = reinterpret_cast<void **>(h);
- while (m) {
- MarkFlags mark = static_cast<MarkFlags>(m & 3);
- switch (mark) {
- case Mark_NoMark:
- break;
- case Mark_Value:
-// qDebug() << "marking value at " << mem;
- reinterpret_cast<Value *>(mem)->mark(engine);
- break;
- case Mark_Pointer: {
-// qDebug() << "marking pointer at " << mem;
- Heap::Base *p = *reinterpret_cast<Heap::Base **>(mem);
- if (p)
- p->mark(engine);
- break;
- }
- case Mark_ValueArray: {
- Q_ASSERT(m == Mark_ValueArray);
-// qDebug() << "marking Value Array at offset" << hex << (mem - reinterpret_cast<void **>(h));
- ValueArray<0> *a = reinterpret_cast<ValueArray<0> *>(mem);
- Value *v = a->values;
- const Value *end = v + a->alloc;
- while (v < end) {
- v->mark(engine);
- ++v;
- }
- break;
- }
- }
-
- m >>= 2;
- ++mem;
- }
- }
+ h->markChildren(this);
}
}
-void MemoryManager::mark()
+void MemoryManager::collectRoots(MarkStack *markStack)
{
- Value *markBase = engine->jsStackTop;
-
- markStackSize = 0;
-
- if (nextGCIsIncremental) {
- // need to collect all gray items and push them onto the mark stack
- blockAllocator.collectGrayItems(engine);
- hugeItemAllocator.collectGrayItems(engine);
- }
-
-// qDebug() << ">>>> Mark phase:";
-// qDebug() << " mark stack after gray items" << (engine->jsStackTop - markBase);
-
- engine->markObjects(nextGCIsIncremental);
+ engine->markObjects(markStack);
// qDebug() << " mark stack after engine->mark" << (engine->jsStackTop - markBase);
- collectFromJSStack();
+ collectFromJSStack(markStack);
// qDebug() << " mark stack after js stack collect" << (engine->jsStackTop - markBase);
- m_persistentValues->mark(engine);
+ m_persistentValues->mark(markStack);
// qDebug() << " mark stack after persistants" << (engine->jsStackTop - markBase);
@@ -951,23 +992,25 @@ void MemoryManager::mark()
}
if (keepAlive)
- qobjectWrapper->mark(engine);
+ qobjectWrapper->mark(markStack);
- if (engine->jsStackTop >= engine->jsStackLimit)
- drainMarkStack(markBase);
+ if (markStack->top >= markStack->limit)
+ markStack->drain();
}
-
- drainMarkStack(markBase);
}
-void MemoryManager::sweep(bool lastSweep)
+void MemoryManager::mark()
{
- if (lastSweep && nextGCIsIncremental) {
- // ensure we properly clean up on destruction even if the GC is in incremental mode
- blockAllocator.resetBlackBits();
- hugeItemAllocator.resetBlackBits();
- }
+ markStackSize = 0;
+
+ MarkStack markStack(engine);
+ collectRoots(&markStack);
+
+ markStack.drain();
+}
+void MemoryManager::sweep(bool lastSweep, ClassDestroyStatsCallback classCountPtr)
+{
for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) {
Managed *m = (*it).managed();
if (!m || m->markBit())
@@ -1013,8 +1056,8 @@ void MemoryManager::sweep(bool lastSweep)
}
}
- blockAllocator.sweep();
- hugeItemAllocator.sweep();
+ blockAllocator.sweep(classCountPtr);
+ hugeItemAllocator.sweep(classCountPtr);
}
bool MemoryManager::shouldRunGC() const
@@ -1046,20 +1089,13 @@ size_t dumpBins(BlockAllocator *b, bool printOutput = true)
return totalSlotMem*Chunk::SlotSize;
}
-void MemoryManager::runGC(bool forceFullCollection)
+void MemoryManager::runGC()
{
if (gcBlocked) {
// qDebug() << "Not running GC.";
return;
}
- if (forceFullCollection) {
- // do a full GC
- blockAllocator.resetBlackBits();
- hugeItemAllocator.resetBlackBits();
- nextGCIsIncremental = false;
- }
-
QScopedValueRollback<bool> gcBlocker(gcBlocked, true);
// qDebug() << "runGC";
@@ -1081,7 +1117,6 @@ void MemoryManager::runGC(bool forceFullCollection)
qDebug() << " Allocations since last GC" << allocationCount;
allocationCount = 0;
#endif
- qDebug() << "Incremental:" << nextGCIsIncremental;
qDebug() << "Allocated" << totalMem << "bytes in" << blockAllocator.chunks.size() << "chunks";
qDebug() << "Fragmented memory before GC" << (totalMem - usedBefore);
dumpBins(&blockAllocator);
@@ -1095,7 +1130,7 @@ void MemoryManager::runGC(bool forceFullCollection)
mark();
qint64 markTime = t.nsecsElapsed()/1000;
t.restart();
- sweep();
+ sweep(false, increaseFreedCountForClass);
const size_t usedAfter = getUsedMem();
const size_t largeItemsAfter = getLargeItemsMem();
qint64 sweepTime = t.nsecsElapsed()/1000;
@@ -1107,13 +1142,23 @@ void MemoryManager::runGC(bool forceFullCollection)
qDebug() << " unmanaged heap limit:" << unmanagedHeapSizeGCLimit;
}
size_t memInBins = dumpBins(&blockAllocator);
-#ifdef MM_STATS
- if (nextGCIsIncremental)
- qDebug() << " number of gray items:" << nGrayItems;
-#endif
qDebug() << "Marked object in" << markTime << "us.";
qDebug() << " " << markStackSize << "objects marked";
qDebug() << "Sweeped object in" << sweepTime << "us.";
+
+ // sort our object types by number of freed instances
+ MMStatsHash freedObjectStats;
+ std::swap(freedObjectStats, *freedObjectStatsGlobal());
+ typedef std::pair<const char*, int> ObjectStatInfo;
+ std::vector<ObjectStatInfo> freedObjectsSorted;
+ freedObjectsSorted.reserve(freedObjectStats.count());
+ for (auto it = freedObjectStats.constBegin(); it != freedObjectStats.constEnd(); ++it) {
+ freedObjectsSorted.push_back(std::make_pair(it.key(), it.value()));
+ }
+ std::sort(freedObjectsSorted.begin(), freedObjectsSorted.end(), [](const ObjectStatInfo &a, const ObjectStatInfo &b) {
+ return a.second > b.second && strcmp(a.first, b.first) < 0;
+ });
+
qDebug() << "Used memory before GC:" << usedBefore;
qDebug() << "Used memory after GC :" << usedAfter;
qDebug() << "Freed up bytes :" << (usedBefore - usedAfter);
@@ -1125,6 +1170,11 @@ void MemoryManager::runGC(bool forceFullCollection)
qDebug() << "Large item memory after GC:" << largeItemsAfter;
qDebug() << "Large item memory freed up:" << (largeItemsBefore - largeItemsAfter);
}
+
+ for (auto it = freedObjectsSorted.cbegin(); it != freedObjectsSorted.cend(); ++it) {
+ qDebug().noquote() << QString::fromLatin1("Freed JS type: %1 (%2 instances)").arg(QString::fromLatin1(it->first), QString::number(it->second));
+ }
+
qDebug() << "======== End GC ========";
}
@@ -1133,36 +1183,11 @@ void MemoryManager::runGC(bool forceFullCollection)
Q_ASSERT(blockAllocator.allocatedMem() == getUsedMem() + dumpBins(&blockAllocator, false));
}
- if (!nextGCIsIncremental)
- usedSlotsAfterLastFullSweep = blockAllocator.usedSlotsAfterLastSweep;
+ usedSlotsAfterLastFullSweep = blockAllocator.usedSlotsAfterLastSweep;
-#if WRITEBARRIER(steele)
- static int count = 0;
- ++count;
- if (aggressiveGC) {
- nextGCIsIncremental = (count % 256);
- } else {
- size_t total = blockAllocator.totalSlots();
- size_t usedSlots = blockAllocator.usedSlotsAfterLastSweep;
- if (!nextGCIsIncremental) {
- // always try an incremental GC after a full one, unless there is anyway lots of memory pressure
- nextGCIsIncremental = usedSlots * 4 < total * 3;
- count = 0;
- } else {
- if (count > 16)
- nextGCIsIncremental = false;
- else
- nextGCIsIncremental = usedSlots * 4 < total * 3; // less than 75% full
- }
- }
-#else
- nextGCIsIncremental = false;
-#endif
- if (!nextGCIsIncremental) {
- // do a full GC
- blockAllocator.resetBlackBits();
- hugeItemAllocator.resetBlackBits();
- }
+ // reset all black bits
+ blockAllocator.resetBlackBits();
+ hugeItemAllocator.resetBlackBits();
}
size_t MemoryManager::getUsedMem() const
@@ -1223,7 +1248,7 @@ void MemoryManager::willAllocate(std::size_t size)
#endif // DETAILED_MM_STATS
-void MemoryManager::collectFromJSStack() const
+void MemoryManager::collectFromJSStack(MarkStack *markStack) const
{
Value *v = engine->jsStackBase;
Value *top = engine->jsStackTop;
@@ -1231,7 +1256,7 @@ void MemoryManager::collectFromJSStack() const
Managed *m = v->managed();
if (m && m->inUse())
// Skip pointers to already freed objects, they are bogus as well
- m->mark(engine);
+ m->mark(markStack);
++v;
}
}
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index 7f02a4f929..07e428b9bc 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -153,10 +153,10 @@ struct BlockAllocator {
return used;
}
- void sweep();
+ void sweep(ClassDestroyStatsCallback classCountPtr);
void freeAll();
void resetBlackBits();
- void collectGrayItems(ExecutionEngine *engine);
+ void collectGrayItems(MarkStack *markStack);
// bump allocations
HeapItem *nextFree = 0;
@@ -176,10 +176,10 @@ struct HugeItemAllocator {
{}
HeapItem *allocate(size_t size);
- void sweep();
+ void sweep(ClassDestroyStatsCallback classCountPtr);
void freeAll();
void resetBlackBits();
- void collectGrayItems(ExecutionEngine *engine);
+ void collectGrayItems(MarkStack *markStack);
size_t usedMem() const {
size_t used = 0;
@@ -422,7 +422,7 @@ public:
return t->d();
}
- void runGC(bool forceFullCollection = false);
+ void runGC();
void dumpStats() const;
@@ -432,8 +432,6 @@ public:
// called when a JS object grows itself. Specifically: Heap::String::append
void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; }
- void drainMarkStack(Value *markBase);
-
protected:
/// expects size to be aligned
@@ -446,10 +444,11 @@ protected:
#endif // DETAILED_MM_STATS
private:
- void collectFromJSStack() const;
+ void collectFromJSStack(MarkStack *markStack) const;
void mark();
- void sweep(bool lastSweep = false);
+ void sweep(bool lastSweep = false, ClassDestroyStatsCallback classCountPtr = nullptr);
bool shouldRunGC() const;
+ void collectRoots(MarkStack *markStack);
public:
QV4::ExecutionEngine *engine;
@@ -468,7 +467,6 @@ public:
bool gcBlocked = false;
bool aggressiveGC = false;
bool gcStats = false;
- bool nextGCIsIncremental = false;
};
}
diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h
index 1fc7b6a527..bf29b44a2c 100644
--- a/src/qml/memory/qv4mmdefs_p.h
+++ b/src/qml/memory/qv4mmdefs_p.h
@@ -59,6 +59,10 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+struct MarkStack;
+
+typedef void(*ClassDestroyStatsCallback)(const char *);
+
/*
* Chunks are the basic structure containing GC managed objects.
*
@@ -182,10 +186,10 @@ struct Chunk {
return usedSlots;
}
- void sweep();
+ void sweep(ClassDestroyStatsCallback classCountPtr);
void freeAll();
void resetBlackBits();
- void collectGrayItems(ExecutionEngine *engine);
+ void collectGrayItems(QV4::MarkStack *markStack);
void sortIntoBins(HeapItem **bins, uint nBins);
};
@@ -265,6 +269,24 @@ Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize);
Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits);
Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits);
+struct MarkStack {\
+ MarkStack(ExecutionEngine *engine);
+ Heap::Base **top = 0;
+ Heap::Base **base = 0;
+ Heap::Base **limit = 0;
+ ExecutionEngine *engine;
+ void push(Heap::Base *m) {
+ *top = m;
+ ++top;
+ }
+ Heap::Base *pop() {
+ --top;
+ return *top;
+ }
+ void drain();
+
+};
+
// Base class for the execution engine
#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h
index a2f85822ca..e36ea0749a 100644
--- a/src/qml/memory/qv4writebarrier_p.h
+++ b/src/qml/memory/qv4writebarrier_p.h
@@ -55,7 +55,6 @@
QT_BEGIN_NAMESPACE
-#define WRITEBARRIER_steele -1
#define WRITEBARRIER_none 1
#define WRITEBARRIER(x) (1/WRITEBARRIER_##x == 1)
@@ -78,42 +77,7 @@ enum NewValueType {
// ### this needs to be filled with a real memory fence once marking is concurrent
Q_ALWAYS_INLINE void fence() {}
-#if WRITEBARRIER(steele)
-
-template <NewValueType type>
-static Q_CONSTEXPR inline bool isRequired() {
- return type != Primitive;
-}
-
-inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Value value)
-{
- Q_UNUSED(engine);
- *slot = value;
- if (isRequired<Unknown>()) {
- fence();
- base->setGrayBit();
- }
-}
-
-inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Heap::Base *value)
-{
- Q_UNUSED(engine);
- *slot = value;
- if (isRequired<Object>()) {
- fence();
- base->setGrayBit();
- }
-}
-
-inline void write(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value)
-{
- Q_UNUSED(engine);
- *slot = value;
- fence();
- base->setGrayBit();
-}
-
-#elif WRITEBARRIER(none)
+#if WRITEBARRIER(none)
template <NewValueType type>
static Q_CONSTEXPR inline bool isRequired() {
diff --git a/src/qml/parser/qqmljsglobal_p.h b/src/qml/parser/qqmljsglobal_p.h
index 933c8f5202..0e195994b4 100644
--- a/src/qml/parser/qqmljsglobal_p.h
+++ b/src/qml/parser/qqmljsglobal_p.h
@@ -67,13 +67,17 @@
#else // !QT_CREATOR
# define QT_QML_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
# define QT_QML_END_NAMESPACE QT_END_NAMESPACE
-# if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
- // QmlDevTools is a static library
-# define QML_PARSER_EXPORT
-# elif defined(QT_BUILD_QML_LIB)
-# define QML_PARSER_EXPORT Q_DECL_EXPORT
+# ifndef QT_STATIC
+# if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
+ // QmlDevTools is a static library
+# define QML_PARSER_EXPORT
+# elif defined(QT_BUILD_QML_LIB)
+# define QML_PARSER_EXPORT Q_DECL_EXPORT
+# else
+# define QML_PARSER_EXPORT Q_DECL_IMPORT
+# endif
# else
-# define QML_PARSER_EXPORT Q_DECL_IMPORT
+# define QML_PARSER_EXPORT
# endif
#endif // QT_CREATOR
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index 8f9e4b7f83..be3956bb61 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -48,7 +48,9 @@ include(jit/jit.pri)
include(jsruntime/jsruntime.pri)
include(qml/qml.pri)
include(debugger/debugger.pri)
-include(animations/animations.pri)
+qtConfig(animation) {
+ include(animations/animations.pri)
+}
include(types/types.pri)
MODULE_PLUGIN_TYPES = \
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index e271598c2d..2083326cd5 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -201,7 +201,9 @@ public:
static QQmlData *get(const QObject *object, bool create = false) {
QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
- if (priv->wasDeleted) {
+ // If QObjectData::isDeletingChildren is set then access to QObjectPrivate::declarativeData has
+ // to be avoided because QObjectPrivate::currentChildBeingDeleted is in use.
+ if (priv->isDeletingChildren || priv->wasDeleted) {
Q_ASSERT(!create);
return 0;
} else if (priv->declarativeData) {
@@ -269,8 +271,8 @@ bool QQmlData::wasDeleted(QObject *object)
if (!priv || priv->wasDeleted)
return true;
- return priv->declarativeData &&
- static_cast<QQmlData *>(priv->declarativeData)->isQueuedForDeletion;
+ QQmlData *ddata = QQmlData::get(object);
+ return ddata && ddata->isQueuedForDeletion;
}
QQmlNotifierEndpoint *QQmlData::notify(int index)
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index d4d21583ba..9ff76d7b24 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -82,7 +82,9 @@
#include <private/qqmllocale_p.h>
#include <private/qqmlbind_p.h>
#include <private/qqmlconnections_p.h>
+#if QT_CONFIG(animation)
#include <private/qqmltimer_p.h>
+#endif
#include <private/qqmllistmodel_p.h>
#include <private/qqmlplatform_p.h>
#include <private/qquickpackage_p.h>
@@ -218,7 +220,9 @@ void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int
qmlRegisterType<QQmlBind,8>(uri, versionMajor, (versionMinor < 8 ? 8 : versionMinor), "Binding"); //Only available in >=2.8
qmlRegisterType<QQmlConnections,1>(uri, versionMajor, (versionMinor < 3 ? 3 : versionMinor), "Connections"); //Only available in >=2.3
qmlRegisterType<QQmlConnections>(uri, versionMajor, versionMinor,"Connections");
+#if QT_CONFIG(animation)
qmlRegisterType<QQmlTimer>(uri, versionMajor, versionMinor,"Timer");
+#endif
qmlRegisterType<QQmlInstantiator>(uri, versionMajor, (versionMinor < 1 ? 1 : versionMinor), "Instantiator"); //Only available in >=2.1
qmlRegisterCustomType<QQmlConnections>(uri, versionMajor, versionMinor,"Connections", new QQmlConnectionsParser);
qmlRegisterType<QQmlInstanceModel>();
@@ -709,9 +713,7 @@ QQmlEnginePrivate::~QQmlEnginePrivate()
void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
{
- QObjectPrivate *p = QObjectPrivate::get(o);
- if (p->declarativeData) {
- QQmlData *d = static_cast<QQmlData*>(p->declarativeData);
+ if (QQmlData *d = QQmlData::get(o)) {
if (d->ownContext && d->context) {
d->context->destroy();
d->context = 0;
@@ -881,13 +883,10 @@ void QQmlData::markAsDeleted(QObject *o)
void QQmlData::setQueuedForDeletion(QObject *object)
{
if (object) {
- if (QObjectPrivate *priv = QObjectPrivate::get(object)) {
- if (!priv->wasDeleted && priv->declarativeData) {
- QQmlData *ddata = QQmlData::get(object, false);
- if (ddata->ownContext && ddata->context)
- ddata->context->emitDestruction();
- ddata->isQueuedForDeletion = true;
- }
+ if (QQmlData *ddata = QQmlData::get(object)) {
+ if (ddata->ownContext && ddata->context)
+ ddata->context->emitDestruction();
+ ddata->isQueuedForDeletion = true;
}
}
}
@@ -1336,17 +1335,11 @@ QQmlContext *QQmlEngine::contextForObject(const QObject *object)
if(!object)
return 0;
- QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
-
- QQmlData *data =
- static_cast<QQmlData *>(priv->declarativeData);
-
- if (!data)
- return 0;
- else if (data->outerContext)
+ QQmlData *data = QQmlData::get(object);
+ if (data && data->outerContext)
return data->outerContext->asQQmlContext();
- else
- return 0;
+
+ return 0;
}
/*!
@@ -1881,6 +1874,7 @@ void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex)
QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv)
{
Q_ASSERT(priv);
+ Q_ASSERT(!priv->isDeletingChildren);
priv->declarativeData = new QQmlData;
return static_cast<QQmlData *>(priv->declarativeData);
}
diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp
index 7a1e02eec6..64f008cd32 100644
--- a/src/qml/qml/qqmlerror.cpp
+++ b/src/qml/qml/qqmlerror.cpp
@@ -44,6 +44,7 @@
#include <QtCore/qfile.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qvector.h>
+#include <QtCore/qpointer.h>
#include <private/qv4errorobject_p.h>
@@ -86,7 +87,7 @@ public:
quint16 line;
quint16 column;
QtMsgType messageType;
- QObject *object;
+ QPointer<QObject> object;
};
QQmlErrorPrivate::QQmlErrorPrivate()
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 85fbd86dc4..2cbcfbbfb6 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -1075,7 +1075,9 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
{
QQmlData *ddata = new (ddataMemory) QQmlData;
ddata->ownMemory = false;
- QObjectPrivate::get(instance)->declarativeData = ddata;
+ QObjectPrivate* p = QObjectPrivate::get(instance);
+ Q_ASSERT(!p->isDeletingChildren);
+ p->declarativeData = ddata;
}
const int parserStatusCast = type->parserStatusCast();
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index ca522c29af..9b5f7b0a06 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1627,7 +1627,7 @@ QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const Q
*/
static inline void flush_vme_signal(const QObject *object, int index, bool indexInSignalRange)
{
- QQmlData *data = static_cast<QQmlData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData);
+ QQmlData *data = QQmlData::get(object);
if (data && data->propertyCache) {
QQmlPropertyData *property = indexInSignalRange ? data->propertyCache->signal(index)
: data->propertyCache->method(index);
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index f464a099e0..9f86d1cae9 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -1170,16 +1170,16 @@ void QQmlVMEMetaObject::ensureQObjectWrapper()
QV4::QObjectWrapper::wrap(v4, object);
}
-void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e)
+void QQmlVMEMetaObject::mark(QV4::MarkStack *markStack)
{
QV4::ExecutionEngine *v4 = cache ? cache->engine : 0;
- if (v4 != e)
+ if (v4 != markStack->engine)
return;
- propertyAndMethodStorage.markOnce(e);
+ propertyAndMethodStorage.markOnce(markStack);
if (QQmlVMEMetaObject *parent = parentVMEMetaObject())
- parent->mark(e);
+ parent->mark(markStack);
}
bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index bb6fede7c8..031a9a9ddd 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -203,7 +203,7 @@ public:
void ensureQObjectWrapper();
- void mark(QV4::ExecutionEngine *e);
+ void mark(QV4::MarkStack *markStack);
void connectAlias(int aliasId);
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 68a64a28f0..8cc0b32168 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -2019,7 +2019,7 @@ void GlobalExtensions::method_qsTrIdNoOp(const BuiltinFunction *, Scope &scope,
void GlobalExtensions::method_gc(const BuiltinFunction *, Scope &scope, CallData *)
{
- scope.engine->memoryManager->runGC(/* forceFullCollection = */ true);
+ scope.engine->memoryManager->runGC();
scope.result = QV4::Encode::undefined();
}
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 870aeaa6e2..66bc772279 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -235,14 +235,13 @@ void QQmlConnectionsParser::verifyBindings(const QV4::CompiledData::Unit *qmlUni
{
for (int ii = 0; ii < props.count(); ++ii) {
const QV4::CompiledData::Binding *binding = props.at(ii);
- QString propName = qmlUnit->stringAt(binding->propertyNameIndex);
+ const QString &propName = qmlUnit->stringAt(binding->propertyNameIndex);
- if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) {
+ if (!propName.startsWith(QLatin1String("on")) || (propName.length() < 3 || !propName.at(2).isUpper())) {
error(props.at(ii), QQmlConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
return;
}
-
if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
const QV4::CompiledData::Object *target = qmlUnit->objectAt(binding->value.objectIndex);
if (!qmlUnit->stringAt(target->inheritedTypeNameIndex).isEmpty())
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 34bc266cb5..f26e5f6cdb 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -1964,9 +1964,8 @@ void QQmlDelegateModelItem::destroyObject()
Q_ASSERT(object);
Q_ASSERT(contextData);
- QObjectPrivate *p = QObjectPrivate::get(object);
- Q_ASSERT(p->declarativeData);
- QQmlData *data = static_cast<QQmlData*>(p->declarativeData);
+ QQmlData *data = QQmlData::get(object);
+ Q_ASSERT(data);
if (data->ownContext && data->context)
data->context->clearContext();
object->deleteLater();
@@ -1983,10 +1982,8 @@ void QQmlDelegateModelItem::destroyObject()
QQmlDelegateModelItem *QQmlDelegateModelItem::dataForObject(QObject *object)
{
- QObjectPrivate *p = QObjectPrivate::get(object);
- QQmlContextData *context = p->declarativeData
- ? static_cast<QQmlData *>(p->declarativeData)->context
- : 0;
+ QQmlData *d = QQmlData::get(object);
+ QQmlContextData *context = d ? d->context : 0;
for (context = context ? context->parent : 0; context; context = context->parent) {
if (QQmlDelegateModelItem *cacheItem = qobject_cast<QQmlDelegateModelItem *>(
context->contextObject)) {
diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri
index d2e5020738..e85ab5982b 100644
--- a/src/qml/types/types.pri
+++ b/src/qml/types/types.pri
@@ -7,7 +7,6 @@ SOURCES += \
$$PWD/qqmlmodelsmodule.cpp \
$$PWD/qqmlmodelindexvaluetype.cpp \
$$PWD/qqmlobjectmodel.cpp \
- $$PWD/qqmltimer.cpp \
$$PWD/qquickpackage.cpp \
$$PWD/qquickworkerscript.cpp \
$$PWD/qqmlinstantiator.cpp
@@ -23,8 +22,15 @@ HEADERS += \
$$PWD/qqmlmodelsmodule_p.h \
$$PWD/qqmlmodelindexvaluetype_p.h \
$$PWD/qqmlobjectmodel_p.h \
- $$PWD/qqmltimer_p.h \
$$PWD/qquickpackage_p.h \
$$PWD/qquickworkerscript_p.h \
$$PWD/qqmlinstantiator_p.h \
$$PWD/qqmlinstantiator_p_p.h
+
+qtConfig(animation) {
+ SOURCES += \
+ $$PWD/qqmltimer.cpp
+
+ HEADERS += \
+ $$PWD/qqmltimer_p.h
+}
diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
index fbde5d354d..2d6bb02af4 100644
--- a/src/quick/accessible/qaccessiblequickitem.cpp
+++ b/src/quick/accessible/qaccessiblequickitem.cpp
@@ -142,9 +142,6 @@ QAccessibleInterface *QAccessibleQuickItem::child(int index) const
return 0;
QQuickItem *child = children.at(index);
- if (!child) // FIXME can this happen?
- return 0;
-
return QAccessible::queryAccessibleInterface(child);
}
diff --git a/src/quick/designer/qquickdesignersupport.cpp b/src/quick/designer/qquickdesignersupport.cpp
index 749ece8221..88971e3172 100644
--- a/src/quick/designer/qquickdesignersupport.cpp
+++ b/src/quick/designer/qquickdesignersupport.cpp
@@ -90,10 +90,11 @@ void QQuickDesignerSupport::refFromEffectItem(QQuickItem *referencedItem, bool h
QSGRenderContext *rc = QQuickWindowPrivate::get(referencedItem->window())->context;
QSGLayer *texture = rc->sceneGraphContext()->createLayer(rc);
+ QSizeF itemSize = referencedItem->size();
texture->setLive(true);
texture->setItem(QQuickItemPrivate::get(referencedItem)->rootNode());
- texture->setRect(referencedItem->boundingRect());
- texture->setSize(referencedItem->boundingRect().size().toSize());
+ texture->setRect(QRectF(QPointF(0, 0), itemSize));
+ texture->setSize(itemSize.toSize());
texture->setRecursive(true);
#if QT_CONFIG(opengl)
#ifndef QT_OPENGL_ES
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index da9379e7af..bda3250c16 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -889,7 +889,7 @@ void QQuickCanvasItem::getContext(QQmlV4Function *args)
}
/*!
- \qmlmethod long QtQuick::Canvas::requestAnimationFrame(callback)
+ \qmlmethod int QtQuick::Canvas::requestAnimationFrame(callback)
This function schedules callback to be invoked before composing the Qt Quick
scene.
@@ -919,7 +919,7 @@ void QQuickCanvasItem::requestAnimationFrame(QQmlV4Function *args)
}
/*!
- \qmlmethod QtQuick::Canvas::cancelRequestAnimationFrame(long handle)
+ \qmlmethod QtQuick::Canvas::cancelRequestAnimationFrame(int handle)
This function will cancel the animation callback referenced by \a handle.
*/
@@ -1104,14 +1104,17 @@ bool QQuickCanvasItem::isImageLoaded(const QUrl& url) const
QImage QQuickCanvasItem::toImage(const QRectF& rect) const
{
Q_D(const QQuickCanvasItem);
- if (d->context) {
- if (rect.isEmpty())
- return d->context->toImage(canvasWindow());
- else
- return d->context->toImage(rect);
- }
- return QImage();
+ if (!d->context)
+ return QImage();
+
+ const QRectF &rectSource = rect.isEmpty() ? canvasWindow() : rect;
+ const qreal dpr = window() ? window()->effectiveDevicePixelRatio() : qreal(1);
+ const QRectF rectScaled(rectSource.topLeft() * dpr, rectSource.size() * dpr);
+
+ QImage image = d->context->toImage(rectScaled);
+ image.setDevicePixelRatio(dpr);
+ return image;
}
static const char* mimeToType(const QString &mime)
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index db9b1acbdf..1a6f530bfa 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -927,9 +927,9 @@ struct QQuickJSContext2DImageData : public QV4::Object
static void method_get_height(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
static void method_get_data(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
- static void markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *engine) {
- static_cast<QQuickJSContext2DImageData::Data *>(that)->pixelData.mark(engine);
- QV4::Object::markObjects(that, engine);
+ static void markObjects(QV4::Heap::Base *that, QV4::MarkStack *markStack) {
+ static_cast<QQuickJSContext2DImageData::Data *>(that)->pixelData.mark(markStack);
+ QV4::Object::markObjects(that, markStack);
}
};
@@ -960,7 +960,7 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE
*pixelData->d()->image = QImage(w, h, QImage::Format_ARGB32);
pixelData->d()->image->fill(0x00000000);
} else {
- Q_ASSERT(image.width() == qRound(w) && image.height() == qRound(h));
+ Q_ASSERT(image.width()== qRound(w * image.devicePixelRatio()) && image.height() == qRound(h * image.devicePixelRatio()));
*pixelData->d()->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
}
diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h
index 357f72b3e7..17e9d8c690 100644
--- a/src/quick/items/qquickdrag_p.h
+++ b/src/quick/items/qquickdrag_p.h
@@ -248,7 +248,7 @@ class QQuickDragAttached : public QObject
Q_PROPERTY(QObject *source READ source WRITE setSource NOTIFY sourceChanged RESET resetSource)
Q_PROPERTY(QObject *target READ target NOTIFY targetChanged)
Q_PROPERTY(QPointF hotSpot READ hotSpot WRITE setHotSpot NOTIFY hotSpotChanged)
- Q_PROPERTY(QUrl imageSource READ imageSource WRITE setImageSource NOTIFY imageSourceChanged REVISION 8)
+ Q_PROPERTY(QUrl imageSource READ imageSource WRITE setImageSource NOTIFY imageSourceChanged)
Q_PROPERTY(QStringList keys READ keys WRITE setKeys NOTIFY keysChanged)
Q_PROPERTY(QVariantMap mimeData READ mimeData WRITE setMimeData NOTIFY mimeDataChanged)
Q_PROPERTY(Qt::DropActions supportedActions READ supportedActions WRITE setSupportedActions NOTIFY supportedActionsChanged)
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index f1f82f9e0e..ac0505da82 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -846,9 +846,24 @@ QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool i
auto p = m_touchPoints.at(i);
if (p->isAccepted())
continue;
+ // include points where item is the grabber
bool isGrabber = p->grabber() == item;
+ // include newly pressed points inside the bounds
bool isPressInside = p->state() == QQuickEventPoint::Pressed && item->contains(item->mapFromScene(p->scenePos()));
- if (!(isGrabber || isPressInside || isFiltering))
+
+ // filtering: (childMouseEventFilter) include points that are grabbed by children of the target item
+ bool grabberIsChild = false;
+ auto parent = p->grabber();
+ while (isFiltering && parent) {
+ if (parent == item) {
+ grabberIsChild = true;
+ break;
+ }
+ parent = parent->parentItem();
+ }
+ bool filterRelevant = isFiltering && grabberIsChild;
+
+ if (!(isGrabber || isPressInside || filterRelevant))
continue;
const QTouchEvent::TouchPoint *tp = touchPointById(p->pointId());
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 27d7072f03..1c732f9157 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -254,6 +254,7 @@ QQuickFlickablePrivate::QQuickFlickablePrivate()
, flickBoost(1.0), fixupMode(Normal), vTime(0), visibleArea(0)
, flickableDirection(QQuickFlickable::AutoFlickDirection)
, boundsBehavior(QQuickFlickable::DragAndOvershootBounds)
+ , boundsMovement(QQuickFlickable::FollowBoundsBehavior)
, rebound(0)
{
}
@@ -563,18 +564,6 @@ void QQuickFlickablePrivate::updateBeginningEnd()
visibleArea->updateVisible();
}
-/*
-XXXTODO add docs describing moving, dragging, flicking properties, e.g.
-
-When the user starts dragging the Flickable, the dragging and moving properties
-will be true.
-
-If the velocity is sufficient when the drag is ended, flicking may begin.
-
-The moving properties will remain true until all dragging and flicking
-is finished.
-*/
-
/*!
\qmlsignal QtQuick::Flickable::dragStarted()
@@ -1573,16 +1562,18 @@ void QQuickFlickablePrivate::replayDelayedPress()
void QQuickFlickablePrivate::setViewportX(qreal x)
{
Q_Q(QQuickFlickable);
- if (pixelAligned)
- x = -Round(-x);
-
- contentItem->setX(x);
- if (contentItem->x() != x)
- return; // reentered
+ qreal effectiveX = pixelAligned ? -Round(-x) : x;
const qreal maxX = q->maxXExtent();
const qreal minX = q->minXExtent();
+ if (boundsMovement == int(QQuickFlickable::StopAtBounds))
+ effectiveX = qBound(maxX, effectiveX, minX);
+
+ contentItem->setX(effectiveX);
+ if (contentItem->x() != effectiveX)
+ return; // reentered
+
qreal overshoot = 0.0;
if (x <= maxX)
overshoot = maxX - x;
@@ -1598,16 +1589,18 @@ void QQuickFlickablePrivate::setViewportX(qreal x)
void QQuickFlickablePrivate::setViewportY(qreal y)
{
Q_Q(QQuickFlickable);
- if (pixelAligned)
- y = -Round(-y);
-
- contentItem->setY(y);
- if (contentItem->y() != y)
- return; // reentered
+ qreal effectiveY = pixelAligned ? -Round(-y) : y;
const qreal maxY = q->maxYExtent();
const qreal minY = q->minYExtent();
+ if (boundsMovement == int(QQuickFlickable::StopAtBounds))
+ effectiveY = qBound(maxY, effectiveY, minY);
+
+ contentItem->setY(effectiveY);
+ if (contentItem->y() != effectiveY)
+ return; // reentered
+
qreal overshoot = 0.0;
if (y <= maxY)
overshoot = maxY - y;
@@ -1867,8 +1860,9 @@ QQmlListProperty<QQuickItem> QQuickFlickable::flickableChildren()
beyond the Flickable's boundaries, or overshoot the
Flickable's boundaries when flicked.
- This enables the feeling that the edges of the view are soft,
- rather than a hard physical boundary.
+ When the \l boundsMovement is \c Flickable.FollowBoundsBehavior, a value
+ other than \c Flickable.StopAtBounds will give a feeling that the edges of
+ the view are soft, rather than a hard physical boundary.
The \c boundsBehavior can be one of:
@@ -1884,7 +1878,7 @@ QQmlListProperty<QQuickItem> QQuickFlickable::flickableChildren()
boundary when flicked.
\endlist
- \sa horizontalOvershoot, verticalOvershoot
+ \sa horizontalOvershoot, verticalOvershoot, boundsMovement
*/
QQuickFlickable::BoundsBehavior QQuickFlickable::boundsBehavior() const
{
@@ -2695,7 +2689,11 @@ void QQuickFlickablePrivate::updateVelocity()
The value is negative when the content is dragged or flicked beyond the beginning,
and positive when beyond the end; \c 0.0 otherwise.
- \sa verticalOvershoot, boundsBehavior
+ Whether the values are reported for dragging and/or flicking is determined by
+ \l boundsBehavior. The overshoot distance is reported even when \l boundsMovement
+ is \c Flickable.StopAtBounds.
+
+ \sa verticalOvershoot, boundsBehavior, boundsMovement
*/
qreal QQuickFlickable::horizontalOvershoot() const
{
@@ -2712,7 +2710,11 @@ qreal QQuickFlickable::horizontalOvershoot() const
The value is negative when the content is dragged or flicked beyond the beginning,
and positive when beyond the end; \c 0.0 otherwise.
- \sa horizontalOvershoot, boundsBehavior
+ Whether the values are reported for dragging and/or flicking is determined by
+ \l boundsBehavior. The overshoot distance is reported even when \l boundsMovement
+ is \c Flickable.StopAtBounds.
+
+ \sa horizontalOvershoot, boundsBehavior, boundsMovement
*/
qreal QQuickFlickable::verticalOvershoot() const
{
@@ -2720,4 +2722,66 @@ qreal QQuickFlickable::verticalOvershoot() const
return d->vData.overshoot;
}
+/*!
+ \qmlproperty enumeration QtQuick::Flickable::boundsMovement
+ \since 5.10
+
+ This property holds whether the flickable will give a feeling that the edges of the
+ view are soft, rather than a hard physical boundary.
+
+ The \c boundsMovement can be one of:
+
+ \list
+ \li Flickable.StopAtBounds - this allows implementing custom edge effects where the
+ contents do not follow drags or flicks beyond the bounds of the flickable. The values
+ of \l horizontalOvershoot and \l verticalOvershoot can be utilized to implement custom
+ edge effects.
+ \li Flickable.FollowBoundsBehavior (default) - whether the contents follow drags or
+ flicks beyond the bounds of the flickable is determined by \l boundsBehavior.
+ \endlist
+
+ The following example keeps the contents within bounds and instead applies a flip
+ effect when flicked over horizontal bounds:
+ \code
+ Flickable {
+ id: flickable
+ boundsMovement: Flickable.StopAtBounds
+ boundsBehavior: Flickable.DragAndOvershootBounds
+ transform: Rotation {
+ axis { x: 0; y: 1; z: 0 }
+ origin.x: flickable.width / 2
+ origin.y: flickable.height / 2
+ angle: Math.min(30, Math.max(-30, flickable.horizontalOvershoot))
+ }
+ }
+ \endcode
+
+ The following example keeps the contents within bounds and instead applies an opacity
+ effect when dragged over vertical bounds:
+ \code
+ Flickable {
+ boundsMovement: Flickable.StopAtBounds
+ boundsBehavior: Flickable.DragOverBounds
+ opacity: Math.max(0.5, 1.0 - Math.abs(verticalOvershoot) / height)
+ }
+ \endcode
+
+ \sa boundsBehavior, verticalOvershoot, horizontalOvershoot
+*/
+QQuickFlickable::BoundsMovement QQuickFlickable::boundsMovement() const
+{
+ Q_D(const QQuickFlickable);
+ return d->boundsMovement;
+}
+
+void QQuickFlickable::setBoundsMovement(BoundsMovement movement)
+{
+ Q_D(QQuickFlickable);
+ if (d->boundsMovement == movement)
+ return;
+
+ d->boundsMovement = movement;
+ emit boundsMovementChanged();
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h
index 52cade1472..7558ee7df8 100644
--- a/src/quick/items/qquickflickable_p.h
+++ b/src/quick/items/qquickflickable_p.h
@@ -80,6 +80,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickFlickable : public QQuickItem
Q_PROPERTY(qreal verticalVelocity READ verticalVelocity NOTIFY verticalVelocityChanged)
Q_PROPERTY(BoundsBehavior boundsBehavior READ boundsBehavior WRITE setBoundsBehavior NOTIFY boundsBehaviorChanged)
+ Q_PROPERTY(BoundsMovement boundsMovement READ boundsMovement WRITE setBoundsMovement NOTIFY boundsMovementChanged REVISION 10)
Q_PROPERTY(QQuickTransition *rebound READ rebound WRITE setRebound NOTIFY reboundChanged)
Q_PROPERTY(qreal maximumFlickVelocity READ maximumFlickVelocity WRITE setMaximumFlickVelocity NOTIFY maximumFlickVelocityChanged)
Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration NOTIFY flickDecelerationChanged)
@@ -132,6 +133,15 @@ public:
BoundsBehavior boundsBehavior() const;
void setBoundsBehavior(BoundsBehavior);
+ enum BoundsMovement {
+ // StopAtBounds = 0x0,
+ FollowBoundsBehavior = 0x1
+ };
+ Q_ENUM(BoundsMovement)
+
+ BoundsMovement boundsMovement() const;
+ void setBoundsMovement(BoundsMovement movement);
+
QQuickTransition *rebound() const;
void setRebound(QQuickTransition *transition);
@@ -237,6 +247,7 @@ Q_SIGNALS:
void flickableDirectionChanged();
void interactiveChanged();
void boundsBehaviorChanged();
+ Q_REVISION(10) void boundsMovementChanged();
void reboundChanged();
void maximumFlickVelocityChanged();
void flickDecelerationChanged();
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index 1ceff22dfc..8609a15fcd 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -247,6 +247,7 @@ public:
QQuickFlickableVisibleArea *visibleArea;
QQuickFlickable::FlickableDirection flickableDirection;
QQuickFlickable::BoundsBehavior boundsBehavior;
+ QQuickFlickable::BoundsMovement boundsMovement;
QQuickTransition *rebound;
void viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index f3d7dc4b56..bf982117e8 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -559,7 +559,8 @@ void QQuickImage::updatePaintedGeometry()
void QQuickImage::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
QQuickImageBase::geometryChanged(newGeometry, oldGeometry);
- updatePaintedGeometry();
+ if (newGeometry.size() != oldGeometry.size())
+ updatePaintedGeometry();
}
QRectF QQuickImage::boundingRect() const
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 539a374dd9..0bbf21607d 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -163,7 +163,7 @@ void QQuickTransform::update()
}
QQuickContents::QQuickContents(QQuickItem *item)
-: m_item(item), m_x(0), m_y(0), m_width(0), m_height(0)
+: m_item(item)
{
}
@@ -176,8 +176,8 @@ QQuickContents::~QQuickContents()
bool QQuickContents::calcHeight(QQuickItem *changed)
{
- qreal oldy = m_y;
- qreal oldheight = m_height;
+ qreal oldy = m_contents.y();
+ qreal oldheight = m_contents.height();
if (changed) {
qreal top = oldy;
@@ -187,8 +187,8 @@ bool QQuickContents::calcHeight(QQuickItem *changed)
bottom = y + changed->height();
if (y < top)
top = y;
- m_y = top;
- m_height = bottom - top;
+ m_contents.setY(top);
+ m_contents.setHeight(bottom - top);
} else {
qreal top = std::numeric_limits<qreal>::max();
qreal bottom = -std::numeric_limits<qreal>::max();
@@ -201,17 +201,17 @@ bool QQuickContents::calcHeight(QQuickItem *changed)
top = y;
}
if (!children.isEmpty())
- m_y = top;
- m_height = qMax(bottom - top, qreal(0.0));
+ m_contents.setY(top);
+ m_contents.setHeight(qMax(bottom - top, qreal(0.0)));
}
- return (m_height != oldheight || m_y != oldy);
+ return (m_contents.height() != oldheight || m_contents.y() != oldy);
}
bool QQuickContents::calcWidth(QQuickItem *changed)
{
- qreal oldx = m_x;
- qreal oldwidth = m_width;
+ qreal oldx = m_contents.x();
+ qreal oldwidth = m_contents.width();
if (changed) {
qreal left = oldx;
@@ -221,8 +221,8 @@ bool QQuickContents::calcWidth(QQuickItem *changed)
right = x + changed->width();
if (x < left)
left = x;
- m_x = left;
- m_width = right - left;
+ m_contents.setX(left);
+ m_contents.setWidth(right - left);
} else {
qreal left = std::numeric_limits<qreal>::max();
qreal right = -std::numeric_limits<qreal>::max();
@@ -235,11 +235,11 @@ bool QQuickContents::calcWidth(QQuickItem *changed)
left = x;
}
if (!children.isEmpty())
- m_x = left;
- m_width = qMax(right - left, qreal(0.0));
+ m_contents.setX(left);
+ m_contents.setWidth(qMax(right - left, qreal(0.0)));
}
- return (m_width != oldwidth || m_x != oldx);
+ return (m_contents.width() != oldwidth || m_contents.x() != oldx);
}
void QQuickContents::complete()
@@ -7179,6 +7179,8 @@ void QQuickItemPrivate::setHasCursorInChild(bool hasCursor)
QQuickItemPrivate *parentPrivate = QQuickItemPrivate::get(parent);
parentPrivate->setHasCursorInChild(hasCursor);
}
+#else
+ Q_UNUSED(hasCursor);
#endif
}
@@ -8441,19 +8443,19 @@ struct QQuickItemWrapper : public QObjectWrapper {
struct QQuickItemWrapper : public QV4::QObjectWrapper {
V4_OBJECT2(QQuickItemWrapper, QV4::QObjectWrapper)
- static void markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e);
+ static void markObjects(QV4::Heap::Base *that, QV4::MarkStack *markStack);
};
DEFINE_OBJECT_VTABLE(QQuickItemWrapper);
-void QQuickItemWrapper::markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e)
+void QQuickItemWrapper::markObjects(QV4::Heap::Base *that, QV4::MarkStack *markStack)
{
QObjectWrapper::Data *This = static_cast<QObjectWrapper::Data *>(that);
if (QQuickItem *item = static_cast<QQuickItem*>(This->object())) {
for (QQuickItem *child : qAsConst(QQuickItemPrivate::get(item)->childItems))
- QV4::QObjectWrapper::markWrapper(child, e);
+ QV4::QObjectWrapper::markWrapper(child, markStack);
}
- QV4::QObjectWrapper::markObjects(that, e);
+ QV4::QObjectWrapper::markObjects(that, markStack);
}
quint64 QQuickItemPrivate::_q_createJSWrapper(QV4::ExecutionEngine *engine)
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 797ba42781..e56d839de9 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -94,7 +94,7 @@ public:
QQuickContents(QQuickItem *item);
~QQuickContents();
- QRectF rectF() const { return QRectF(m_x, m_y, m_width, m_height); }
+ QRectF rectF() const { return m_contents; }
inline void calcGeometry(QQuickItem *changed = 0);
void complete();
@@ -112,10 +112,7 @@ private:
void updateRect();
QQuickItem *m_item;
- qreal m_x;
- qreal m_y;
- qreal m_width;
- qreal m_height;
+ QRectF m_contents;
};
void QQuickContents::calcGeometry(QQuickItem *changed)
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 6c0539bcc1..9e692da442 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -401,6 +401,8 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
#if QT_CONFIG(quick_shadereffect)
qmlRegisterType<QQuickShaderEffectSource, 2>(uri, 2, 9, "ShaderEffectSource");
#endif
+
+ qmlRegisterType<QQuickFlickable, 10>(uri, 2, 10, "Flickable");
}
static void initResources()
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp
index 62119effb2..1882976e0c 100644
--- a/src/quick/items/qquickmultipointtoucharea.cpp
+++ b/src/quick/items/qquickmultipointtoucharea.cpp
@@ -176,8 +176,6 @@ void QQuickTouchPoint::setVelocity(const QVector2D &velocity)
It is deprecated because a touch point is more correctly modeled as an ellipse,
whereas this rectangle represents the outer bounds of the ellipse after \l rotation.
-
- \sa horizontalDiameter, verticalDiameter
*/
void QQuickTouchPoint::setArea(const QRectF &area)
{
diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp
index 70fc5fa65f..05882d0464 100644
--- a/src/quick/items/qquickpositioners.cpp
+++ b/src/quick/items/qquickpositioners.cpp
@@ -48,19 +48,8 @@
QT_BEGIN_NAMESPACE
-// The default item change types that positioners are interested in.
-static const QQuickItemPrivate::ChangeTypes explicitSizeItemChangeTypes =
- QQuickItemPrivate::Geometry
- | QQuickItemPrivate::SiblingOrder
- | QQuickItemPrivate::Visibility
- | QQuickItemPrivate::Destroyed;
-
-// The item change types for positioners that are only interested in the implicit
-// size of the items they manage. These are used if useImplicitSize is true.
-// useImplicitSize should be set in the constructor, before any items are added.
-static const QQuickItemPrivate::ChangeTypes implicitSizeItemChangeTypes =
- QQuickItemPrivate::ImplicitWidth
- | QQuickItemPrivate::ImplicitHeight
+static const QQuickItemPrivate::ChangeTypes watchedChanges
+ = QQuickItemPrivate::Geometry
| QQuickItemPrivate::SiblingOrder
| QQuickItemPrivate::Visibility
| QQuickItemPrivate::Destroyed;
@@ -68,15 +57,13 @@ static const QQuickItemPrivate::ChangeTypes implicitSizeItemChangeTypes =
void QQuickBasePositionerPrivate::watchChanges(QQuickItem *other)
{
QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other);
- otherPrivate->addItemChangeListener(this, useImplicitSize
- ? implicitSizeItemChangeTypes : explicitSizeItemChangeTypes);
+ otherPrivate->addItemChangeListener(this, watchedChanges);
}
void QQuickBasePositionerPrivate::unwatchChanges(QQuickItem* other)
{
QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other);
- otherPrivate->removeItemChangeListener(this, useImplicitSize
- ? implicitSizeItemChangeTypes : explicitSizeItemChangeTypes);
+ otherPrivate->removeItemChangeListener(this, watchedChanges);
}
@@ -336,7 +323,7 @@ void QQuickBasePositioner::prePositioning()
if (wIdx < 0) {
d->watchChanges(child);
posItem.isNew = true;
- if (!childPrivate->explicitVisible || !d->itemWidth(child) || !d->itemHeight(child)) {
+ if (!childPrivate->explicitVisible || !child->width() || !child->height()) {
posItem.isVisible = false;
posItem.index = -1;
unpositionedItems.append(posItem);
@@ -358,7 +345,7 @@ void QQuickBasePositioner::prePositioning()
PositionedItem *item = &oldItems[wIdx];
// Items are only omitted from positioning if they are explicitly hidden
// i.e. their positioning is not affected if an ancestor is hidden.
- if (!childPrivate->explicitVisible || !d->itemWidth(child) || !d->itemHeight(child)) {
+ if (!childPrivate->explicitVisible || !child->width() || !child->height()) {
item->isVisible = false;
item->index = -1;
unpositionedItems.append(*item);
@@ -957,7 +944,6 @@ QQuickColumn::QQuickColumn(QQuickItem *parent)
void QQuickColumn::doPositioning(QSizeF *contentSize)
{
//Precondition: All items in the positioned list have a valid item pointer and should be positioned
- QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
qreal voffset = topPadding();
const qreal padding = leftPadding() + rightPadding();
contentSize->setWidth(qMax(contentSize->width(), padding));
@@ -966,9 +952,9 @@ void QQuickColumn::doPositioning(QSizeF *contentSize)
PositionedItem &child = positionedItems[ii];
positionItem(child.itemX() + leftPadding() - child.leftPadding, voffset, &child);
child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
- contentSize->setWidth(qMax(contentSize->width(), d->itemWidth(child.item) + padding));
+ contentSize->setWidth(qMax(contentSize->width(), child.item->width() + padding));
- voffset += d->itemHeight(child.item);
+ voffset += child.item->height();
voffset += spacing();
}
@@ -1236,9 +1222,9 @@ void QQuickRow::doPositioning(QSizeF *contentSize)
hoffsets << hoffset;
}
- contentSize->setHeight(qMax(contentSize->height(), d->itemHeight(child.item) + padding));
+ contentSize->setHeight(qMax(contentSize->height(), child.item->height() + padding));
- hoffset += d->itemWidth(child.item);
+ hoffset += child.item->width();
hoffset += spacing();
}
@@ -1259,7 +1245,7 @@ void QQuickRow::doPositioning(QSizeF *contentSize)
int acc = 0;
for (int ii = 0; ii < positionedItems.count(); ++ii) {
PositionedItem &child = positionedItems[ii];
- hoffset = end - hoffsets[acc++] - d->itemWidth(child.item);
+ hoffset = end - hoffsets[acc++] - child.item->width();
positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child);
child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
}
@@ -1760,12 +1746,10 @@ void QQuickGrid::doPositioning(QSizeF *contentSize)
break;
const PositionedItem &child = positionedItems.at(childIndex++);
- const qreal childWidth = d->itemWidth(child.item);
- const qreal childHeight = d->itemHeight(child.item);
- if (childWidth > maxColWidth[j])
- maxColWidth[j] = childWidth;
- if (childHeight > maxRowHeight[i])
- maxRowHeight[i] = childHeight;
+ if (child.item->width() > maxColWidth[j])
+ maxColWidth[j] = child.item->width();
+ if (child.item->height() > maxRowHeight[i])
+ maxRowHeight[i] = child.item->height();
}
}
} else {
@@ -1780,12 +1764,10 @@ void QQuickGrid::doPositioning(QSizeF *contentSize)
break;
const PositionedItem &child = positionedItems.at(childIndex++);
- const qreal childWidth = d->itemWidth(child.item);
- const qreal childHeight = d->itemHeight(child.item);
- if (childWidth > maxColWidth[j])
- maxColWidth[j] = childWidth;
- if (childHeight > maxRowHeight[i])
- maxRowHeight[i] = childHeight;
+ if (child.item->width() > maxColWidth[j])
+ maxColWidth[j] = child.item->width();
+ if (child.item->height() > maxRowHeight[i])
+ maxRowHeight[i] = child.item->height();
}
}
}
@@ -1827,22 +1809,20 @@ void QQuickGrid::doPositioning(QSizeF *contentSize)
for (int i = 0; i < positionedItems.count(); ++i) {
PositionedItem &child = positionedItems[i];
qreal childXOffset = xoffset;
- const qreal childWidth = d->itemWidth(child.item);
- const qreal childHeight = d->itemHeight(child.item);
if (effectiveHAlign() == AlignRight)
- childXOffset += maxColWidth[curCol] - childWidth;
+ childXOffset += maxColWidth[curCol] - child.item->width();
else if (hItemAlign() == AlignHCenter)
- childXOffset += (maxColWidth[curCol] - childWidth)/2.0;
+ childXOffset += (maxColWidth[curCol] - child.item->width())/2.0;
if (!d->isLeftToRight())
childXOffset -= maxColWidth[curCol];
qreal alignYOffset = yoffset;
if (m_vItemAlign == AlignVCenter)
- alignYOffset += (maxRowHeight[curRow] - childHeight)/2.0;
+ alignYOffset += (maxRowHeight[curRow] - child.item->height())/2.0;
else if (m_vItemAlign == AlignBottom)
- alignYOffset += maxRowHeight[curRow] - childHeight;
+ alignYOffset += maxRowHeight[curRow] - child.item->height();
positionItem(childXOffset, alignYOffset, &child);
child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
@@ -2160,17 +2140,15 @@ void QQuickFlow::doPositioning(QSizeF *contentSize)
for (int i = 0; i < positionedItems.count(); ++i) {
PositionedItem &child = positionedItems[i];
- const qreal childWidth = d->itemWidth(child.item);
- const qreal childHeight = d->itemHeight(child.item);
if (d->flow == LeftToRight) {
- if (widthValid() && hoffset != hoffset1 && hoffset + childWidth + hoffset2 > width()) {
+ if (widthValid() && hoffset != hoffset1 && hoffset + child.item->width() + hoffset2 > width()) {
hoffset = hoffset1;
voffset += linemax + spacing();
linemax = 0;
}
} else {
- if (heightValid() && voffset != voffset1 && voffset + childHeight + bottomPadding() > height()) {
+ if (heightValid() && voffset != voffset1 && voffset + child.item->height() + bottomPadding() > height()) {
voffset = voffset1;
hoffset += linemax + spacing();
linemax = 0;
@@ -2187,17 +2165,17 @@ void QQuickFlow::doPositioning(QSizeF *contentSize)
child.bottomPadding = bottomPadding();
}
- contentSize->setWidth(qMax(contentSize->width(), hoffset + childWidth + hoffset2));
- contentSize->setHeight(qMax(contentSize->height(), voffset + childHeight + bottomPadding()));
+ contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width() + hoffset2));
+ contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height() + bottomPadding()));
if (d->flow == LeftToRight) {
- hoffset += childWidth;
+ hoffset += child.item->width();
hoffset += spacing();
- linemax = qMax(linemax, childHeight);
+ linemax = qMax(linemax, child.item->height());
} else {
- voffset += childHeight;
+ voffset += child.item->height();
voffset += spacing();
- linemax = qMax(linemax, childWidth);
+ linemax = qMax(linemax, child.item->width());
}
}
@@ -2212,7 +2190,7 @@ void QQuickFlow::doPositioning(QSizeF *contentSize)
int acc = 0;
for (int i = 0; i < positionedItems.count(); ++i) {
PositionedItem &child = positionedItems[i];
- hoffset = end - hoffsets[acc++] - d->itemWidth(child.item);
+ hoffset = end - hoffsets[acc++] - child.item->width();
positionItemX(hoffset, &child);
child.leftPadding = leftPadding();
child.rightPadding = rightPadding();
@@ -2236,18 +2214,4 @@ void QQuickFlow::reportConflictingAnchors()
qmlWarning(this) << "Cannot specify anchors for items inside Flow." << " Flow will not function.";
}
-QQuickImplicitRow::QQuickImplicitRow(QQuickItem *parent)
- : QQuickRow(parent)
-{
- QQuickBasePositionerPrivate *d = QQuickBasePositioner::get(this);
- d->useImplicitSize = true;
-}
-
-QQuickImplicitGrid::QQuickImplicitGrid(QQuickItem *parent)
- : QQuickGrid(parent)
-{
- QQuickBasePositionerPrivate *d = QQuickBasePositioner::get(this);
- d->useImplicitSize = true;
-}
-
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickpositioners_p.h b/src/quick/items/qquickpositioners_p.h
index cfe163b4c1..9ae7029d69 100644
--- a/src/quick/items/qquickpositioners_p.h
+++ b/src/quick/items/qquickpositioners_p.h
@@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE
class QQuickBasePositionerPrivate;
-class Q_QUICK_PRIVATE_EXPORT QQuickPositionerAttached : public QObject
+class QQuickPositionerAttached : public QObject
{
Q_OBJECT
@@ -132,11 +132,6 @@ public:
static QQuickPositionerAttached *qmlAttachedProperties(QObject *obj);
- static QQuickBasePositionerPrivate* get(QQuickBasePositioner *positioner)
- {
- return positioner->d_func();
- }
-
void updateAttachedProperties(QQuickPositionerAttached *specificProperty = 0, QQuickItem *specificPropertyOwner = 0) const;
qreal padding() const;
@@ -187,7 +182,7 @@ protected:
virtual void doPositioning(QSizeF *contentSize)=0;
virtual void reportConflictingAnchors()=0;
- class Q_QUICK_PRIVATE_EXPORT PositionedItem
+ class PositionedItem
{
public :
PositionedItem(QQuickItem *i);
@@ -232,7 +227,7 @@ private:
Q_DECLARE_PRIVATE(QQuickBasePositioner)
};
-class Q_QUICK_PRIVATE_EXPORT QQuickColumn : public QQuickBasePositioner
+class Q_AUTOTEST_EXPORT QQuickColumn : public QQuickBasePositioner
{
Q_OBJECT
public:
@@ -246,7 +241,7 @@ private:
};
class QQuickRowPrivate;
-class Q_QUICK_PRIVATE_EXPORT QQuickRow: public QQuickBasePositioner
+class Q_AUTOTEST_EXPORT QQuickRow: public QQuickBasePositioner
{
Q_OBJECT
Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged)
@@ -271,7 +266,7 @@ private:
};
class QQuickGridPrivate;
-class Q_QUICK_PRIVATE_EXPORT QQuickGrid : public QQuickBasePositioner
+class Q_AUTOTEST_EXPORT QQuickGrid : public QQuickBasePositioner
{
Q_OBJECT
Q_PROPERTY(int rows READ rows WRITE setRows NOTIFY rowsChanged)
@@ -358,7 +353,7 @@ private:
};
class QQuickFlowPrivate;
-class Q_QUICK_PRIVATE_EXPORT QQuickFlow: public QQuickBasePositioner
+class Q_AUTOTEST_EXPORT QQuickFlow: public QQuickBasePositioner
{
Q_OBJECT
Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged)
@@ -391,22 +386,6 @@ private:
Q_DECLARE_PRIVATE(QQuickFlow)
};
-class Q_QUICK_PRIVATE_EXPORT QQuickImplicitRow : public QQuickRow
-{
- Q_OBJECT
-
-public:
- QQuickImplicitRow(QQuickItem *parent = nullptr);
-};
-
-class Q_QUICK_PRIVATE_EXPORT QQuickImplicitGrid : public QQuickGrid
-{
- Q_OBJECT
-
-public:
- QQuickImplicitGrid(QQuickItem *parent = nullptr);
-};
-
QT_END_NAMESPACE
@@ -414,8 +393,6 @@ QML_DECLARE_TYPE(QQuickColumn)
QML_DECLARE_TYPE(QQuickRow)
QML_DECLARE_TYPE(QQuickGrid)
QML_DECLARE_TYPE(QQuickFlow)
-QML_DECLARE_TYPE(QQuickImplicitRow)
-QML_DECLARE_TYPE(QQuickImplicitGrid)
QML_DECLARE_TYPE(QQuickBasePositioner)
QML_DECLARE_TYPEINFO(QQuickBasePositioner, QML_HAS_ATTACHED_PROPERTIES)
diff --git a/src/quick/items/qquickpositioners_p_p.h b/src/quick/items/qquickpositioners_p_p.h
index 1a7051615c..0be4c56df6 100644
--- a/src/quick/items/qquickpositioners_p_p.h
+++ b/src/quick/items/qquickpositioners_p_p.h
@@ -89,14 +89,10 @@ public:
QLazilyAllocated<ExtraData> extra;
QQuickBasePositionerPrivate()
- : spacing(0)
- , type(QQuickBasePositioner::None)
- , transitioner(0)
- , positioningDirty(false)
- , doingPositioning(false)
- , anchorConflict(false)
- , useImplicitSize(false)
- , layoutDirection(Qt::LeftToRight)
+ : spacing(0), type(QQuickBasePositioner::None)
+ , transitioner(0), positioningDirty(false)
+ , doingPositioning(false), anchorConflict(false), layoutDirection(Qt::LeftToRight)
+
{
}
@@ -123,7 +119,6 @@ public:
bool positioningDirty : 1;
bool doingPositioning : 1;
bool anchorConflict : 1;
- bool useImplicitSize : 1;
Qt::LayoutDirection layoutDirection;
@@ -179,34 +174,6 @@ public:
{
}
- void itemImplicitWidthChanged(QQuickItem *) override
- {
- Q_ASSERT(useImplicitSize);
- setPositioningDirty();
- }
-
- void itemImplicitHeightChanged(QQuickItem *) override
- {
- Q_ASSERT(useImplicitSize);
- setPositioningDirty();
- }
-
- qreal itemWidth(QQuickItem *item) const
- {
- if (Q_LIKELY(!useImplicitSize))
- return item->width();
-
- return item->implicitWidth();
- }
-
- qreal itemHeight(QQuickItem *item) const
- {
- if (Q_LIKELY(!useImplicitSize))
- return item->height();
-
- return item->implicitHeight();
- }
-
inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; }
void setTopPadding(qreal value, bool reset = false);
void setLeftPadding(qreal value, bool reset = false);
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index 03d96aea1f..e2a20f9e7e 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -385,6 +385,9 @@ QImage QQuickRenderControl::grab()
cd->syncSceneGraph();
render();
grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->effectiveDevicePixelRatio(), false, false);
+ if (QQuickRenderControl::renderWindowFor(d->window)) {
+ grabContent.setDevicePixelRatio(d->window->effectiveDevicePixelRatio());
+ }
#endif
} else if (d->window->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) {
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 1720377046..c8bc76aef8 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -274,15 +274,9 @@ void QQuickTextPrivate::updateLayout()
elideLayout->clearFormats();
QString tmp = text;
multilengthEos = tmp.indexOf(QLatin1Char('\x9c'));
- if (multilengthEos != -1) {
+ if (multilengthEos != -1)
tmp = tmp.mid(0, multilengthEos);
- tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
- } else if (tmp.contains(QLatin1Char('\n'))) {
- // Replace always does a detach. Checking for the new line character first
- // means iterating over those items again if found but prevents a realloc
- // otherwise.
- tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
- }
+ tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
layout.setText(tmp);
}
textHasChanged = false;
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index 555fd233b3..2dce3e9ec8 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -769,52 +769,8 @@ void QQuickTextControl::processEvent(QEvent *e, const QMatrix &matrix)
case QEvent::ShortcutOverride:
if (d->interactionFlags & Qt::TextEditable) {
QKeyEvent* ke = static_cast<QKeyEvent *>(e);
- if (ke->modifiers() == Qt::NoModifier
- || ke->modifiers() == Qt::ShiftModifier
- || ke->modifiers() == Qt::KeypadModifier) {
- if (ke->key() < Qt::Key_Escape) {
- ke->accept();
- } else {
- switch (ke->key()) {
- case Qt::Key_Return:
- case Qt::Key_Enter:
- case Qt::Key_Delete:
- case Qt::Key_Home:
- case Qt::Key_End:
- case Qt::Key_Backspace:
- case Qt::Key_Left:
- case Qt::Key_Right:
- case Qt::Key_Up:
- case Qt::Key_Down:
- case Qt::Key_Tab:
- ke->accept();
- default:
- break;
- }
- }
-#if QT_CONFIG(shortcut)
- } else if (ke == QKeySequence::Copy
- || ke == QKeySequence::Paste
- || ke == QKeySequence::Cut
- || ke == QKeySequence::Redo
- || ke == QKeySequence::Undo
- || ke == QKeySequence::MoveToNextWord
- || ke == QKeySequence::MoveToPreviousWord
- || ke == QKeySequence::MoveToStartOfDocument
- || ke == QKeySequence::MoveToEndOfDocument
- || ke == QKeySequence::SelectNextWord
- || ke == QKeySequence::SelectPreviousWord
- || ke == QKeySequence::SelectStartOfLine
- || ke == QKeySequence::SelectEndOfLine
- || ke == QKeySequence::SelectStartOfBlock
- || ke == QKeySequence::SelectEndOfBlock
- || ke == QKeySequence::SelectStartOfDocument
- || ke == QKeySequence::SelectEndOfDocument
- || ke == QKeySequence::SelectAll
- ) {
+ if (isCommonTextEditShortcut(ke))
ke->accept();
-#endif
- }
}
break;
default:
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index a023ad8a8c..f4a88a1c45 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -3885,6 +3885,7 @@ void QQuickTextInputPrivate::parseInputMask(const QString &maskFields)
break;
case '\\':
escape = true;
+ Q_FALLTHROUGH();
default:
s = true;
break;
@@ -4403,7 +4404,9 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
}
bool unknown = false;
+#if QT_CONFIG(shortcut)
bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
+#endif
if (false) {
}
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index bd68f39e48..b3417cc727 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -2762,6 +2762,8 @@ void QQuickWindowPrivate::contextCreationFailureMessage(const QSurfaceFormat &fo
#endif // !Q_OS_WIN32
}
+#if QT_DEPRECATED_SINCE(5, 8)
+
/*!
Propagates an event \a e to a QQuickItem \a item on the window.
@@ -2814,6 +2816,8 @@ bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e)
return false;
}
+#endif
+
void QQuickWindowPrivate::cleanupNodes()
{
for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
@@ -3526,6 +3530,7 @@ QImage QQuickWindow::grabWindow()
bool alpha = format().alphaBufferSize() > 0 && color().alpha() < 255;
QImage image = qt_gl_read_framebuffer(size() * effectiveDevicePixelRatio(), alpha, alpha);
+ image.setDevicePixelRatio(effectiveDevicePixelRatio());
d->cleanupNodesOnShutdown();
d->context->invalidate();
context.doneCurrent();
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index 27a73988ae..0655ae9e7f 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -112,7 +112,9 @@ public:
QQuickItem *mouseGrabberItem() const;
- bool sendEvent(QQuickItem *, QEvent *);
+#if QT_DEPRECATED_SINCE(5, 8)
+ QT_DEPRECATED bool sendEvent(QQuickItem *, QEvent *);
+#endif
QImage grabWindow();
#if QT_CONFIG(opengl)
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index d4324bc489..14f8514289 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -338,7 +338,7 @@ void Updater::visitNode(Node *n)
case QSGNode::RenderNodeType:
if (m_added)
n->renderNodeElement()->root = m_roots.last();
- // Fall through to visit children.
+ Q_FALLTHROUGH(); // to visit children
default:
SHADOWNODE_TRAVERSE(n) visitNode(child);
break;
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
index 8d666d3d0b..07dc87a643 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
@@ -419,6 +419,10 @@ void QSGMaterialShader::compile()
\value DirtyMatrix Used to indicate that the matrix has changed and must be updated.
\value DirtyOpacity Used to indicate that the opacity has changed and must be updated.
+
+ \value DirtyCachedMaterialData Used to indicate that the cached material data have changed and must be updated.
+
+ \value DirtyAll Used to indicate that everything needs to be updated.
*/
diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp
index 7ef75d4b4c..7ac3914023 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnode.cpp
@@ -112,6 +112,7 @@ static void qt_print_node_count()
\value DirtyGeometry The geometry of a QSGGeometryNode has changed.
\value DirtyMaterial The material of a QSGGeometryNode has changed.
\value DirtyOpacity The opacity of a QSGOpacityNode has changed.
+ \value DirtySubtreeBlocked The subtree has been blocked.
\sa QSGNode::markDirty()
*/
@@ -146,6 +147,7 @@ static void qt_print_node_count()
\value TransformNodeType The type of QSGTransformNode
\value ClipNodeType The type of QSGClipNode
\value OpacityNodeType The type of QSGOpacityNode
+ \value RenderNodeType The type of QSGRenderNode
\sa type()
*/
diff --git a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
index 48ab1aa52f..2b70139b37 100644
--- a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
+++ b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
@@ -133,6 +133,7 @@ Tokenizer::Token Tokenizer::next()
pos += 3;
return Token_Void;
}
+ Q_FALLTHROUGH();
}
case ';': return Token_SemiColon;
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index bb581c5e36..293a706c2e 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -423,6 +423,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
if (data.grabOnly) {
bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() != 255;
grabContent = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), alpha, alpha);
+ grabContent.setDevicePixelRatio(window->effectiveDevicePixelRatio());
data.grabOnly = false;
}
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 17a2c62a4e..560fddd580 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -432,6 +432,7 @@ bool QSGRenderThread::event(QEvent *e)
qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- grabbing result";
bool alpha = ce->window->format().alphaBufferSize() > 0 && ce->window->color().alpha() != 255;
*ce->image = qt_gl_read_framebuffer(windowSize * ce->window->effectiveDevicePixelRatio(), alpha, alpha);
+ ce->image->setDevicePixelRatio(ce->window->effectiveDevicePixelRatio());
}
qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- waking gui to handle result";
waitCondition.wakeOne();
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index e944ddbc4f..eff6763a16 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -325,6 +325,7 @@ QImage QSGWindowsRenderLoop::grab(QQuickWindow *window)
bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() != 255;
QImage image = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), alpha, alpha);
+ image.setDevicePixelRatio(window->effectiveDevicePixelRatio());
return image;
}
diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp
index 09e4cdf5a7..259e45c978 100644
--- a/src/quick/scenegraph/util/qsgengine.cpp
+++ b/src/quick/scenegraph/util/qsgengine.cpp
@@ -84,6 +84,8 @@ QT_BEGIN_NAMESPACE
will delete the GL texture when the texture object is deleted.
\value TextureCanUseAtlas The image can be uploaded into a texture atlas.
+
+ \value TextureIsOpaque The texture object is opaque.
*/
QSGEnginePrivate::QSGEnginePrivate()
diff --git a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp
index d8f92919cb..e134a5d4d3 100644
--- a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp
+++ b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp
@@ -122,6 +122,7 @@ Tokenizer::Token Tokenizer::next()
case '*':
if (*pos == '/')
return Token_MultiLineCommentEnd;
+ Q_FALLTHROUGH();
case '\n':
return Token_NewLine;
@@ -129,6 +130,7 @@ Tokenizer::Token Tokenizer::next()
case '\r':
if (*pos == '\n')
return Token_NewLine;
+ Q_FALLTHROUGH();
case '#': {
if (*pos == 'v' && pos[1] == 'e' && pos[2] == 'r' && pos[3] == 's'
@@ -177,7 +179,7 @@ Tokenizer::Token Tokenizer::next()
pos += 3;
return Token_Void;
}
- // Fall-thru
+ Q_FALLTHROUGH();
}
default:
// Identifier...
diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
index 521c5e666f..3432a87c53 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -297,6 +297,8 @@ static void qt_debug_remove_texture(QSGTexture* texture)
\value Anisotropy8x 8x anisotropic filtering.
\value Anisotropy16x 16x anisotropic filtering.
+
+ \since 5.9
*/
/*!
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index 89007cff1f..9c9261c101 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -140,6 +140,14 @@ QObject *QQuickAnimatorProxyJob::findAnimationContext(QQuickAbstractAnimation *a
void QQuickAnimatorProxyJob::updateCurrentTime(int)
{
+ if (m_internalState != State_Running)
+ return;
+
+ // A proxy which is being ticked should be associated with a window, (see
+ // setWindow() below). If we get here when there is no more controller we
+ // have a problem.
+ Q_ASSERT(m_controller);
+
// We do a simple check here to see if the animator has run and stopped on
// the render thread. isPendingStart() will perform a check against jobs
// that have been scheduled for start, but that will not yet have entered
@@ -150,8 +158,7 @@ void QQuickAnimatorProxyJob::updateCurrentTime(int)
// we might get the wrong value for this update, but then we'll simply
// pick it up on the next iterationm when the job is stopped and render
// thread is no longer using it.
- if (m_internalState == State_Running
- && !m_controller->isPendingStart(m_job)
+ if (!m_controller->isPendingStart(m_job)
&& !m_job->isRunning()) {
stop();
}
@@ -167,9 +174,9 @@ void QQuickAnimatorProxyJob::updateState(QAbstractAnimationJob::State newState,
}
} else if (newState == Stopped) {
- syncBackCurrentValues();
m_internalState = State_Stopped;
if (m_controller) {
+ syncBackCurrentValues();
m_controller->cancel(m_job);
}
}
@@ -193,6 +200,7 @@ void QQuickAnimatorProxyJob::setWindow(QQuickWindow *window)
if (m_job && m_controller)
m_controller->cancel(m_job);
m_controller = nullptr;
+ stop();
} else if (!m_controller && m_job) {
m_controller = QQuickWindowPrivate::get(window)->animationController;
@@ -313,8 +321,10 @@ void QQuickTransformAnimatorJob::preSync()
m_helper = nullptr;
}
- if (!m_target)
+ if (!m_target) {
+ invalidate();
return;
+ }
if (!m_helper) {
m_helper = qquick_transform_animatorjob_helper_store()->acquire(m_target);
@@ -334,27 +344,6 @@ void QQuickTransformAnimatorJob::preSync()
m_helper->sync();
}
-void QQuickTransformAnimatorJob::postSync()
-{
- Q_ASSERT((m_helper != nullptr) == (m_target != nullptr)); // If there is a target, there should also be a helper, ref: preSync
- Q_ASSERT(!m_helper || m_helper->item == m_target); // If there is a helper, it should point to our target
-
- if (!m_target || !m_helper) {
- invalidate();
- return;
- }
-
- QQuickItemPrivate *d = QQuickItemPrivate::get(m_target);
-#if QT_CONFIG(quick_shadereffect)
- if (d->extra.isAllocated()
- && d->extra->layer
- && d->extra->layer->enabled()) {
- d = QQuickItemPrivate::get(d->extra->layer->m_effectSource);
- }
-#endif
- m_helper->node = d->itemNode();
-}
-
void QQuickTransformAnimatorJob::invalidate()
{
if (m_helper)
diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h
index a3ced4c21b..777da2ee6c 100644
--- a/src/quick/util/qquickanimatorjob_p.h
+++ b/src/quick/util/qquickanimatorjob_p.h
@@ -235,7 +235,6 @@ public:
protected:
QQuickTransformAnimatorJob();
- void postSync() override;
void invalidate() override;
Helper *m_helper;
diff --git a/src/quick/util/qquickfontloader.cpp b/src/quick/util/qquickfontloader.cpp
index 3761a37a6d..21e8eda365 100644
--- a/src/quick/util/qquickfontloader.cpp
+++ b/src/quick/util/qquickfontloader.cpp
@@ -236,7 +236,7 @@ QQuickFontLoader::~QQuickFontLoader()
/*!
\qmlproperty url QtQuick::FontLoader::source
- The url of the font to load.
+ The URL of the font to load.
*/
QUrl QQuickFontLoader::source() const
{
@@ -317,7 +317,7 @@ void QQuickFontLoader::updateFontInfo(const QString& name, QQuickFontLoader::Sta
\qmlproperty string QtQuick::FontLoader::name
This property holds the name of the font family.
- It is set automatically when a font is loaded using the \c url property.
+ It is set automatically when a font is loaded using the \l source property.
Use this to set the \c font.family property of a \c Text item.
diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp
index 20bb23338d..2070fd7ff0 100644
--- a/src/quick/util/qquickglobal.cpp
+++ b/src/quick/util/qquickglobal.cpp
@@ -810,6 +810,7 @@ public:
#ifndef QT_NO_DESKTOPSERVICES
return QDesktopServices::openUrl(url);
#else
+ Q_UNUSED(url);
return false;
#endif
}
diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp
index 0ceed7f681..c4a98c69f9 100644
--- a/src/quick/util/qquickimageprovider.cpp
+++ b/src/quick/util/qquickimageprovider.cpp
@@ -613,7 +613,6 @@ void QQuickImageProviderOptions::setPreserveAspectRatioFit(bool preserveAspectRa
d->preserveAspectRatioFit = preserveAspectRatioFit;
}
-
QQuickImageProviderWithOptions::QQuickImageProviderWithOptions(ImageType type, Flags flags)
: QQuickAsyncImageProvider()
{
@@ -670,5 +669,49 @@ QQuickImageResponse *QQuickImageProviderWithOptions::requestImageResponse(const
return requestImageResponse(id, requestedSize);
}
+/*!
+ Returns the recommended scaled image size for loading and storage. This is
+ calculated according to the native pixel size of the image \a originalSize,
+ the requested sourceSize \a requestedSize, the image file format \a format,
+ and \a options. If the calculation otherwise concludes that scaled loading
+ is not recommended, an invalid size is returned.
+*/
+QSize QQuickImageProviderWithOptions::loadSize(const QSize &originalSize, const QSize &requestedSize, const QByteArray &format, const QQuickImageProviderOptions &options)
+{
+ QSize res;
+ if ((requestedSize.width() <= 0 && requestedSize.height() <= 0) || originalSize.isEmpty())
+ return res;
+
+ const bool preserveAspectCropOrFit = options.preserveAspectRatioCrop() || options.preserveAspectRatioFit();
+ const bool force_scale = (format == "svg" || format == "svgz");
+
+ qreal ratio = 0.0;
+ if (requestedSize.width() && (preserveAspectCropOrFit || force_scale || requestedSize.width() < originalSize.width())) {
+ ratio = qreal(requestedSize.width()) / originalSize.width();
+ }
+ if (requestedSize.height() && (preserveAspectCropOrFit || force_scale || requestedSize.height() < originalSize.height())) {
+ qreal hr = qreal(requestedSize.height()) / originalSize.height();
+ if (ratio == 0.0)
+ ratio = hr;
+ else if (!preserveAspectCropOrFit && (hr < ratio))
+ ratio = hr;
+ else if (preserveAspectCropOrFit && (hr > ratio))
+ ratio = hr;
+ }
+ if (ratio > 0.0) {
+ res.setHeight(qRound(originalSize.height() * ratio));
+ res.setWidth(qRound(originalSize.width() * ratio));
+ }
+ return res;
+}
+
+QQuickImageProviderWithOptions *QQuickImageProviderWithOptions::checkedCast(QQuickImageProvider *provider)
+{
+ if (provider && provider->d && provider->d->isProviderWithOptions)
+ return static_cast<QQuickImageProviderWithOptions *>(provider);
+
+ return nullptr;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickimageprovider.h b/src/quick/util/qquickimageprovider.h
index c77ff95f32..681de4b6c2 100644
--- a/src/quick/util/qquickimageprovider.h
+++ b/src/quick/util/qquickimageprovider.h
@@ -88,7 +88,6 @@ Q_SIGNALS:
class Q_QUICK_EXPORT QQuickImageProvider : public QQmlImageProviderBase
{
friend class QQuickImageProviderWithOptions; // ### Qt 6 Remove
- friend class QQuickPixmapReader; // ### Qt 6 Remove
public:
QQuickImageProvider(ImageType type, Flags flags = Flags());
virtual ~QQuickImageProvider();
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 395b89c784..7d88935402 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -141,6 +141,7 @@ public:
QUrl url;
bool loading;
+ QQuickImageProviderOptions providerOptions;
int redirectCount;
class Event : public QEvent {
@@ -204,7 +205,7 @@ protected:
private:
friend class QQuickPixmapReaderThreadObject;
void processJobs();
- void processJob(QQuickPixmapReply *, const QUrl &, const QString &, const QQuickImageProviderOptions &, QQuickImageProvider::ImageType, QQuickImageProvider *);
+ void processJob(QQuickPixmapReply *, const QUrl &, const QString &, QQuickImageProvider::ImageType, QQuickImageProvider *);
#if QT_CONFIG(qml_network)
void networkRequestDone(QNetworkReply *);
#endif
@@ -386,37 +387,15 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e
const QSize &requestSize, const QQuickImageProviderOptions &providerOptions,
QQuickImageProviderOptions::AutoTransform *appliedTransform = nullptr)
{
- const bool preserveAspectCropOrFit = providerOptions.preserveAspectRatioCrop() || providerOptions.preserveAspectRatioFit();
-
QImageReader imgio(dev);
if (providerOptions.autoTransform() != QQuickImageProviderOptions::UsePluginDefaultTransform)
imgio.setAutoTransform(providerOptions.autoTransform() == QQuickImageProviderOptions::ApplyTransform);
else if (appliedTransform)
*appliedTransform = imgio.autoTransform() ? QQuickImageProviderOptions::ApplyTransform : QQuickImageProviderOptions::DoNotApplyTransform;
- const bool force_scale = imgio.format() == "svg" || imgio.format() == "svgz";
-
- if (requestSize.width() > 0 || requestSize.height() > 0) {
- QSize s = imgio.size();
- qreal ratio = 0.0;
- if (requestSize.width() && (preserveAspectCropOrFit || force_scale || requestSize.width() < s.width())) {
- ratio = qreal(requestSize.width())/s.width();
- }
- if (requestSize.height() && (preserveAspectCropOrFit || force_scale || requestSize.height() < s.height())) {
- qreal hr = qreal(requestSize.height())/s.height();
- if (ratio == 0.0)
- ratio = hr;
- else if (!preserveAspectCropOrFit && (hr < ratio))
- ratio = hr;
- else if (preserveAspectCropOrFit && (hr > ratio))
- ratio = hr;
- }
- if (ratio > 0.0) {
- s.setHeight(qRound(s.height() * ratio));
- s.setWidth(qRound(s.width() * ratio));
- imgio.setScaledSize(s);
- }
- }
+ QSize scSize = QQuickImageProviderWithOptions::loadSize(imgio.size(), requestSize, imgio.format(), providerOptions);
+ if (scSize.isValid())
+ imgio.setScaledSize(scSize);
if (impsize)
*impsize = imgio.size();
@@ -664,7 +643,7 @@ void QQuickPixmapReader::processJobs()
PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
locker.unlock();
- processJob(job, url, localFile, job->data->providerOptions, imageType, provider);
+ processJob(job, url, localFile, imageType, provider);
locker.relock();
}
}
@@ -676,7 +655,6 @@ void QQuickPixmapReader::processJobs()
}
void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &url, const QString &localFile,
- const QQuickImageProviderOptions &providerOptions,
QQuickImageProvider::ImageType imageType, QQuickImageProvider *provider)
{
// fetch
@@ -693,8 +671,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
return;
}
- QQuickImageProviderWithOptions *providerV2 = provider->d->isProviderWithOptions ? static_cast<QQuickImageProviderWithOptions *>(provider)
- : nullptr;
+ QQuickImageProviderWithOptions *providerV2 = QQuickImageProviderWithOptions::checkedCast(provider);
switch (imageType) {
case QQuickImageProvider::Invalid:
@@ -707,7 +684,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
{
QImage image;
if (providerV2) {
- image = providerV2->requestImage(imageId(url), &readSize, runningJob->requestSize, providerOptions);
+ image = providerV2->requestImage(imageId(url), &readSize, runningJob->requestSize, runningJob->providerOptions);
} else {
image = provider->requestImage(imageId(url), &readSize, runningJob->requestSize);
}
@@ -728,7 +705,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
{
QPixmap pixmap;
if (providerV2) {
- pixmap = providerV2->requestPixmap(imageId(url), &readSize, runningJob->requestSize, providerOptions);
+ pixmap = providerV2->requestPixmap(imageId(url), &readSize, runningJob->requestSize, runningJob->providerOptions);
} else {
pixmap = provider->requestPixmap(imageId(url), &readSize, runningJob->requestSize);
}
@@ -749,7 +726,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
{
QQuickTextureFactory *t;
if (providerV2) {
- t = providerV2->requestTexture(imageId(url), &readSize, runningJob->requestSize, providerOptions);
+ t = providerV2->requestTexture(imageId(url), &readSize, runningJob->requestSize, runningJob->providerOptions);
} else {
t = provider->requestTexture(imageId(url), &readSize, runningJob->requestSize);
}
@@ -772,7 +749,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
{
QQuickImageResponse *response;
if (providerV2) {
- response = providerV2->requestImageResponse(imageId(url), runningJob->requestSize, providerOptions);
+ response = providerV2->requestImageResponse(imageId(url), runningJob->requestSize, runningJob->providerOptions);
} else {
QQuickAsyncImageProvider *asyncProvider = static_cast<QQuickAsyncImageProvider*>(provider);
response = asyncProvider->requestImageResponse(imageId(url), runningJob->requestSize);
@@ -794,7 +771,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
QFile f(localFile);
QSize readSize;
if (f.open(QIODevice::ReadOnly)) {
- if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, providerOptions))
+ if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, runningJob->providerOptions))
errorCode = QQuickPixmapReply::Loading;
} else {
errorStr = QQuickPixmap::tr("Cannot open: %1").arg(url.toString());
@@ -1075,7 +1052,7 @@ void QQuickPixmap::purgeCache()
}
QQuickPixmapReply::QQuickPixmapReply(QQuickPixmapData *d)
-: data(d), engineForReader(0), requestSize(d->requestSize), url(d->url), loading(false), redirectCount(0)
+: data(d), engineForReader(0), requestSize(d->requestSize), url(d->url), loading(false), providerOptions(d->providerOptions), redirectCount(0)
{
if (finishedIndex == -1) {
finishedIndex = QMetaMethod::fromSignal(&QQuickPixmapReply::finished).methodIndex();
@@ -1196,6 +1173,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
QQuickImageProvider::ImageType imageType = QQuickImageProvider::Invalid;
QQuickImageProvider *provider = static_cast<QQuickImageProvider *>(engine->imageProvider(imageProviderId(url)));
+ QQuickImageProviderWithOptions *providerV2 = QQuickImageProviderWithOptions::checkedCast(provider);
if (provider)
imageType = provider->imageType();
@@ -1205,7 +1183,8 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
QQuickPixmap::tr("Invalid image provider: %1").arg(url.toString()));
case QQuickImageProvider::Texture:
{
- QQuickTextureFactory *texture = provider->requestTexture(imageId(url), &readSize, requestSize);
+ QQuickTextureFactory *texture = providerV2 ? providerV2->requestTexture(imageId(url), &readSize, requestSize, providerOptions)
+ : provider->requestTexture(imageId(url), &readSize, requestSize);
if (texture) {
*ok = true;
return new QQuickPixmapData(declarativePixmap, url, texture, readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
@@ -1215,7 +1194,8 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
case QQuickImageProvider::Image:
{
- QImage image = provider->requestImage(imageId(url), &readSize, requestSize);
+ QImage image = providerV2 ? providerV2->requestImage(imageId(url), &readSize, requestSize, providerOptions)
+ : provider->requestImage(imageId(url), &readSize, requestSize);
if (!image.isNull()) {
*ok = true;
return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
@@ -1224,7 +1204,8 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
}
case QQuickImageProvider::Pixmap:
{
- QPixmap pixmap = provider->requestPixmap(imageId(url), &readSize, requestSize);
+ QPixmap pixmap = providerV2 ? providerV2->requestPixmap(imageId(url), &readSize, requestSize, providerOptions)
+ : provider->requestPixmap(imageId(url), &readSize, requestSize);
if (!pixmap.isNull()) {
*ok = true;
return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h
index 93d5a1cf56..91fb1ed3bb 100644
--- a/src/quick/util/qquickpixmapcache_p.h
+++ b/src/quick/util/qquickpixmapcache_p.h
@@ -204,6 +204,9 @@ public:
virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize, const QQuickImageProviderOptions &options);
virtual QQuickTextureFactory *requestTexture(const QString &id, QSize *size, const QSize &requestedSize, const QQuickImageProviderOptions &options);
virtual QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize, const QQuickImageProviderOptions &options);
+
+ static QSize loadSize(const QSize &originalSize, const QSize &requestedSize, const QByteArray &format, const QQuickImageProviderOptions &options);
+ static QQuickImageProviderWithOptions *checkedCast(QQuickImageProvider *provider);
};
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickshortcut_p.h b/src/quick/util/qquickshortcut_p.h
index 93430ad893..db918058b2 100644
--- a/src/quick/util/qquickshortcut_p.h
+++ b/src/quick/util/qquickshortcut_p.h
@@ -111,6 +111,7 @@ protected:
bool event(QEvent *event) Q_DECL_OVERRIDE;
struct Shortcut {
+ Shortcut() : id(0) { }
bool matches(QShortcutEvent *event) const;
int id;
QVariant userValue;
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index 5d7fb04b9f..a2ea0f7af2 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -76,10 +76,6 @@
QT_BEGIN_NAMESPACE
-#if QT_CONFIG(opengl)
-extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
-#endif
-
class QQuickWidgetRenderControl : public QQuickRenderControl
{
public:
@@ -157,6 +153,16 @@ void QQuickWidgetPrivate::invalidateRenderControl()
#endif
renderControl->invalidate();
+
+ // Many things can happen inside the above invalidate() call, including a
+ // change of current context. Restore if needed since some code will rely
+ // on the fact that this function makes and leaves the context current.
+#if QT_CONFIG(opengl)
+ if (!useSoftwareRenderer && context) {
+ if (QOpenGLContext::currentContext() != context)
+ context->makeCurrent(offscreenSurface);
+ }
+#endif
}
void QQuickWidgetPrivate::handleWindowChange()
diff --git a/tests/auto/particles/qquickparticlesystem/data/crashaffectors.qml b/tests/auto/particles/qquickparticlesystem/data/crashaffectors.qml
new file mode 100644
index 0000000000..de105916a7
--- /dev/null
+++ b/tests/auto/particles/qquickparticlesystem/data/crashaffectors.qml
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 reMarkable A/S
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Particles 2.0
+
+ParticleSystem {
+ running: false
+ Affector { Component.onCompleted: destroy() }
+ Emitter {
+ Timer { interval: 1; running: true; onTriggered: parent.lifeSpan = 1 }
+ }
+}
diff --git a/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp b/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp
index 5c82b946e5..5f9db12144 100644
--- a/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp
+++ b/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp
@@ -42,6 +42,7 @@ public:
private slots:
void initTestCase();
void test_basic();
+ void test_affectorscrash();
};
void tst_qquickparticlesystem::initTestCase()
@@ -78,6 +79,12 @@ void tst_qquickparticlesystem::test_basic()
delete view;
QVERIFY(extremelyFuzzyCompare(stillAlive, 500, 5));//Small simulation variance is permissible.
}
+void tst_qquickparticlesystem::test_affectorscrash()
+{
+ QScopedPointer<QQuickView> view (createView(testFileUrl("crashaffectors.qml"), 600));
+
+ // This should have crashed by now
+}
QTEST_MAIN(tst_qquickparticlesystem);
diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
index 8c30a82317..d9a4777115 100644
--- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
+++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp
@@ -180,14 +180,9 @@ void tst_QQmlEngineDebugService::recursiveObjectTest(
{
const QMetaObject *meta = o->metaObject();
- QQmlType *type = QQmlMetaType::qmlType(meta);
- QString className = type ? QString(type->qmlTypeName())
- : QString(meta->className());
- className = className.mid(className.lastIndexOf(QLatin1Char('/'))+1);
-
QCOMPARE(oref.debugId, QQmlDebugService::idForObject(o));
QCOMPARE(oref.name, o->objectName());
- QCOMPARE(oref.className, className);
+ QCOMPARE(oref.className, QQmlMetaType::prettyTypeName(o));
QCOMPARE(oref.contextDebugId, QQmlDebugService::idForObject(
qmlContext(o)));
@@ -201,6 +196,7 @@ void tst_QQmlEngineDebugService::recursiveObjectTest(
QmlDebugObjectReference cref;
foreach (const QmlDebugObjectReference &ref, oref.children) {
+ QVERIFY(!ref.className.isEmpty());
if (ref.debugId == debugId) {
cref = ref;
break;
@@ -369,6 +365,7 @@ void tst_QQmlEngineDebugService::setMethodBody()
{
bool success;
QmlDebugObjectReference obj = findRootObject(2);
+ QVERIFY(!obj.className.isEmpty());
QObject *root = m_components.at(2);
// Without args
@@ -410,6 +407,7 @@ void tst_QQmlEngineDebugService::setMethodBody()
void tst_QQmlEngineDebugService::watch_property()
{
QmlDebugObjectReference obj = findRootObject();
+ QVERIFY(!obj.className.isEmpty());
QmlDebugPropertyReference prop = findProperty(obj.properties, "width");
bool success;
@@ -454,6 +452,7 @@ void tst_QQmlEngineDebugService::watch_property()
void tst_QQmlEngineDebugService::watch_object()
{
QmlDebugObjectReference obj = findRootObject();
+ QVERIFY(!obj.className.isEmpty());
bool success;
@@ -519,6 +518,7 @@ void tst_QQmlEngineDebugService::watch_expression()
int origWidth = m_rootItem->property("width").toInt();
QmlDebugObjectReference obj = findRootObject();
+ QVERIFY(!obj.className.isEmpty());
bool success;
@@ -654,6 +654,7 @@ void tst_QQmlEngineDebugService::queryObject()
bool success;
QmlDebugObjectReference rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
recursive ? unconnected->queryObjectRecursive(rootObject, &success) : unconnected->queryObject(rootObject, &success);
@@ -665,6 +666,7 @@ void tst_QQmlEngineDebugService::queryObject()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QmlDebugObjectReference obj = m_dbg->object();
+ QVERIFY(!obj.className.isEmpty());
// check source as defined in main()
QmlDebugFileReference source = obj.source;
@@ -676,12 +678,15 @@ void tst_QQmlEngineDebugService::queryObject()
recursiveObjectTest(m_rootItem, obj, recursive);
if (recursive) {
- foreach (const QmlDebugObjectReference &child, obj.children)
+ foreach (const QmlDebugObjectReference &child, obj.children) {
+ QVERIFY(!child.className.isEmpty());
QVERIFY(child.properties.count() > 0);
+ }
QmlDebugObjectReference rect;
QmlDebugObjectReference text;
foreach (const QmlDebugObjectReference &child, obj.children) {
+ QVERIFY(!child.className.isEmpty());
if (child.className == "Rectangle")
rect = child;
else if (child.className == "Text")
@@ -695,8 +700,10 @@ void tst_QQmlEngineDebugService::queryObject()
QCOMPARE(findProperty(text.properties, "color").value, qVariantFromValue(QColor("blue")));
} else {
- foreach (const QmlDebugObjectReference &child, obj.children)
+ foreach (const QmlDebugObjectReference &child, obj.children) {
+ QVERIFY(!child.className.isEmpty());
QCOMPARE(child.properties.count(), 0);
+ }
}
}
@@ -715,6 +722,7 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
bool success;
QmlDebugObjectReference rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
const QString fileName = QFileInfo(rootObject.source.url.toString()).fileName();
int lineNumber = rootObject.source.lineNumber;
@@ -737,6 +745,7 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
QCOMPARE(m_dbg->objects().count(), 1);
QmlDebugObjectReference obj = m_dbg->objects().first();
+ QVERIFY(!obj.className.isEmpty());
// check source as defined in main()
QmlDebugFileReference source = obj.source;
@@ -748,12 +757,15 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
recursiveObjectTest(m_rootItem, obj, recursive);
if (recursive) {
- foreach (const QmlDebugObjectReference &child, obj.children)
+ foreach (const QmlDebugObjectReference &child, obj.children) {
+ QVERIFY(!child.className.isEmpty());
QVERIFY(child.properties.count() > 0);
+ }
QmlDebugObjectReference rect;
QmlDebugObjectReference text;
foreach (const QmlDebugObjectReference &child, obj.children) {
+ QVERIFY(!child.className.isEmpty());
if (child.className == "Rectangle")
rect = child;
else if (child.className == "Text")
@@ -767,8 +779,10 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
QCOMPARE(findProperty(text.properties, "color").value, qVariantFromValue(QColor("blue")));
} else {
- foreach (const QmlDebugObjectReference &child, obj.children)
+ foreach (const QmlDebugObjectReference &child, obj.children) {
+ QVERIFY(!child.className.isEmpty());
QCOMPARE(child.properties.count(), 0);
+ }
}
}
@@ -783,6 +797,7 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation_data()
void tst_QQmlEngineDebugService::regression_QTCREATORBUG_7451()
{
QmlDebugObjectReference rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
int contextId = rootObject.contextDebugId;
QQmlContext *context = qobject_cast<QQmlContext *>(QQmlDebugService::objectForId(contextId));
QQmlComponent component(context->engine());
@@ -809,6 +824,7 @@ void tst_QQmlEngineDebugService::regression_QTCREATORBUG_7451()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
foreach (QmlDebugObjectReference child, rootObject.children) {
+ QVERIFY(!child.className.isEmpty());
success = false;
lineNumber = child.source.lineNumber;
columnNumber = child.source.columnNumber;
@@ -831,6 +847,7 @@ void tst_QQmlEngineDebugService::regression_QTCREATORBUG_7451()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
foreach (QmlDebugObjectReference child, rootObject.children) {
+ QVERIFY(!child.className.isEmpty());
success = false;
lineNumber = child.source.lineNumber;
columnNumber = child.source.columnNumber;
@@ -846,6 +863,7 @@ void tst_QQmlEngineDebugService::queryObjectWithNonStreamableTypes()
bool success;
QmlDebugObjectReference rootObject = findRootObject(4, true);
+ QVERIFY(!rootObject.className.isEmpty());
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
unconnected->queryObject(rootObject, &success);
@@ -857,6 +875,7 @@ void tst_QQmlEngineDebugService::queryObjectWithNonStreamableTypes()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QmlDebugObjectReference obj = m_dbg->object();
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties, "modelIndex").value, QVariant());
}
@@ -950,6 +969,7 @@ void tst_QQmlEngineDebugService::queryExpressionResultBC_data()
void tst_QQmlEngineDebugService::setBindingForObject()
{
QmlDebugObjectReference rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
QVERIFY(rootObject.debugId != -1);
QmlDebugPropertyReference widthPropertyRef = findProperty(rootObject.properties, "width");
@@ -967,6 +987,7 @@ void tst_QQmlEngineDebugService::setBindingForObject()
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
widthPropertyRef = findProperty(rootObject.properties, "width");
QCOMPARE(widthPropertyRef.value, QVariant(15));
@@ -982,6 +1003,7 @@ void tst_QQmlEngineDebugService::setBindingForObject()
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
widthPropertyRef = findProperty(rootObject.properties, "width");
QCOMPARE(widthPropertyRef.value, QVariant(20));
@@ -992,13 +1014,14 @@ void tst_QQmlEngineDebugService::setBindingForObject()
// set handler
//
rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
QCOMPARE(rootObject.children.size(), 5); // Rectangle, Text, MouseArea, Component.onCompleted, NonScriptPropertyElement
QmlDebugObjectReference mouseAreaObject = rootObject.children.at(2);
+ QVERIFY(!mouseAreaObject.className.isEmpty());
m_dbg->queryObjectRecursive(mouseAreaObject, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
mouseAreaObject = m_dbg->object();
-
QCOMPARE(mouseAreaObject.className, QString("MouseArea"));
QmlDebugPropertyReference onEnteredRef = findProperty(mouseAreaObject.properties, "onEntered");
@@ -1015,11 +1038,14 @@ void tst_QQmlEngineDebugService::setBindingForObject()
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
mouseAreaObject = rootObject.children.at(2);
+ QVERIFY(!mouseAreaObject.className.isEmpty());
m_dbg->queryObjectRecursive(mouseAreaObject, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
mouseAreaObject = m_dbg->object();
+ QVERIFY(!mouseAreaObject.className.isEmpty());
onEnteredRef = findProperty(mouseAreaObject.properties, "onEntered");
QCOMPARE(onEnteredRef.name, QString("onEntered"));
QCOMPARE(onEnteredRef.value, QVariant("function() { [code] }"));
@@ -1028,6 +1054,7 @@ void tst_QQmlEngineDebugService::setBindingForObject()
void tst_QQmlEngineDebugService::resetBindingForObject()
{
QmlDebugObjectReference rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
QVERIFY(rootObject.debugId != -1);
QmlDebugPropertyReference widthPropertyRef = findProperty(rootObject.properties, "width");
@@ -1048,6 +1075,7 @@ void tst_QQmlEngineDebugService::resetBindingForObject()
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
widthPropertyRef = findProperty(rootObject.properties, "width");
QCOMPARE(widthPropertyRef.value, QVariant(0));
@@ -1063,6 +1091,7 @@ void tst_QQmlEngineDebugService::resetBindingForObject()
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
+ QVERIFY(!rootObject.className.isEmpty());
QmlDebugPropertyReference boldPropertyRef = findProperty(rootObject.properties, "font.bold");
QCOMPARE(boldPropertyRef.value.toBool(), false);
@@ -1076,7 +1105,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
const int sourceIndex = 3;
QmlDebugObjectReference obj = findRootObject(sourceIndex);
-
+ QVERIFY(!obj.className.isEmpty());
QVERIFY(obj.debugId != -1);
QVERIFY(obj.children.count() >= 2);
bool success;
@@ -1092,6 +1121,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),200);
@@ -1102,6 +1132,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
obj = findRootObject(sourceIndex, true);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),100);
@@ -1111,6 +1142,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(state.children.count() > 0);
QmlDebugObjectReference propertyChange = state.children[0];
+ QVERIFY(!propertyChange.className.isEmpty());
QVERIFY(propertyChange.debugId != -1);
m_dbg->setBindingForObject(propertyChange.debugId, "width",QVariant(300),true,
@@ -1120,6 +1152,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
// check properties changed in state
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),100);
@@ -1128,6 +1161,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),300);
// check changing properties of base state from within a state
@@ -1141,6 +1175,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),300);
m_dbg->queryExpressionResult(obj.debugId,QString("state=\"\""), &success);
@@ -1148,6 +1183,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 400);
// reset binding while in a state
@@ -1156,6 +1192,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 300);
m_dbg->resetBindingForObject(propertyChange.debugId, "width", &success);
@@ -1164,6 +1201,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QCOMPARE(m_dbg->valid(), true);
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 400);
// re-add binding
@@ -1174,6 +1212,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QCOMPARE(m_dbg->valid(), true);
obj = findRootObject(sourceIndex);
+ QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 300);
}
@@ -1182,7 +1221,7 @@ void tst_QQmlEngineDebugService::queryObjectTree()
const int sourceIndex = 3;
QmlDebugObjectReference obj = findRootObject(sourceIndex, true);
-
+ QVERIFY(!obj.className.isEmpty());
QVERIFY(obj.debugId != -1);
QVERIFY(obj.children.count() >= 2);
@@ -1192,16 +1231,16 @@ void tst_QQmlEngineDebugService::queryObjectTree()
QVERIFY(state.children.count() > 0);
QmlDebugObjectReference propertyChange = state.children[0];
+ QVERIFY(!propertyChange.className.isEmpty());
QVERIFY(propertyChange.debugId != -1);
QmlDebugPropertyReference propertyChangeTarget = findProperty(propertyChange.properties,"target");
QCOMPARE(propertyChangeTarget.objectDebugId, propertyChange.debugId);
QmlDebugObjectReference targetReference = qvariant_cast<QmlDebugObjectReference>(propertyChangeTarget.value);
+ QVERIFY(!targetReference.className.isEmpty());
QVERIFY(targetReference.debugId != -1);
-
-
// check transition
QmlDebugObjectReference transition = obj.children[0];
QCOMPARE(transition.className, QString("Transition"));
@@ -1210,12 +1249,14 @@ void tst_QQmlEngineDebugService::queryObjectTree()
QVERIFY(transition.children.count() > 0);
QmlDebugObjectReference animation = transition.children[0];
+ QVERIFY(!animation.className.isEmpty());
QVERIFY(animation.debugId != -1);
QmlDebugPropertyReference animationTarget = findProperty(animation.properties,"target");
QCOMPARE(animationTarget.objectDebugId, animation.debugId);
targetReference = qvariant_cast<QmlDebugObjectReference>(animationTarget.value);
+ QVERIFY(!targetReference.className.isEmpty());
QVERIFY(targetReference.debugId != -1);
QCOMPARE(findProperty(animation.properties,"property").value.toString(), QString("width"));
diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
index 6d0d884ed7..584bd10151 100644
--- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
+++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
@@ -315,8 +315,8 @@ private slots:
void stepToEndOfScript_data() { redundancy_data(); }
void stepToEndOfScript();
- void lastLineOfLoop_data();
- void lastLineOfLoop();
+ void lastLineOfConditional_data();
+ void lastLineOfConditional();
private:
QV4Debugger *debugger() const
{
@@ -801,32 +801,60 @@ void tst_qv4debugger::stepToEndOfScript()
QCOMPARE(state.lineNumber, -4); // A return instruction without proper line number.
}
-void tst_qv4debugger::lastLineOfLoop_data()
+void tst_qv4debugger::lastLineOfConditional_data()
{
- QTest::addColumn<QString>("loopHead");
- QTest::addColumn<QString>("loopTail");
-
- QTest::newRow("for") << "for (var i = 0; i < 10; ++i) {\n" << "}\n";
- QTest::newRow("for..in") << "for (var i in [0, 1, 2, 3, 4]) {\n" << "}\n";
- QTest::newRow("while") << "while (ret < 10) {\n" << "}\n";
- QTest::newRow("do..while") << "do {\n" << "} while (ret < 10);\n";
+ QTest::addColumn<QString>("head");
+ QTest::addColumn<QString>("tail");
+ QTest::addColumn<int>("breakPoint");
+ QTest::addColumn<int>("lastLine");
+
+ QTest::newRow("for {block}") << "for (var i = 0; i < 10; ++i) {\n" << "}" << 4 << 7;
+ QTest::newRow("for..in {block}") << "for (var i in [0, 1, 2, 3, 4]) {\n" << "}" << 4 << 7;
+ QTest::newRow("while {block}") << "while (ret < 10) {\n" << "}" << 4 << 7;
+ QTest::newRow("do..while {block}") << "do {\n" << "} while (ret < 10);" << 4 << 7;
+
+ QTest::newRow("if true {block}") << "if (true) {\n" << "}"
+ << 4 << 7;
+ QTest::newRow("if false {block}") << "if (false) {\n" << "}"
+ << 2 << 8;
+ QTest::newRow("if true else {block}") << "if (true) {\n" << "} else {\n ret += 8;\n}"
+ << 4 << 7;
+ QTest::newRow("if false else {block}") << "if (false) {\n" << "} else {\n ret += 8;\n}"
+ << 8 << 9;
+
+ QTest::newRow("for statement") << "for (var i = 0; i < 10; ++i)\n" << "" << 4 << 2;
+ QTest::newRow("for..in statement") << "for (var i in [0, 1, 2, 3, 4])\n" << "" << 4 << 2;
+ QTest::newRow("while statement") << "while (ret < 10)\n" << "" << 4 << 2;
+ QTest::newRow("do..while statement") << "do\n" << "while (ret < 10);" << 4 << 7;
+
+ // For two nested if statements without blocks, we need to map the jump from the inner to the
+ // outer one on the outer "if". There is just no better place.
+ QTest::newRow("if true statement") << "if (true)\n" << "" << 4 << 2;
+ QTest::newRow("if false statement") << "if (false)\n" << "" << 2 << 8;
+
+ // Also two nested ifs without blocks.
+ QTest::newRow("if true else statement") << "if (true)\n" << "else\n ret += 8;" << 4 << 2;
+ QTest::newRow("if false else statement") << "if (false)\n" << "else\n ret += 8;" << 8 << 9;
}
-void tst_qv4debugger::lastLineOfLoop()
+void tst_qv4debugger::lastLineOfConditional()
{
- QFETCH(QString, loopHead);
- QFETCH(QString, loopTail);
+ QFETCH(QString, head);
+ QFETCH(QString, tail);
+ QFETCH(int, breakPoint);
+ QFETCH(int, lastLine);
QString script =
- "var ret = 0;\n"
- + loopHead +
+ "var ret = 2;\n"
+ + head +
" if (ret == 2)\n"
" ret += 4;\n" // breakpoint, then step over
- " else \n"
+ " else\n"
" ret += 1;\n"
- + loopTail;
+ + tail + "\n" +
+ "ret -= 5;";
- debugger()->addBreakPoint("trueBranch", 4);
+ debugger()->addBreakPoint("trueBranch", breakPoint);
m_debuggerAgent->m_resumeSpeed = QV4Debugger::StepOver;
evaluateJavaScript(script, "trueBranch");
QVERIFY(m_debuggerAgent->m_wasPaused);
@@ -834,10 +862,10 @@ void tst_qv4debugger::lastLineOfLoop()
QVERIFY(m_debuggerAgent->m_statesWhenPaused.count() > 1);
QV4Debugger::ExecutionState firstState = m_debuggerAgent->m_statesWhenPaused.first();
QCOMPARE(firstState.fileName, QString("trueBranch"));
- QCOMPARE(firstState.lineNumber, 4);
+ QCOMPARE(firstState.lineNumber, breakPoint);
QV4Debugger::ExecutionState secondState = m_debuggerAgent->m_statesWhenPaused.at(1);
QCOMPARE(secondState.fileName, QString("trueBranch"));
- QCOMPARE(secondState.lineNumber, 7);
+ QCOMPARE(secondState.lineNumber, lastLine);
}
void tst_qv4debugger::redundancy_data()
diff --git a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp
index 3e27951d78..c0252a0290 100644
--- a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp
+++ b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp
@@ -386,6 +386,7 @@ void QQmlEngineDebugClient::decode(QPacket &ds,
{
QmlDebugObjectReference obj;
obj.debugId = prop.value.toInt();
+ obj.className = prop.valueTypeName;
prop.value = qVariantFromValue(obj);
break;
}
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 39f6d80fa0..a3a2efd565 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -29,6 +29,7 @@
#include <QtTest/QtTest>
+#include <private/qqmldata_p.h>
#include <qjsengine.h>
#include <qjsvalueiterator.h>
#include <qgraphicsitem.h>
@@ -73,6 +74,7 @@ private slots:
void newQObject();
void newQObject_ownership();
void newQObject_deletedEngine();
+ void newQObjectPropertyCache();
void newQMetaObject();
void exceptionInSlot();
void globalObjectProperties();
@@ -749,6 +751,19 @@ private:
int m_called;
};
+void tst_QJSEngine::newQObjectPropertyCache()
+{
+ QScopedPointer<QObject> obj(new QObject);
+ QQmlEngine::setObjectOwnership(obj.data(), QQmlEngine::CppOwnership);
+
+ {
+ QJSEngine engine;
+ engine.newQObject(obj.data());
+ QVERIFY(QQmlData::get(obj.data())->propertyCache);
+ }
+ QVERIFY(!QQmlData::get(obj.data())->propertyCache);
+}
+
void tst_QJSEngine::newQMetaObject() {
{
QJSEngine engine;
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index 007eb0dc83..59566ad927 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -36,6 +36,7 @@ PRIVATETESTS += \
qqmlcpputils \
qqmldirparser \
v4misc \
+ qmlcachegen
!boot2qt {
PRIVATETESTS += \
diff --git a/tests/auto/qml/qmlcachegen/qmlcachegen.pro b/tests/auto/qml/qmlcachegen/qmlcachegen.pro
new file mode 100644
index 0000000000..8d8b37be15
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/qmlcachegen.pro
@@ -0,0 +1,7 @@
+CONFIG += testcase
+TARGET = tst_qmlcachegen
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_qmlcachegen.cpp
+
+QT += core-private qml-private testlib
diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
new file mode 100644
index 0000000000..b7e616a050
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+
+#include <QQmlComponent>
+#include <QQmlEngine>
+#include <QProcess>
+#include <QLibraryInfo>
+#include <QSysInfo>
+
+class tst_qmlcachegen: public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+
+ void loadGeneratedFile();
+ void translationExpressionSupport();
+};
+
+// A wrapper around QQmlComponent to ensure the temporary reference counts
+// on the type data as a result of the main thread <> loader thread communication
+// are dropped. Regular Synchronous loading will leave us with an event posted
+// to the gui thread and an extra refcount that will only be dropped after the
+// event delivery. A plain sendPostedEvents() however is insufficient because
+// we can't be sure that the event is posted after the constructor finished.
+class CleanlyLoadingComponent : public QQmlComponent
+{
+public:
+ CleanlyLoadingComponent(QQmlEngine *engine, const QUrl &url)
+ : QQmlComponent(engine, url, QQmlComponent::Asynchronous)
+ { waitForLoad(); }
+ CleanlyLoadingComponent(QQmlEngine *engine, const QString &fileName)
+ : QQmlComponent(engine, fileName, QQmlComponent::Asynchronous)
+ { waitForLoad(); }
+
+ void waitForLoad()
+ {
+ QTRY_VERIFY(status() == QQmlComponent::Ready || status() == QQmlComponent::Error);
+ }
+};
+
+static bool generateCache(const QString &qmlFileName)
+{
+ QProcess proc;
+ proc.setProcessChannelMode(QProcess::ForwardedChannels);
+ proc.setProgram(QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator() + QLatin1String("qmlcachegen"));
+ proc.setArguments(QStringList() << (QLatin1String("--target-architecture=") + QSysInfo::buildCpuArchitecture()) << (QLatin1String("--target-abi=") + QSysInfo::buildAbi()) << qmlFileName);
+ proc.start();
+ if (!proc.waitForFinished())
+ return false;
+ if (proc.exitStatus() != QProcess::NormalExit)
+ return false;
+ return proc.exitCode() == 0;
+}
+
+void tst_qmlcachegen::initTestCase()
+{
+ qputenv("QML_FORCE_DISK_CACHE", "1");
+}
+
+void tst_qmlcachegen::loadGeneratedFile()
+{
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+
+ const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
+ QFile f(tempDir.path() + '/' + fileName);
+ const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ Q_ASSERT(ok);
+ f.write(contents);
+ return f.fileName();
+ };
+
+ const QString testFilePath = writeTempFile("test.qml", "import QtQml 2.0\n"
+ "QtObject {\n"
+ " property int value: Math.min(100, 42);\n"
+ "}");
+
+ QVERIFY(generateCache(testFilePath));
+
+ const QString cacheFilePath = testFilePath + QLatin1Char('c');
+ QVERIFY(QFile::exists(cacheFilePath));
+ QVERIFY(QFile::remove(testFilePath));
+
+ QQmlEngine engine;
+ CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("value").toInt(), 42);
+}
+
+void tst_qmlcachegen::translationExpressionSupport()
+{
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+
+ const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
+ QFile f(tempDir.path() + '/' + fileName);
+ const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ Q_ASSERT(ok);
+ f.write(contents);
+ return f.fileName();
+ };
+
+ const QString testFilePath = writeTempFile("test.qml", "import QtQml.Models 2.2\n"
+ "import QtQml 2.2\n"
+ "QtObject {\n"
+ " property ListModel model: ListModel {\n"
+ " ListElement {\n"
+ " text: qsTr(\"All\")\n"
+ " }\n"
+ " ListElement {\n"
+ " text: QT_TR_NOOP(\"Ok\")\n"
+ " }\n"
+ " }\n"
+ " property string text: model.get(0).text + \" \" + model.get(1).text\n"
+ "}");
+
+
+ QVERIFY(generateCache(testFilePath));
+
+ const QString cacheFilePath = testFilePath + QLatin1Char('c');
+ QVERIFY(QFile::exists(cacheFilePath));
+ QVERIFY(QFile::remove(testFilePath));
+
+ QQmlEngine engine;
+ CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("text").toString(), QString("All Ok"));
+}
+
+QTEST_GUILESS_MAIN(tst_qmlcachegen)
+
+#include "tst_qmlcachegen.moc"
diff --git a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp
index 838966e2a0..68e11e3551 100644
--- a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp
+++ b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp
@@ -105,12 +105,12 @@ void tst_qmlplugindump::singleton()
args << QLatin1String("tests.dumper.CompositeSingleton") << QLatin1String("1.0")
<< QLatin1String(".");
dumper.start(qmlplugindumpPath, args);
- dumper.waitForFinished();
+ QVERIFY2(dumper.waitForStarted(), qPrintable(dumper.errorString()));
+ QVERIFY2(dumper.waitForFinished(), qPrintable(dumper.errorString()));
const QString &result = dumper.readAllStandardOutput();
- qDebug() << "result: " << result;
- QVERIFY(result.contains(QLatin1String("exports: [\"Singleton 1.0\"]")));
- QVERIFY(result.contains(QLatin1String("exportMetaObjectRevisions: [0]")));
+ QVERIFY2(result.contains(QLatin1String("exports: [\"Singleton 1.0\"]")), qPrintable(result));
+ QVERIFY2(result.contains(QLatin1String("exportMetaObjectRevisions: [0]")), qPrintable(result));
}
QTEST_MAIN(tst_qmlplugindump)
diff --git a/tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml b/tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml
new file mode 100644
index 0000000000..462a9577ff
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.4
+
+Item {
+ id: blaBlaBla
+ function hint() {
+ }
+
+ Connections {
+ //target: blaBlaBla
+ //onHint: hint();
+ on: true
+ }
+}
+
+
diff --git a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
index b3ac1ce958..1ed94fcb93 100644
--- a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
+++ b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
@@ -53,6 +53,7 @@ private slots:
void singletonTypeTarget();
void enableDisable_QTBUG_36350();
void clearImplicitTarget();
+ void onWithoutASignal();
private:
QQmlEngine engine;
@@ -379,6 +380,15 @@ void tst_qqmlconnections::clearImplicitTarget()
delete item;
}
+void tst_qqmlconnections::onWithoutASignal()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("connection-no-signal-name.qml"));
+ QVERIFY(c.isError()); // Cannot assign to non-existent property "on" expected
+ QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(c.create()));
+ QVERIFY(item == nullptr); // should parse error, and not give us an item (or crash).
+}
+
QTEST_MAIN(tst_qqmlconnections)
#include "tst_qqmlconnections.moc"
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceSort.qml b/tests/auto/qml/qqmlecmascript/data/sequenceSort.qml
index 74c7cda9a3..c6732efc05 100644
--- a/tests/auto/qml/qqmlecmascript/data/sequenceSort.qml
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceSort.qml
@@ -52,7 +52,11 @@ Item {
function doStringTest(stringList, fn) {
var expected = createExpected(stringList, fn);
var actual = msc.strings(stringList);
- return checkResults(expected, actual, fn);
+ var actual2 = msc.stringsVector(stringList);
+ var actual3 = msc.stringsStdVector(stringList);
+ return checkResults(expected, actual, fn)
+ && checkResults(expected, actual2, fn)
+ && checkResults(expected, actual3, fn)
}
function doIntTest(intList, fn) {
var expected = createExpected(intList, fn);
@@ -67,12 +71,16 @@ Item {
function doIntVectorTest(intList, fn) {
var expected = createExpected(intList, fn);
var actual = msc.integerVector(intList);
- return checkResults(expected, actual, fn);
+ var actual2 = msc.integerStdVector(intList);
+ return checkResults(expected, actual, fn)
+ && checkResults(expected, actual2, fn)
}
function doRealVectorTest(realList, fn) {
var expected = createExpected(realList, fn);
var actual = msc.realVector(realList);
- return checkResults(expected, actual, fn);
+ var actual2 = msc.realStdVector(realList);
+ return checkResults(expected, actual, fn)
+ && checkResults(expected, actual2, fn)
}
function test_qtbug_25269(useCustomCompare) {
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp
index 63c2918325..c4692fdf31 100644
--- a/tests/auto/qml/qqmlecmascript/testtypes.cpp
+++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp
@@ -283,6 +283,15 @@ public:
{
return stringList;
}
+ Q_INVOKABLE QVector<QString> stringsVector(const QStringList& stringList) const
+ {
+ return stringList.toVector();
+ }
+ Q_INVOKABLE
+ std::vector<QString> stringsStdVector(const QStringList& stringList) const
+ {
+ return std::vector<QString>(stringList.begin(), stringList.end());
+ }
Q_INVOKABLE QList<int> integers(QList<int> v) const
{
return v;
@@ -299,14 +308,29 @@ public:
{
return v;
}
+ Q_INVOKABLE
+ std::vector<int> integerStdVector(std::vector<int> v) const
+ {
+ return v;
+ }
Q_INVOKABLE QVector<qreal> realVector(QVector<qreal> v) const
{
return v;
}
+ Q_INVOKABLE
+ std::vector<qreal> realStdVector(std::vector<qreal> v) const
+ {
+ return v;
+ }
Q_INVOKABLE QVector<bool> boolVector(QVector<bool> v) const
{
return v;
}
+ Q_INVOKABLE
+ std::vector<bool> boolStdVector(std::vector<bool> v) const
+ {
+ return v;
+ }
};
static MyInheritedQmlObject *theSingletonObject = 0;
diff --git a/tests/auto/qml/qqmlengine/data/testGCCorruption.qml b/tests/auto/qml/qqmlengine/data/testGCCorruption.qml
new file mode 100644
index 0000000000..8728b9b915
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/testGCCorruption.qml
@@ -0,0 +1,29 @@
+import QtQml 2.0
+
+QtObject {
+ id: root
+ property int count: 10000;
+ property var items: [];
+
+ property Component component: Component {
+ id: component;
+ QtObject {
+ }
+ }
+
+ property int iterations: 0
+ Component.onCompleted: {
+ for (var iterations = 0; iterations < 5; ++iterations) {
+ for (var i=0; i<items.length; ++i) {
+ items[i].destroy();
+ }
+
+ for (var i=0; i<root.count; ++i) {
+ var object = component.createObject();
+ items[i] = object
+ }
+ }
+
+ // if we crash, then something bad has happened. :)
+ }
+}
diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
index e170920486..3f6107ab2b 100644
--- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
+++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
@@ -70,8 +70,8 @@ private slots:
void qtqmlModule();
void urlInterceptor_data();
void urlInterceptor();
-
void qmlContextProperties();
+ void testGCCorruption();
public slots:
QObject *createAQObjectForOwnershipTest ()
@@ -836,6 +836,15 @@ void tst_qqmlengine::qmlContextProperties()
QVERIFY(o);
}
+void tst_qqmlengine::testGCCorruption()
+{
+ QQmlEngine e;
+
+ QQmlComponent c(&e, testFileUrl("testGCCorruption.qml"));
+ QObject *o = c.create();
+ QVERIFY2(o, qPrintable(c.errorString()));
+}
+
QTEST_MAIN(tst_qqmlengine)
#include "tst_qqmlengine.moc"
diff --git a/tests/auto/qmltest/animatedimage/animatedimage.pro b/tests/auto/qmltest/animatedimage/animatedimage.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/animatedimage/animatedimage.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/animations/animations.pro b/tests/auto/qmltest/animations/animations.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/animations/animations.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/borderimage/borderimage.pro b/tests/auto/qmltest/borderimage/borderimage.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/borderimage/borderimage.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/buttonclick/buttonclick.pro b/tests/auto/qmltest/buttonclick/buttonclick.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/buttonclick/buttonclick.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/createbenchmark/createbenchmark.pro b/tests/auto/qmltest/createbenchmark/createbenchmark.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/createbenchmark/createbenchmark.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/events/events.pro b/tests/auto/qmltest/events/events.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/events/events.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/fontloader/fontloader.pro b/tests/auto/qmltest/fontloader/fontloader.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/fontloader/fontloader.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/gradient/gradient.pro b/tests/auto/qmltest/gradient/gradient.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/gradient/gradient.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/image/image.pro b/tests/auto/qmltest/image/image.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/image/image.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/itemgrabber/itemgrabber.pro b/tests/auto/qmltest/itemgrabber/itemgrabber.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/itemgrabber/itemgrabber.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml b/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml
index a80814d6de..53ed3658c2 100644
--- a/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml
+++ b/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml
@@ -135,7 +135,7 @@ Item {
property int callCount: 0;
property bool ready: false;
function handleGrab(result) {
- if (!result.saveToFile("itemgrabber/image.png"))
+ if (!result.saveToFile("image.png"))
print("Error: Failed to save image to disk...");
source = "image.png";
ready = true;
@@ -149,7 +149,7 @@ Item {
y: 0
property bool ready: false;
function handleGrab(result) {
- if (!result.saveToFile("itemgrabber/image_small.png"))
+ if (!result.saveToFile("image_small.png"))
print("Error: Failed to save image to disk...");
source = "image_small.png";
ready = true;
diff --git a/tests/auto/qmltest/layout/layout.pro b/tests/auto/qmltest/layout/layout.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/layout/layout.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/listmodel/listmodel.pro b/tests/auto/qmltest/listmodel/listmodel.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/listmodel/listmodel.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/listview/BLACKLIST b/tests/auto/qmltest/listview/BLACKLIST
new file mode 100644
index 0000000000..083e2f8978
--- /dev/null
+++ b/tests/auto/qmltest/listview/BLACKLIST
@@ -0,0 +1,4 @@
+# Blacklist for testing
+[ListView::test_listInteractiveCurrentIndexEnforce]
+linux
+macos-10.12
diff --git a/tests/auto/qmltest/listview/listview.pro b/tests/auto/qmltest/listview/listview.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/listview/listview.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/objectmodel/objectmodel.pro b/tests/auto/qmltest/objectmodel/objectmodel.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/objectmodel/objectmodel.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/pathview/pathview.pro b/tests/auto/qmltest/pathview/pathview.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/pathview/pathview.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/pixel/pixel.pro b/tests/auto/qmltest/pixel/pixel.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/pixel/pixel.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/positioners/positioners.pro b/tests/auto/qmltest/positioners/positioners.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/positioners/positioners.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/qmltest.pro b/tests/auto/qmltest/qmltest.pro
index 52fd6bf9de..8ad1541cbc 100644
--- a/tests/auto/qmltest/qmltest.pro
+++ b/tests/auto/qmltest/qmltest.pro
@@ -1,14 +1,30 @@
-TEMPLATE=app
-TARGET=tst_qmltest
-CONFIG += qmltestcase
-CONFIG += console
-SOURCES += tst_qmltest.cpp
-
-
-importFiles.files = borderimage buttonclick createbenchmark events qqmlbinding selftests
-
-importFiles.path = .
-DEPLOYMENT += importFiles
-
-# Please do not make this test insignificant again, thanks.
-# Just skip those unstable ones. See also QTBUG-33723.
+TEMPLATE = subdirs
+SUBDIRS += \
+ animatedimage \
+ animations \
+ borderimage \
+ buttonclick \
+ createbenchmark \
+ events \
+ fontloader \
+ gradient \
+ image \
+ itemgrabber \
+ layout \
+ listmodel \
+ listview \
+ objectmodel \
+ pathview \
+ pixel \
+ positioners \
+ qqmlbinding \
+ qtbug46798 \
+ rectangle \
+ selftests \
+ shadersource \
+ stability \
+ statemachine \
+ text \
+ textedit \
+ textinput \
+ window
diff --git a/tests/auto/qmltest/qqmlbinding/qqmlbinding.pro b/tests/auto/qmltest/qqmlbinding/qqmlbinding.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/qqmlbinding/qqmlbinding.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/qtbug46798/qtbug46798.pro b/tests/auto/qmltest/qtbug46798/qtbug46798.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/qtbug46798/qtbug46798.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/rectangle/rectangle.pro b/tests/auto/qmltest/rectangle/rectangle.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/rectangle/rectangle.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/BLACKLIST b/tests/auto/qmltest/selftests/BLACKLIST
index d324e9da5d..9cb2313810 100644
--- a/tests/auto/qmltest/BLACKLIST
+++ b/tests/auto/qmltest/selftests/BLACKLIST
@@ -3,10 +3,6 @@
*
[SelfTests::test_blacklistWithData:test2]
*
-[shadersource-dynamic-sourceobject::test_endresult]
-linux
+# QTBUG-53793: seems to be failing on Linux a little too often...
[tst_grabImage::test_equals]
linux
-[ListView::test_listInteractiveCurrentIndexEnforce]
-linux
-macos-10.12
diff --git a/tests/auto/qmltest/selftests/selftests.pro b/tests/auto/qmltest/selftests/selftests.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/selftests/selftests.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/selftests/tst_grabImage.qml b/tests/auto/qmltest/selftests/tst_grabImage.qml
index 1748030f14..954daaba42 100644
--- a/tests/auto/qmltest/selftests/tst_grabImage.qml
+++ b/tests/auto/qmltest/selftests/tst_grabImage.qml
@@ -35,7 +35,7 @@ TestCase {
when: windowShown
function test_equals() {
- var rect = Qt.createQmlObject("import QtQuick 2.0; Rectangle { color: 'red'; width: 10; height: 10; }", testCase);
+ var rect = createTemporaryQmlObject("import QtQuick 2.0; Rectangle { color: 'red'; width: 10; height: 10; }", testCase);
verify(rect);
var oldImage = grabImage(rect);
rect.width += 10;
diff --git a/tests/auto/qmltest/selftests/tst_selftests.qml b/tests/auto/qmltest/selftests/tst_selftests.qml
index 439ea7a70d..5555876014 100644
--- a/tests/auto/qmltest/selftests/tst_selftests.qml
+++ b/tests/auto/qmltest/selftests/tst_selftests.qml
@@ -167,6 +167,16 @@ TestCase {
caught = true
}
verify(caught)
+
+ caught = false;
+ try {
+ testCase.verify(true, "foo", "bar")
+ } catch (e) {
+ compare(e.message, "QtQuickTest::fail")
+ compare(functions.failmsg, "More than two arguments given to verify(). Did you mean tryVerify() or tryCompare()?")
+ caught = true
+ }
+ verify(caught)
}
function test_compare() {
diff --git a/tests/auto/qmltest/shadersource/BLACKLIST b/tests/auto/qmltest/shadersource/BLACKLIST
new file mode 100644
index 0000000000..cc1e110153
--- /dev/null
+++ b/tests/auto/qmltest/shadersource/BLACKLIST
@@ -0,0 +1,3 @@
+# Blacklist for testing
+[shadersource-dynamic-sourceobject::test_endresult]
+linux
diff --git a/tests/auto/qmltest/shadersource/shadersource.pro b/tests/auto/qmltest/shadersource/shadersource.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/shadersource/shadersource.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/stability/stability.pro b/tests/auto/qmltest/stability/stability.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/stability/stability.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/statemachine/statemachine.pro b/tests/auto/qmltest/statemachine/statemachine.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/statemachine/statemachine.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/text/text.pro b/tests/auto/qmltest/text/text.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/text/text.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/textedit/BLACKLIST b/tests/auto/qmltest/textedit/BLACKLIST
new file mode 100644
index 0000000000..08a86c1b89
--- /dev/null
+++ b/tests/auto/qmltest/textedit/BLACKLIST
@@ -0,0 +1,6 @@
+# Blacklist for testing
+[TextEdit::test_textentry]
+macos-10.12
+[TextEdit::test_textentry_char]
+macos-10.12
+
diff --git a/tests/auto/qmltest/textedit/textedit.pro b/tests/auto/qmltest/textedit/textedit.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/textedit/textedit.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/textinput/textinput.pro b/tests/auto/qmltest/textinput/textinput.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/textinput/textinput.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/qmltest/tst_qmltest.cpp b/tests/auto/qmltest/tst_qmltest.cpp
deleted file mode 100644
index 3387ce8ee9..0000000000
--- a/tests/auto/qmltest/tst_qmltest.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtQuickTest/quicktest.h>
-QUICK_TEST_MAIN(qmltest) \ No newline at end of file
diff --git a/tests/auto/qmltest/window/window.pro b/tests/auto/qmltest/window/window.pro
new file mode 100644
index 0000000000..a7938e7003
--- /dev/null
+++ b/tests/auto/qmltest/window/window.pro
@@ -0,0 +1 @@
+CONFIG += qmltestcase
diff --git a/tests/auto/quick/qquickapplication/BLACKLIST b/tests/auto/quick/qquickapplication/BLACKLIST
new file mode 100644
index 0000000000..81592db56f
--- /dev/null
+++ b/tests/auto/quick/qquickapplication/BLACKLIST
@@ -0,0 +1,2 @@
+[active]
+osx-10.11
diff --git a/tests/auto/quick/qquickflickable/BLACKLIST b/tests/auto/quick/qquickflickable/BLACKLIST
index 647bf819a5..f35397f119 100644
--- a/tests/auto/quick/qquickflickable/BLACKLIST
+++ b/tests/auto/quick/qquickflickable/BLACKLIST
@@ -17,3 +17,5 @@ osx
osx-10.10
[flickVelocity]
osx-10.10
+[nestedSliderUsingTouch:keepNeither]
+ubuntu-16.04
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
index 3ecebfb48f..ef6e444580 100644
--- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
+++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
@@ -63,9 +63,7 @@ public:
, touchReleases(0)
, ungrabs(0)
, m_active(false)
- {
- setFlags(ItemAcceptsDrops);
- }
+ { }
QPointF pos() const { return m_pos; }
@@ -2044,10 +2042,10 @@ void tst_qquickflickable::nestedSliderUsingTouch()
QCOMPARE(tda->active(), !ungrabs);
QTest::touchEvent(window, touchDevice).release(0, p0, window);
QQuickTouchUtils::flush(window);
- QCOMPARE(tda->touchPointStates.first(), Qt::TouchPointPressed);
- QCOMPARE(tda->touchUpdates, updates);
- QCOMPARE(tda->touchReleases, releases);
- QCOMPARE(tda->ungrabs, ungrabs);
+ QTRY_COMPARE(tda->touchPointStates.first(), Qt::TouchPointPressed);
+ QTRY_COMPARE(tda->touchUpdates, updates);
+ QTRY_COMPARE(tda->touchReleases, releases);
+ QTRY_COMPARE(tda->ungrabs, ungrabs);
}
// QTBUG-31328
@@ -2218,6 +2216,7 @@ Q_DECLARE_METATYPE(QQuickFlickable::BoundsBehavior)
void tst_qquickflickable::overshoot()
{
QFETCH(QQuickFlickable::BoundsBehavior, boundsBehavior);
+ QFETCH(int, boundsMovement);
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("overshoot.qml"));
@@ -2234,6 +2233,7 @@ void tst_qquickflickable::overshoot()
QCOMPARE(flickable->contentHeight(), 400.0);
flickable->setBoundsBehavior(boundsBehavior);
+ flickable->setBoundsMovement(QQuickFlickable::BoundsMovement(boundsMovement));
// drag past the beginning
QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(10, 10));
@@ -2242,23 +2242,30 @@ void tst_qquickflickable::overshoot()
QTest::mouseMove(window.data(), QPoint(40, 40));
QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(50, 50));
+ if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::DragOverBounds)) {
+ QVERIFY(flickable->property("minContentX").toReal() < 0.0);
+ QVERIFY(flickable->property("minContentY").toReal() < 0.0);
+ } else {
+ QCOMPARE(flickable->property("minContentX").toReal(), 0.0);
+ QCOMPARE(flickable->property("minContentY").toReal(), 0.0);
+ }
if (boundsBehavior & QQuickFlickable::DragOverBounds) {
- QVERIFY(flickable->property("minVerticalOvershoot").toReal() < 0.0);
QVERIFY(flickable->property("minHorizontalOvershoot").toReal() < 0.0);
- QCOMPARE(flickable->property("minContentY").toReal(),
- flickable->property("minVerticalOvershoot").toReal());
- QCOMPARE(flickable->property("minContentX").toReal(),
- flickable->property("minHorizontalOvershoot").toReal());
+ QVERIFY(flickable->property("minVerticalOvershoot").toReal() < 0.0);
} else {
- QCOMPARE(flickable->property("minContentY").toReal(), 0.0);
- QCOMPARE(flickable->property("minContentX").toReal(), 0.0);
- QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
QCOMPARE(flickable->property("minHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
+ }
+ if (bool(boundsMovement == QQuickFlickable::FollowBoundsBehavior) == bool(boundsBehavior & QQuickFlickable::DragOverBounds)) {
+ QCOMPARE(flickable->property("minContentX").toReal(),
+ flickable->property("minHorizontalOvershoot").toReal());
+ QCOMPARE(flickable->property("minContentY").toReal(),
+ flickable->property("minVerticalOvershoot").toReal());
}
- QCOMPARE(flickable->property("maxContentY").toReal(), 0.0);
QCOMPARE(flickable->property("maxContentX").toReal(), 0.0);
- QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("maxContentY").toReal(), 0.0);
QCOMPARE(flickable->property("maxHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
flickable->setContentX(20.0);
flickable->setContentY(20.0);
@@ -2268,23 +2275,30 @@ void tst_qquickflickable::overshoot()
flick(window.data(), QPoint(10, 10), QPoint(50, 50), 100);
QTRY_VERIFY(!flickable->property("flicking").toBool());
+ if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::OvershootBounds)) {
+ QVERIFY(flickable->property("minContentX").toReal() < 0.0);
+ QVERIFY(flickable->property("minContentY").toReal() < 0.0);
+ } else {
+ QCOMPARE(flickable->property("minContentX").toReal(), 0.0);
+ QCOMPARE(flickable->property("minContentY").toReal(), 0.0);
+ }
if (boundsBehavior & QQuickFlickable::OvershootBounds) {
- QVERIFY(flickable->property("minVerticalOvershoot").toReal() < 0.0);
QVERIFY(flickable->property("minHorizontalOvershoot").toReal() < 0.0);
- QCOMPARE(flickable->property("minContentY").toReal(),
- flickable->property("minVerticalOvershoot").toReal());
- QCOMPARE(flickable->property("minContentX").toReal(),
- flickable->property("minHorizontalOvershoot").toReal());
+ QVERIFY(flickable->property("minVerticalOvershoot").toReal() < 0.0);
} else {
- QCOMPARE(flickable->property("minContentY").toReal(), 0.0);
- QCOMPARE(flickable->property("minContentX").toReal(), 0.0);
- QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
QCOMPARE(flickable->property("minHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
+ }
+ if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) == (boundsBehavior & QQuickFlickable::OvershootBounds)) {
+ QCOMPARE(flickable->property("minContentX").toReal(),
+ flickable->property("minHorizontalOvershoot").toReal());
+ QCOMPARE(flickable->property("minContentY").toReal(),
+ flickable->property("minVerticalOvershoot").toReal());
}
- QCOMPARE(flickable->property("maxContentY").toReal(), 20.0);
QCOMPARE(flickable->property("maxContentX").toReal(), 20.0);
- QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("maxContentY").toReal(), 20.0);
QCOMPARE(flickable->property("maxHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
flickable->setContentX(200.0);
flickable->setContentY(200.0);
@@ -2297,23 +2311,30 @@ void tst_qquickflickable::overshoot()
QTest::mouseMove(window.data(), QPoint(20, 20));
QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(10, 10));
+ if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::DragOverBounds)) {
+ QVERIFY(flickable->property("maxContentX").toReal() > 200.0);
+ QVERIFY(flickable->property("maxContentX").toReal() > 200.0);
+ } else {
+ QCOMPARE(flickable->property("maxContentX").toReal(), 200.0);
+ QCOMPARE(flickable->property("maxContentY").toReal(), 200.0);
+ }
if (boundsBehavior & QQuickFlickable::DragOverBounds) {
- QVERIFY(flickable->property("maxVerticalOvershoot").toReal() > 0.0);
QVERIFY(flickable->property("maxHorizontalOvershoot").toReal() > 0.0);
- QCOMPARE(flickable->property("maxContentY").toReal() - 200.0,
- flickable->property("maxVerticalOvershoot").toReal());
- QCOMPARE(flickable->property("maxContentX").toReal() - 200.0,
- flickable->property("maxHorizontalOvershoot").toReal());
+ QVERIFY(flickable->property("maxVerticalOvershoot").toReal() > 0.0);
} else {
- QCOMPARE(flickable->property("maxContentY").toReal(), 200.0);
- QCOMPARE(flickable->property("maxContentX").toReal(), 200.0);
- QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
QCOMPARE(flickable->property("maxHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
+ }
+ if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) == (boundsBehavior & QQuickFlickable::DragOverBounds)) {
+ QCOMPARE(flickable->property("maxContentX").toReal() - 200.0,
+ flickable->property("maxHorizontalOvershoot").toReal());
+ QCOMPARE(flickable->property("maxContentY").toReal() - 200.0,
+ flickable->property("maxVerticalOvershoot").toReal());
}
- QCOMPARE(flickable->property("minContentY").toReal(), 200.0);
QCOMPARE(flickable->property("minContentX").toReal(), 200.0);
- QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("minContentY").toReal(), 200.0);
QCOMPARE(flickable->property("minHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
flickable->setContentX(180.0);
flickable->setContentY(180.0);
@@ -2323,37 +2344,59 @@ void tst_qquickflickable::overshoot()
flick(window.data(), QPoint(50, 50), QPoint(10, 10), 100);
QTRY_VERIFY(!flickable->property("flicking").toBool());
+ if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::OvershootBounds)) {
+ QVERIFY(flickable->property("maxContentX").toReal() > 200.0);
+ QVERIFY(flickable->property("maxContentY").toReal() > 200.0);
+ } else {
+ QCOMPARE(flickable->property("maxContentX").toReal(), 200.0);
+ QCOMPARE(flickable->property("maxContentY").toReal(), 200.0);
+ }
if (boundsBehavior & QQuickFlickable::OvershootBounds) {
- QVERIFY(flickable->property("maxVerticalOvershoot").toReal() > 0.0);
QVERIFY(flickable->property("maxHorizontalOvershoot").toReal() > 0.0);
- QCOMPARE(flickable->property("maxContentY").toReal() - 200.0,
- flickable->property("maxVerticalOvershoot").toReal());
- QCOMPARE(flickable->property("maxContentX").toReal() - 200.0,
- flickable->property("maxHorizontalOvershoot").toReal());
+ QVERIFY(flickable->property("maxVerticalOvershoot").toReal() > 0.0);
} else {
- QCOMPARE(flickable->property("maxContentY").toReal(), 200.0);
- QCOMPARE(flickable->property("maxContentX").toReal(), 200.0);
- QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
QCOMPARE(flickable->property("maxHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("maxVerticalOvershoot").toReal(), 0.0);
+ }
+ if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) == (boundsBehavior & QQuickFlickable::OvershootBounds)) {
+ QCOMPARE(flickable->property("maxContentX").toReal() - 200.0,
+ flickable->property("maxHorizontalOvershoot").toReal());
+ QCOMPARE(flickable->property("maxContentY").toReal() - 200.0,
+ flickable->property("maxVerticalOvershoot").toReal());
}
- QCOMPARE(flickable->property("minContentY").toReal(), 180.0);
QCOMPARE(flickable->property("minContentX").toReal(), 180.0);
- QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("minContentY").toReal(), 180.0);
QCOMPARE(flickable->property("minHorizontalOvershoot").toReal(), 0.0);
+ QCOMPARE(flickable->property("minVerticalOvershoot").toReal(), 0.0);
}
void tst_qquickflickable::overshoot_data()
{
QTest::addColumn<QQuickFlickable::BoundsBehavior>("boundsBehavior");
-
- QTest::newRow("StopAtBounds")
- << QQuickFlickable::BoundsBehavior(QQuickFlickable::StopAtBounds);
- QTest::newRow("DragOverBounds")
- << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds);
- QTest::newRow("OvershootBounds")
- << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds);
- QTest::newRow("DragAndOvershootBounds")
- << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds);
+ QTest::addColumn<int>("boundsMovement");
+
+ QTest::newRow("StopAtBounds,FollowBoundsBehavior")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::StopAtBounds)
+ << int(QQuickFlickable::FollowBoundsBehavior);
+ QTest::newRow("DragOverBounds,FollowBoundsBehavior")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds)
+ << int(QQuickFlickable::FollowBoundsBehavior);
+ QTest::newRow("OvershootBounds,FollowBoundsBehavior")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds)
+ << int(QQuickFlickable::FollowBoundsBehavior);
+ QTest::newRow("DragAndOvershootBounds,FollowBoundsBehavior")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds)
+ << int(QQuickFlickable::FollowBoundsBehavior);
+
+ QTest::newRow("DragOverBounds,StopAtBounds")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds)
+ << int(QQuickFlickable::StopAtBounds);
+ QTest::newRow("OvershootBounds,StopAtBounds")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds)
+ << int(QQuickFlickable::StopAtBounds);
+ QTest::newRow("DragAndOvershootBounds,StopAtBounds")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds)
+ << int(QQuickFlickable::StopAtBounds);
}
void tst_qquickflickable::overshoot_reentrant()
diff --git a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
new file mode 100644
index 0000000000..cab6e2f7bf
--- /dev/null
+++ b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
@@ -0,0 +1,4 @@
+[nonOverlapping]
+ubuntu-16.04
+[nested]
+ubuntu-16.04
diff --git a/tests/auto/quick/qquickpositioners/data/implicitGridOneItem.qml b/tests/auto/quick/qquickpositioners/data/implicitGridOneItem.qml
deleted file mode 100644
index 8da9fc270d..0000000000
--- a/tests/auto/quick/qquickpositioners/data/implicitGridOneItem.qml
+++ /dev/null
@@ -1,12 +0,0 @@
-import QtQuick 2.9
-import PositionerTest 1.0
-
-ImplicitGrid {
- columns: 2
- rows: 1
-
- Text {
- text: "Text"
- width: parent.width
- }
-}
diff --git a/tests/auto/quick/qquickpositioners/data/implicitRowOneItem.qml b/tests/auto/quick/qquickpositioners/data/implicitRowOneItem.qml
deleted file mode 100644
index 25a287cf31..0000000000
--- a/tests/auto/quick/qquickpositioners/data/implicitRowOneItem.qml
+++ /dev/null
@@ -1,9 +0,0 @@
-import QtQuick 2.9
-import PositionerTest 1.0
-
-ImplicitRow {
- Text {
- text: "Text"
- width: parent.width
- }
-}
diff --git a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp
index 4c4afb7a7b..1b3939401a 100644
--- a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp
+++ b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp
@@ -98,8 +98,6 @@ private slots:
void test_attachedproperties();
void test_attachedproperties_data();
void test_attachedproperties_dynamic();
- void test_useImplicitSize_oneItem_data();
- void test_useImplicitSize_oneItem();
void populateTransitions_row();
void populateTransitions_row_data();
@@ -306,8 +304,6 @@ void tst_qquickpositioners::moveTransitions_flow_data()
tst_qquickpositioners::tst_qquickpositioners()
{
- qmlRegisterType<QQuickImplicitRow>("PositionerTest", 1, 0, "ImplicitRow");
- qmlRegisterType<QQuickImplicitGrid>("PositionerTest", 1, 0, "ImplicitGrid");
}
void tst_qquickpositioners::test_horizontal()
@@ -4008,46 +4004,6 @@ void tst_qquickpositioners::test_attachedproperties_dynamic()
}
-void tst_qquickpositioners::test_useImplicitSize_oneItem_data()
-{
- QTest::addColumn<QString>("positionerType");
-
- QTest::newRow("Grid") << "Grid";
- QTest::newRow("Row") << "Row";
-}
-
-void tst_qquickpositioners::test_useImplicitSize_oneItem()
-{
- QFETCH(QString, positionerType);
-
- QQuickView view;
- view.setSource(testFileUrl(QString::fromLatin1("implicit%1OneItem.qml").arg(positionerType)));
- QCOMPARE(view.status(), QQuickView::Ready);
- view.show();
- QVERIFY(QTest::qWaitForWindowExposed(&view));
-
- QQuickItem *positioner = view.rootObject();
- QVERIFY(positioner);
- const qreal oldPositionerImplicitWidth = positioner->implicitWidth();
-
- QQuickText *text = qobject_cast<QQuickText*>(positioner->childItems().first());
- QVERIFY(text);
- const qreal oldTextImplicitWidth = text->implicitWidth();
- QCOMPARE(positioner->implicitWidth(), text->implicitWidth());
-
- // Ensure that the implicit size of the positioner changes when the implicit size
- // of one of its children changes.
- text->setText(QLatin1String("Even More Text"));
- const qreal textImplicitWidthIncrease = text->implicitWidth() - oldTextImplicitWidth;
- QVERIFY(textImplicitWidthIncrease > 0);
- QTRY_COMPARE(positioner->implicitWidth(), oldPositionerImplicitWidth + textImplicitWidthIncrease);
-
- // Ensure that the implicit size of the positioner does not change when the
- // explicit size of one of its children changes.
- text->setWidth(10);
- QTRY_COMPARE(positioner->implicitWidth(), oldPositionerImplicitWidth + textImplicitWidthIncrease);
-}
-
QQuickView *tst_qquickpositioners::createView(const QString &filename, bool wait)
{
QQuickView *window = new QQuickView(0);
diff --git a/tests/auto/quick/qquickwindow/BLACKLIST b/tests/auto/quick/qquickwindow/BLACKLIST
new file mode 100644
index 0000000000..157808fdbf
--- /dev/null
+++ b/tests/auto/quick/qquickwindow/BLACKLIST
@@ -0,0 +1,4 @@
+[requestActivate]
+osx-10.11
+[attachedProperty]
+osx-10.11
diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp
index 53dd35da07..83680a5ba1 100644
--- a/tools/qml/main.cpp
+++ b/tools/qml/main.cpp
@@ -55,7 +55,9 @@
#include <QLibraryInfo>
#include <qqml.h>
#include <qqmldebug.h>
+#if QT_CONFIG(animation)
#include <private/qabstractanimation_p.h>
+#endif
#include <cstdio>
#include <cstring>
@@ -69,7 +71,9 @@
static Config *conf = 0;
static QQmlApplicationEngine *qae = 0;
+#if defined(Q_OS_DARWIN) || defined(QT_GUI_LIB)
static int exitTimerId = -1;
+#endif
bool verboseMode = false;
static void loadConf(const QString &override, bool quiet) // Terminates app on failure
@@ -386,6 +390,9 @@ void getAppFlags(int &argc, char **argv)
argc -= 2;
}
}
+#else
+ Q_UNUSED(argc)
+ Q_UNUSED(argv)
#endif // QT_GUI_LIB
}
@@ -476,10 +483,12 @@ int main(int argc, char *argv[])
break;
else if (arg == QLatin1String("-verbose"))
verboseMode = true;
+#if QT_CONFIG(animation)
else if (arg == QLatin1String("-slow-animations"))
QUnifiedTimer::instance()->setSlowModeEnabled(true);
else if (arg == QLatin1String("-fixed-animations"))
QUnifiedTimer::instance()->setConsistentTiming(true);
+#endif
else if (arg == QLatin1String("-I")) {
if (i+1 == argList.count())
continue;//Invalid usage, but just ignore it
@@ -548,7 +557,7 @@ int main(int argc, char *argv[])
qInstallMessageHandler(quietMessageHandler);
if (files.count() <= 0) {
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_DARWIN)
if (applicationType == QmlApplicationTypeGui)
exitTimerId = static_cast<LoaderApplication *>(app)->startTimer(FILE_OPEN_EVENT_WAIT_TIME);
else
diff --git a/tools/qmlcachegen/qmlcache.prf b/tools/qmlcachegen/qmlcache.prf
index 31c18a231b..4470db0d09 100644
--- a/tools/qmlcachegen/qmlcache.prf
+++ b/tools/qmlcachegen/qmlcache.prf
@@ -10,7 +10,10 @@ isEmpty(TARGETPATH): error("Must set TARGETPATH (QML import name) for ahead-of-t
!isEmpty(QT_TARGET_ARCH):QML_CACHEGEN_ARCH=$$QT_TARGET_ARCH
else:QML_CACHEGEN_ARCH=$$QT_ARCH
-QML_CACHEGEN_ARGS=--target-architecture=$$QML_CACHEGEN_ARCH
+!isEmpty(QT_TARGET_BUILDABI):QML_CACHEGEN_ABI=$$QT_TARGET_BUILDABI
+else:QML_CACHEGEN_ABI=$$QT_BUILDABI
+
+QML_CACHEGEN_ARGS=--target-architecture=$$QML_CACHEGEN_ARCH --target-abi=$$QML_CACHEGEN_ABI
!system($$QML_CACHEGEN_ARCH_CHECK $$QML_CACHEGEN_ARGS --check-if-supported) {
message("QML cache generation requested but target architecture $$QML_CACHEGEN_ARCH is not supported.")
diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp
index f24ec40184..b201176d5e 100644
--- a/tools/qmlcachegen/qmlcachegen.cpp
+++ b/tools/qmlcachegen/qmlcachegen.cpp
@@ -37,6 +37,7 @@
#include <private/qqmlirbuilder_p.h>
#include <private/qv4isel_moth_p.h>
#include <private/qqmljsparser_p.h>
+#include <private/qv4jssimplifier_p.h>
QT_BEGIN_NAMESPACE
@@ -113,9 +114,10 @@ static void annotateListElements(QmlIR::Document *document)
}
}
-static bool compileQmlFile(const QString &inputFileName, const QString &outputFileName, QV4::EvalISelFactory *iselFactory, Error *error)
+static bool compileQmlFile(const QString &inputFileName, const QString &outputFileName, QV4::EvalISelFactory *iselFactory, const QString &targetABI, Error *error)
{
QmlIR::Document irDocument(/*debugMode*/false);
+ irDocument.jsModule.targetABI = targetABI;
QString sourceCode;
{
@@ -173,7 +175,10 @@ static bool compileQmlFile(const QString &inputFileName, const QString &outputFi
QmlIR::QmlUnitGenerator generator;
- // ### translation binding simplification
+ {
+ QQmlJavaScriptBindingExpressionSimplificationPass pass(irDocument.objects, &irDocument.jsModule, &irDocument.jsGenerator);
+ pass.reduceTranslationBindings();
+ }
QV4::ExecutableAllocator allocator;
QScopedPointer<QV4::EvalInstructionSelection> isel(iselFactory->create(/*engine*/nullptr, &allocator, &irDocument.jsModule, &irDocument.jsGenerator));
@@ -193,9 +198,10 @@ static bool compileQmlFile(const QString &inputFileName, const QString &outputFi
return true;
}
-static bool compileJSFile(const QString &inputFileName, const QString &outputFileName, QV4::EvalISelFactory *iselFactory, Error *error)
+static bool compileJSFile(const QString &inputFileName, const QString &outputFileName, QV4::EvalISelFactory *iselFactory, const QString &targetABI, Error *error)
{
QmlIR::Document irDocument(/*debugMode*/false);
+ irDocument.jsModule.targetABI = targetABI;
QString sourceCode;
{
@@ -262,8 +268,6 @@ static bool compileJSFile(const QString &inputFileName, const QString &outputFil
QmlIR::QmlUnitGenerator generator;
- // ### translation binding simplification
-
QV4::ExecutableAllocator allocator;
QScopedPointer<QV4::EvalInstructionSelection> isel(iselFactory->create(/*engine*/nullptr, &allocator, &irDocument.jsModule, &irDocument.jsGenerator));
// Disable lookups in non-standalone (aka QML) mode
@@ -300,6 +304,9 @@ int main(int argc, char **argv)
QCommandLineOption targetArchitectureOption(QStringLiteral("target-architecture"), QCoreApplication::translate("main", "Target architecture"), QCoreApplication::translate("main", "architecture"));
parser.addOption(targetArchitectureOption);
+ QCommandLineOption targetABIOption(QStringLiteral("target-abi"), QCoreApplication::translate("main", "Target architecture binary interface"), QCoreApplication::translate("main", "abi"));
+ parser.addOption(targetABIOption);
+
QCommandLineOption outputFileOption(QStringLiteral("o"), QCoreApplication::translate("main", "Output file name"), QCoreApplication::translate("main", "file name"));
parser.addOption(outputFileOption);
@@ -347,13 +354,15 @@ int main(int argc, char **argv)
if (parser.isSet(outputFileOption))
outputFileName = parser.value(outputFileOption);
+ const QString targetABI = parser.value(targetABIOption);
+
if (inputFile.endsWith(QLatin1String(".qml"))) {
- if (!compileQmlFile(inputFile, outputFileName, isel.data(), &error)) {
+ if (!compileQmlFile(inputFile, outputFileName, isel.data(), targetABI, &error)) {
error.augment(QLatin1String("Error compiling qml file: ")).print();
return EXIT_FAILURE;
}
} else if (inputFile.endsWith(QLatin1String(".js"))) {
- if (!compileJSFile(inputFile, outputFileName, isel.data(), &error)) {
+ if (!compileJSFile(inputFile, outputFileName, isel.data(), targetABI, &error)) {
error.augment(QLatin1String("Error compiling qml file: ")).print();
return EXIT_FAILURE;
}
diff --git a/tools/qmlprofiler/qmlprofilerdata.cpp b/tools/qmlprofiler/qmlprofilerdata.cpp
index 596ad8d47f..bcda0bb7fe 100644
--- a/tools/qmlprofiler/qmlprofilerdata.cpp
+++ b/tools/qmlprofiler/qmlprofilerdata.cpp
@@ -33,7 +33,7 @@
#include <QHash>
#include <QFile>
#include <QXmlStreamReader>
-#include <QRegExp>
+#include <QRegularExpression>
#include <limits>
@@ -232,10 +232,10 @@ void QmlProfilerData::addQmlEvent(QQmlProfilerDefinitions::RangeType type,
if (!data.isEmpty()) {
details = data.join(QLatin1Char(' ')).replace(
QLatin1Char('\n'), QLatin1Char(' ')).simplified();
- QRegExp rewrite(QStringLiteral("\\(function \\$(\\w+)\\(\\) \\{ (return |)(.+) \\}\\)"));
- bool match = rewrite.exactMatch(details);
- if (match) {
- details = rewrite.cap(1) +QLatin1String(": ") + rewrite.cap(3);
+ QRegularExpression rewrite(QStringLiteral("^\\(function \\$(\\w+)\\(\\) \\{ (return |)(.+) \\}\\)$"));
+ QRegularExpressionMatch match = rewrite.match(details);
+ if (match.hasMatch()) {
+ details = match.captured(1) +QLatin1String(": ") + match.captured(3);
}
if (details.startsWith(QLatin1String("file://")))
details = details.mid(details.lastIndexOf(QLatin1Char('/')) + 1);
diff --git a/tools/qmlscene/main.cpp b/tools/qmlscene/main.cpp
index 7741c4c45b..6ce676456c 100644
--- a/tools/qmlscene/main.cpp
+++ b/tools/qmlscene/main.cpp
@@ -33,7 +33,7 @@
#include <QtCore/qpointer.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qtextstream.h>
-#include <QtCore/qregexp.h>
+#include <QtCore/qregularexpression.h>
#include <QtGui/QGuiApplication>
#include <QtGui/QOpenGLFunctions>
@@ -133,6 +133,17 @@ void RenderStatistics::printTotalStats()
struct Options
{
+ enum QmlApplicationType
+ {
+ QmlApplicationTypeGui,
+ QmlApplicationTypeWidget,
+#ifdef QT_WIDGETS_LIB
+ DefaultQmlApplicationType = QmlApplicationTypeWidget
+#else
+ DefaultQmlApplicationType = QmlApplicationTypeGui
+#endif
+ };
+
Options()
: originalQml(false)
, originalQmlRaster(false)
@@ -146,6 +157,7 @@ struct Options
, resizeViewToRootItem(false)
, multisample(false)
, verbose(false)
+ , applicationType(DefaultQmlApplicationType)
{
// QtWebEngine needs a shared context in order for the GPU thread to
// upload textures.
@@ -167,6 +179,7 @@ struct Options
bool verbose;
QVector<Qt::ApplicationAttribute> applicationAttributes;
QString translationFile;
+ QmlApplicationType applicationType;
};
#if defined(QMLSCENE_BUNDLE)
@@ -259,8 +272,8 @@ static bool checkVersion(const QUrl &url)
return false;
}
- QRegExp quick1("^\\s*import +QtQuick +1\\.\\w*");
- QRegExp qt47("^\\s*import +Qt +4\\.7");
+ QRegularExpression quick1("^\\s*import +QtQuick +1\\.\\w*");
+ QRegularExpression qt47("^\\s*import +Qt +4\\.7");
QTextStream stream(&f);
bool codeFound= false;
@@ -270,10 +283,11 @@ static bool checkVersion(const QUrl &url)
codeFound = true;
} else {
QString import;
- if (quick1.indexIn(line) >= 0)
- import = quick1.cap(0).trimmed();
- else if (qt47.indexIn(line) >= 0)
- import = qt47.cap(0).trimmed();
+ QRegularExpressionMatch match = quick1.match(line);
+ if (match.hasMatch())
+ import = match.captured(0).trimmed();
+ else if ((match = qt47.match(line)).hasMatch())
+ import = match.captured(0).trimmed();
if (!import.isNull()) {
fprintf(stderr, "qmlscene: '%s' is no longer supported.\n"
@@ -291,15 +305,17 @@ static bool checkVersion(const QUrl &url)
static void displayFileDialog(Options *options)
{
#if defined(QT_WIDGETS_LIB) && QT_CONFIG(filedialog)
- QString fileName = QFileDialog::getOpenFileName(0, "Open QML file", QString(), "QML Files (*.qml)");
- if (!fileName.isEmpty()) {
- QFileInfo fi(fileName);
- options->url = QUrl::fromLocalFile(fi.canonicalFilePath());
+ if (options->applicationType == Options::QmlApplicationTypeWidget) {
+ QString fileName = QFileDialog::getOpenFileName(0, "Open QML file", QString(), "QML Files (*.qml)");
+ if (!fileName.isEmpty()) {
+ QFileInfo fi(fileName);
+ options->url = QUrl::fromLocalFile(fi.canonicalFilePath());
+ }
+ return;
}
-#else
+#endif // QT_WIDGETS_LIB && QT_CONFIG(filedialog)
Q_UNUSED(options);
puts("No filename specified...");
-#endif
}
#if QT_CONFIG(translation)
@@ -355,6 +371,9 @@ static void usage()
puts(" --scaling..........................Enable High DPI scaling (AA_EnableHighDpiScaling)");
puts(" --no-scaling.......................Disable High DPI scaling (AA_DisableHighDpiScaling)");
puts(" --verbose..........................Print version and graphical diagnostics for the run-time");
+#ifdef QT_WIDGETS_LIB
+ puts(" --apptype [gui|widgets] ...........Select which application class to use. Default is widgets.");
+#endif
puts(" -I <path> ........................ Add <path> to the list of import paths");
puts(" -P <path> ........................ Add <path> to the list of plugin paths");
puts(" -translation <translationfile> ... Set the language to run in");
@@ -444,30 +463,38 @@ int main(int argc, char ** argv)
// Parse arguments for application attributes to be applied before Q[Gui]Application creation.
for (int i = 1; i < argc; ++i) {
const char *arg = argv[i];
- if (!qstrcmp(arg, "--disable-context-sharing"))
+ if (!qstrcmp(arg, "--disable-context-sharing")) {
options.applicationAttributes.removeAll(Qt::AA_ShareOpenGLContexts);
- else if (!qstrcmp(arg, "--gles"))
+ } else if (!qstrcmp(arg, "--gles")) {
options.applicationAttributes.append(Qt::AA_UseOpenGLES);
- else if (!qstrcmp(arg, "--software"))
+ } else if (!qstrcmp(arg, "--software")) {
options.applicationAttributes.append(Qt::AA_UseSoftwareOpenGL);
- else if (!qstrcmp(arg, "--desktop"))
+ } else if (!qstrcmp(arg, "--desktop")) {
options.applicationAttributes.append(Qt::AA_UseDesktopOpenGL);
- else if (!qstrcmp(arg, "--scaling"))
+ } else if (!qstrcmp(arg, "--scaling")) {
options.applicationAttributes.append(Qt::AA_EnableHighDpiScaling);
- else if (!qstrcmp(arg, "--no-scaling"))
+ } else if (!qstrcmp(arg, "--no-scaling")) {
options.applicationAttributes.append(Qt::AA_DisableHighDpiScaling);
+ } else if (!qstrcmp(arg, "--apptype")) {
+ if (++i >= argc)
+ usage();
+ if (!qstrcmp(argv[i], "gui"))
+ options.applicationType = Options::QmlApplicationTypeGui;
+ }
}
for (Qt::ApplicationAttribute a : qAsConst(options.applicationAttributes))
QCoreApplication::setAttribute(a);
+ QScopedPointer<QGuiApplication> app;
#ifdef QT_WIDGETS_LIB
- QApplication app(argc, argv);
-#else
- QGuiApplication app(argc, argv);
+ if (options.applicationType == Options::QmlApplicationTypeWidget)
+ app.reset(new QApplication(argc, argv));
#endif
- app.setApplicationName("QtQmlViewer");
- app.setOrganizationName("QtProject");
- app.setOrganizationDomain("qt-project.org");
+ if (app.isNull())
+ app.reset(new QGuiApplication(argc, argv));
+ QCoreApplication::setApplicationName(QStringLiteral("QtQmlViewer"));
+ QCoreApplication::setOrganizationName(QStringLiteral("QtProject"));
+ QCoreApplication::setOrganizationDomain(QStringLiteral("qt-project.org"));
QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
const QStringList arguments = QCoreApplication::arguments();
@@ -502,6 +529,8 @@ int main(int argc, char ** argv)
imports.append(arguments.at(++i));
else if (lowerArgument == QLatin1String("-p") && i + 1 < size)
pluginPaths.append(arguments.at(++i));
+ else if (lowerArgument == QLatin1String("--apptype"))
+ ++i; // Consume previously parsed argument
else if (lowerArgument == QLatin1String("--help")
|| lowerArgument == QLatin1String("-help")
|| lowerArgument == QLatin1String("--h")
@@ -515,14 +544,14 @@ int main(int argc, char ** argv)
QTranslator qtTranslator;
QString sysLocale = QLocale::system().name();
if (qtTranslator.load(QLatin1String("qt_") + sysLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
- app.installTranslator(&qtTranslator);
+ app->installTranslator(&qtTranslator);
if (translator.load(QLatin1String("qmlscene_") + sysLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
- app.installTranslator(&translator);
+ app->installTranslator(&translator);
QTranslator qmlTranslator;
if (!options.translationFile.isEmpty()) {
if (qmlTranslator.load(options.translationFile)) {
- app.installTranslator(&qmlTranslator);
+ app->installTranslator(&qmlTranslator);
} else {
fprintf(stderr, "Could not load the translation file \"%s\"\n",
qPrintable(options.translationFile));
@@ -630,7 +659,7 @@ int main(int argc, char ** argv)
// Now would be a good time to inform the debug service to start listening.
- exitCode = app.exec();
+ exitCode = app->exec();
#ifdef QML_RUNTIME_TESTING
RenderStatistics::printTotalStats();
diff --git a/tools/tools.pro b/tools/tools.pro
index 5d9d3740ce..20a3600fb8 100644
--- a/tools/tools.pro
+++ b/tools/tools.pro
@@ -2,8 +2,9 @@ TEMPLATE = subdirs
QT_FOR_CONFIG += qml-private
SUBDIRS += \
qmlmin \
- qmlimportscanner \
- qmlcachegen
+ qmlimportscanner
+
+qtConfig(commandlineparser): SUBDIRS += qmlcachegen
!android|android_app {
SUBDIRS += \