QtQml: Empty SimpleArrayData vacant space when truncating
Without this we effectively soft-leak the contents of any SimpleArrayData whenever we truncate it. Only when the array was either completely dropped or re-filled would the extra objects be reclaimed. Task-number: QTBUG-139025 Pick-to: 6.10 6.9 6.8 Change-Id: I88e9dc3ea8ec57c1de71b7b5417ebcfbaa75bb61 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
5a664f0836
commit
e0f65fe66f
|
@ -264,14 +264,19 @@ uint SimpleArrayData::truncate(Object *o, uint newLen)
|
|||
return newLen;
|
||||
|
||||
if (!dd->attrs) {
|
||||
for (uint i = newLen; i < dd->values.size; ++i)
|
||||
dd->setData(dd->internalClass->engine, i, Value::emptyValue());
|
||||
dd->values.size = newLen;
|
||||
return newLen;
|
||||
}
|
||||
|
||||
while (dd->values.size > newLen) {
|
||||
if (!dd->data(dd->values.size - 1).isEmpty() && !dd->attrs[dd->values.size - 1].isConfigurable())
|
||||
const uint lastIndex = dd->values.size - 1;
|
||||
if (!dd->data(lastIndex).isEmpty() && !dd->attrs[lastIndex].isConfigurable())
|
||||
return dd->values.size;
|
||||
--dd->values.size;
|
||||
|
||||
dd->setData(dd->internalClass->engine, lastIndex, Value::emptyValue());
|
||||
dd->values.size = lastIndex;
|
||||
}
|
||||
return dd->values.size;
|
||||
}
|
||||
|
|
|
@ -355,6 +355,7 @@ private slots:
|
|||
#endif
|
||||
|
||||
void evalInGlobalContext();
|
||||
void truncateArrayData();
|
||||
|
||||
public:
|
||||
Q_INVOKABLE QJSValue throwingCppMethod1();
|
||||
|
@ -6915,6 +6916,35 @@ void tst_QJSEngine::evalInGlobalContext()
|
|||
QCOMPARE(ret.toString(), QLatin1String("99"));
|
||||
}
|
||||
|
||||
void tst_QJSEngine::truncateArrayData()
|
||||
{
|
||||
QJSEngine engine;
|
||||
|
||||
QJSValue array = engine.newArray();
|
||||
array.setProperty(0, QJSValue::NullValue);
|
||||
array.setProperty(1, QJSValue(14));
|
||||
array.setProperty(2, QJSValue(QLatin1String("aaa")));
|
||||
|
||||
// Append a JavaScript-owned object to the array and don't keep a local reference.
|
||||
QJSValue object = engine.newQObject(new QObject());
|
||||
QSignalSpy spy(object.toQObject(), &QObject::destroyed);
|
||||
// std::move won't do here because setProperty() doesn't accept rvalue refs
|
||||
array.setProperty(3, std::exchange(object, QJSValue()));
|
||||
QVERIFY(object.isUndefined());
|
||||
|
||||
QCOMPARE(array.property("length").toInt(), 4);
|
||||
|
||||
gc(*engine.handle());
|
||||
QCOMPARE(spy.count(), 0);
|
||||
QCOMPARE(array.property("length").toInt(), 4);
|
||||
|
||||
// Truncating the array allows the GC to collect the QObject, which results in its deletion.
|
||||
array.setProperty("length", 3);
|
||||
QCOMPARE(array.property("length").toInt(), 3);
|
||||
gc(*engine.handle());
|
||||
QCOMPARE(spy.count(), 1);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QJSEngine)
|
||||
|
||||
#include "tst_qjsengine.moc"
|
||||
|
|
Loading…
Reference in New Issue