From 3c94c7eb7e622051677eb319f6a79e5edb8e2a12 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jo=C3=A3o=20Abecasis?= Date: Wed, 7 Mar 2012 23:17:54 +0100 Subject: [PATCH] Don't grow container when desired size is known QList::reserve() is used upfront to allocate necessary memory in a one go. This tells us straight away whether allocation is possible at all and reduces re-allocations and consequent memory copies. This also has the side effect that no spare memory is allocated, also allowing up to (and including) INT_MAX elements to actually be stored in the underlying QList, as long as enough memory is available to satisfy the allocation request and subsequent fill. The qqmlecmascript::sequenceConversionIndexes was changed to not attempt INT_MAX allocations as, given enough memory and virtual address space, that might succeed but take a really long time. Change-Id: I4b0c965e9c23be78874343a70d7c155933c80903 Reviewed-by: Chris Adams Reviewed-by: Kent Hansen --- src/qml/qml/v8/qv8sequencewrapper_p_p.h | 25 ++++++++++++---------- .../data/sequenceConversion.indexes.qml | 14 ------------ .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 4 ---- 3 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/qml/qml/v8/qv8sequencewrapper_p_p.h b/src/qml/qml/v8/qv8sequencewrapper_p_p.h index 9d51980..eebc40e 100644 --- a/src/qml/qml/v8/qv8sequencewrapper_p_p.h +++ b/src/qml/qml/v8/qv8sequencewrapper_p_p.h @@ -265,6 +265,7 @@ static QString convertUrlToString(QV8Engine *, const QUrl &v) static QVariant toVariant(QV8Engine *e, v8::Handle array, uint32_t length, bool *succeeded) \ { \ SequenceType list; \ + list.reserve(length); \ for (uint32_t ii = 0; ii < length; ++ii) { \ list.append(ConversionFromV8fn(e, array->Get(ii))); \ } \ @@ -334,14 +335,15 @@ static QString convertUrlToString(QV8Engine *, const QUrl &v) /* according to ECMA262r3 we need to insert */ \ /* undefined values increasing length to newLength. */ \ /* We cannot, so we insert default-values instead. */ \ + QT_TRY { \ + c.reserve(newCount); \ + } QT_CATCH (std::bad_alloc &exception) { \ + generateWarning(engine, QString(QLatin1String(exception.what()) \ + + QLatin1String(" during length set"))); \ + return; /* failed; don't write back any result. */ \ + } \ while (newCount > count++) { \ - QT_TRY { \ - c.append(DefaultValue); \ - } QT_CATCH (std::bad_alloc &exception) { \ - generateWarning(engine, QString(QLatin1String(exception.what()) \ - + QLatin1String(" during length set"))); \ - return; /* failed; don't write back any result. */ \ - } \ + c.append(DefaultValue); \ } \ } else { \ /* according to ECMA262r3 we need to remove */ \ @@ -382,15 +384,16 @@ static QString convertUrlToString(QV8Engine *, const QUrl &v) /* according to ECMA262r3 we need to insert */ \ /* the value at the given index, increasing length to index+1. */ \ QT_TRY { \ - while (signedIdx > count++) { \ - c.append(DefaultValue); \ - } \ - c.append(elementValue); \ + c.reserve(signedIdx + 1); \ } QT_CATCH (std::bad_alloc &exception) { \ generateWarning(engine, QString(QLatin1String(exception.what()) \ + QLatin1String(" during indexed set"))); \ return v8::Undefined(); /* failed; don't write back any result. */ \ } \ + while (signedIdx > count++) { \ + c.append(DefaultValue); \ + } \ + c.append(elementValue); \ } \ /* write back. already checked that object is non-null, so skip that check here. */ \ if (objectType == QV8SequenceResource::Reference) \ diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.indexes.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.indexes.qml index 23f1e90..962e8dd 100644 --- a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.indexes.qml +++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.indexes.qml @@ -71,19 +71,5 @@ Item { success = false; if (!verifyExpected(msco.intListProperty, 4)) success = false; - - // NOTE: while these two operations are technically - // fine, we expect std::bad_alloc exceptions here - // which we handle in the sequence wrapper. - msco.intListProperty.length = maxIndex; - if (msco.intListProperty.length != expectedLength) - success = false; - if (!verifyExpected(msco.intListProperty, 4)) - success = false; - msco.intListProperty[maxIndex] = 15; - if (msco.intListProperty.length != expectedLength) - success = false; - if (!verifyExpected(msco.intListProperty, 4)) - success = false; } } diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 0dc0e5a..5770dc4 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -4649,13 +4649,9 @@ void tst_qqmlecmascript::sequenceConversionIndexes() QString w1 = qmlFile.toString() + QLatin1String(":34: Index out of range during length set"); QString w2 = qmlFile.toString() + QLatin1String(":41: Index out of range during indexed set"); QString w3 = qmlFile.toString() + QLatin1String(":48: Index out of range during indexed get"); - QString w4 = qmlFile.toString() + QLatin1String(":78: std::bad_alloc during length set"); - QString w5 = qmlFile.toString() + QLatin1String(":83: std::bad_alloc during indexed set"); QTest::ignoreMessage(QtWarningMsg, qPrintable(w1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(w2)); QTest::ignoreMessage(QtWarningMsg, qPrintable(w3)); - QTest::ignoreMessage(QtWarningMsg, qPrintable(w4)); - QTest::ignoreMessage(QtWarningMsg, qPrintable(w5)); QMetaObject::invokeMethod(object, "indexedAccess"); QVERIFY(object->property("success").toBool()); delete object; -- 2.7.4