aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/memory/qv4mm.cpp14
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp5
-rw-r--r--tests/auto/qml/qv4mm/data/createobjects.qml81
-rw-r--r--tests/auto/qml/qv4mm/tst_qv4mm.cpp12
4 files changed, 111 insertions, 1 deletions
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 06caf04e5a..0aeeb0ec5b 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -790,6 +790,13 @@ Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
HeapItem *m = allocate(&blockAllocator, stringSize);
memset(m, 0, stringSize);
+ if (gcBlocked) {
+ // If the gc is running right now, it will not have a chance to mark the newly created item
+ // and may therefore sweep it right away.
+ // Protect the new object from the current GC run to avoid this.
+ m->as<Heap::Base>()->setMarkBit();
+ }
+
return *m;
}
@@ -805,6 +812,13 @@ Heap::Base *MemoryManager::allocData(std::size_t size)
HeapItem *m = allocate(&blockAllocator, size);
memset(m, 0, size);
+ if (gcBlocked) {
+ // If the gc is running right now, it will not have a chance to mark the newly created item
+ // and may therefore sweep it right away.
+ // Protect the new object from the current GC run to avoid this.
+ m->as<Heap::Base>()->setMarkBit();
+ }
+
return *m;
}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 96fdd012e2..985b8c7a98 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -7676,7 +7676,10 @@ void tst_qqmlecmascript::onDestructionViaGC()
gc(engine);
QVERIFY2(mutatorResult, "We failed to re-assign the weak reference a new value during GC");
- QVERIFY2(sentinelResult, "The weak reference was not cleared properly");
+ QVERIFY2(!sentinelResult, "The weak value was cleared on first GC run");
+ QVERIFY2(!weakRef->isNullOrUndefined(), "The weak value was cleared on first GC run");
+ gc(engine);
+ QVERIFY2(weakRef->isNullOrUndefined(), "The weak value was not cleared on second gc run");
}
struct EventProcessor : public QObject
diff --git a/tests/auto/qml/qv4mm/data/createobjects.qml b/tests/auto/qml/qv4mm/data/createobjects.qml
new file mode 100644
index 0000000000..5196855eca
--- /dev/null
+++ b/tests/auto/qml/qv4mm/data/createobjects.qml
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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$
+**
+****************************************************************************/
+
+import QtQml 2.2
+
+QtObject {
+ property var objects: []
+ property int numChecked: 0
+ property var c: null
+ property bool ok: false
+
+ function container() {
+ var objs
+
+ return {
+ "check": function() {
+ for (var i = 0; i < 1000; ++i) {
+ if (objs[i][0] !== 1 || objs[i][1] !== 2 || objs[i][2] !== 3)
+ return false;
+ }
+ return true;
+ },
+
+ "generate": function() {
+ objs = [];
+ for (var i = 0; i < 1000; ++i)
+ objs[i] = [1, 2, 3]
+ }
+ }
+ }
+
+ property Component itemComponent: Component {
+ QtObject {}
+ }
+
+ property Component triggerComponent: Component {
+ QtObject {
+ Component.onDestruction: {
+ for (var i = 0; i < 1000; ++i)
+ objects[i] = itemComponent.createObject();
+ c = container();
+ c.generate();
+ }
+ }
+ }
+
+ Component.onCompleted: {
+ triggerComponent.createObject();
+ gc();
+ for (var i = 0; i < 1000; ++i) {
+ if (objects[i] !== undefined)
+ ++numChecked;
+ }
+ ok = c.check();
+ }
+}
diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
index 5d635aa63b..b6a5753e56 100644
--- a/tests/auto/qml/qv4mm/tst_qv4mm.cpp
+++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
@@ -48,6 +48,7 @@ private slots:
void multiWrappedQObjects();
void accessParentOnDestruction();
void clearICParent();
+ void createObjectsOnDestruction();
};
void tst_qv4mm::gcStats()
@@ -148,6 +149,17 @@ void tst_qv4mm::clearICParent()
QFAIL("Garbage collector was not triggered by large amount of InternalClasses");
}
+void tst_qv4mm::createObjectsOnDestruction()
+{
+ QLoggingCategory::setFilterRules("qt.qml.gc.*=false");
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("createobjects.qml"));
+ std::unique_ptr<QObject> obj(component.create());
+ QVERIFY(obj);
+ QCOMPARE(obj->property("numChecked").toInt(), 1000);
+ QCOMPARE(obj->property("ok").toBool(), true);
+}
+
QTEST_MAIN(tst_qv4mm)
#include "tst_qv4mm.moc"