From 60f766f5c68fc33322c6d095d81b1856828b2b0b Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 26 Mar 2019 13:57:33 +0100 Subject: Re-use existing IC when freezing properties There is no reason to start from the empty class in that case. Furthermore, if the properties are already frozen, starting from the empty class will walk the IC hierarchy to the current IC. However, if the garbage collector has removed the intermediate classes in the mean time, we end up at a new IC which is equivalent but not the same. Therefore, the freezing never terminates. Task-number: QTBUG-74190 Change-Id: Id544bd00d3b4b563fb06dfce0edd0385e1d32a6c Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4internalclass.cpp | 7 +++---- src/qml/jsruntime/qv4internalclass_p.h | 2 +- tests/auto/qml/qqmlengine/tst_qqmlengine.cpp | 13 +++++++++++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 8e2657f4a5..3fb2465a45 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -658,11 +658,10 @@ Heap::InternalClass *InternalClass::frozen() return f; } -Heap::InternalClass *InternalClass::propertiesFrozen() const +Heap::InternalClass *InternalClass::propertiesFrozen() { Scope scope(engine); - Scoped frozen(scope, engine->internalClasses(EngineBase::Class_Empty)->changeVTable(vtable)); - frozen = frozen->changePrototype(prototype); + Scoped frozen(scope, this); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); if (!nameMap.at(i).isValid()) @@ -671,7 +670,7 @@ Heap::InternalClass *InternalClass::propertiesFrozen() const attrs.setWritable(false); attrs.setConfigurable(false); } - frozen = frozen->addMember(nameMap.at(i), attrs); + frozen = frozen->changeMember(nameMap.at(i), attrs); } return frozen->d(); } diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index c689637721..121238c555 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -428,7 +428,7 @@ struct InternalClass : Base { Q_REQUIRED_RESULT InternalClass *sealed(); Q_REQUIRED_RESULT InternalClass *frozen(); - Q_REQUIRED_RESULT InternalClass *propertiesFrozen() const; + Q_REQUIRED_RESULT InternalClass *propertiesFrozen(); Q_REQUIRED_RESULT InternalClass *asProtoClass(); diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index f58ae38264..b9cb6b70d2 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -80,6 +80,7 @@ private slots: void qrcUrls(); void cppSignalAndEval(); void singletonInstance(); + void aggressiveGc(); public slots: QObject *createAQObjectForOwnershipTest () @@ -1043,6 +1044,18 @@ void tst_qqmlengine::singletonInstance() } } +void tst_qqmlengine::aggressiveGc() +{ + const QByteArray origAggressiveGc = qgetenv("QV4_MM_AGGRESSIVE_GC"); + qputenv("QV4_MM_AGGRESSIVE_GC", "true"); + { + QQmlEngine engine; // freezing should not run into infinite recursion + QJSValue obj = engine.newObject(); + QVERIFY(obj.isObject()); + } + qputenv("QV4_MM_AGGRESSIVE_GC", origAggressiveGc); +} + QTEST_MAIN(tst_qqmlengine) #include "tst_qqmlengine.moc" -- cgit v1.2.3