aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@theqtcompany.com>2016-04-28 11:09:41 +0200
committerErik Verbruggen <erik.verbruggen@qt.io>2016-05-11 12:23:17 +0000
commit28128f2dc6c5eb63d52658ede840e02b06f9ac2c (patch)
treefee0d69ebf243f41a2567ea3942bcf8c42a07aeb
parent39ce4c70e7cfc6b761c2172fe9b048027c220af4 (diff)
QML: Fill QtObject lazily.
Only iterate over the enumerations/enumerators in the staticQtMetaObject when a get() is done, and the key/value is not yet in stored in the underlying Object. The whole cost of the iteration is now moved to get() and advanceIterator(). The latter will add all items in one swoop, but iteration over QtObject isn't used much (if at all). The get() will add all key/value pairs up until it finds the requested key. Checking a number of applications shows that none of them use all (or the "last") key, so it will actually save entries (which equals memory) too. This change reduces the instruction count for QtObject from 2.7M instructions down to 95k. As this initialization is done from the QQmlEngine constructor, it also speeds up that initialization. Task-number: QTBUG-43770 Change-Id: I71331ff76bdacdd4790f7ff0430c4cbc214fe0ab Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp82
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h14
-rw-r--r--tests/auto/qml/qqmlqt/data/qtObjectContents.qml10
-rw-r--r--tests/auto/qml/qqmlqt/tst_qqmlqt.cpp46
4 files changed, 141 insertions, 11 deletions
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index ed478fa17f..ecfc817d3b 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -87,22 +87,18 @@ struct StaticQtMetaObject : public QObject
};
Heap::QtObject::QtObject(QQmlEngine *qmlEngine)
+ : enumeratorIterator(0)
+ , keyIterator(0)
{
Scope scope(internalClass->engine);
ScopedObject o(scope, this);
- // Set all the enums from the "Qt" namespace
- const QMetaObject *qtMetaObject = StaticQtMetaObject::get();
- ScopedString str(scope);
- ScopedValue v(scope);
- for (int ii = 0, eii = qtMetaObject->enumeratorCount(); ii < eii; ++ii) {
- QMetaEnum enumerator = qtMetaObject->enumerator(ii);
- for (int jj = 0, ejj = enumerator.keyCount(); jj < ejj; ++jj) {
- o->put((str = scope.engine->newString(QString::fromUtf8(enumerator.key(jj)))), (v = QV4::Primitive::fromInt32(enumerator.value(jj))));
- }
+ {
+ ScopedString str(scope);
+ ScopedValue v(scope);
+ o->put((str = scope.engine->newString(QStringLiteral("Asynchronous"))), (v = QV4::Primitive::fromInt32(0)));
+ o->put((str = scope.engine->newString(QStringLiteral("Synchronous"))), (v = QV4::Primitive::fromInt32(1)));
}
- o->put((str = scope.engine->newString(QStringLiteral("Asynchronous"))), (v = QV4::Primitive::fromInt32(0)));
- o->put((str = scope.engine->newString(QStringLiteral("Synchronous"))), (v = QV4::Primitive::fromInt32(1)));
o->defineDefaultProperty(QStringLiteral("include"), QV4Include::method_include);
o->defineDefaultProperty(QStringLiteral("isQtObject"), QV4::QtObject::method_isQtObject);
@@ -151,6 +147,70 @@ Heap::QtObject::QtObject(QQmlEngine *qmlEngine)
o->defineAccessorProperty(QStringLiteral("styleHints"), QV4::QtObject::method_get_styleHints, 0);
}
+void QtObject::addAll()
+{
+ bool dummy = false;
+ findAndAdd(nullptr, dummy);
+}
+
+ReturnedValue QtObject::findAndAdd(const QString *name, bool &foundProperty) const
+{
+ Scope scope(engine());
+ ScopedObject o(scope, this);
+ ScopedString key(scope);
+ ScopedValue value(scope);
+
+ const QMetaObject *qtMetaObject = StaticQtMetaObject::get();
+ for (int enumCount = qtMetaObject->enumeratorCount(); d()->enumeratorIterator < enumCount;
+ ++d()->enumeratorIterator) {
+ QMetaEnum enumerator = qtMetaObject->enumerator(d()->enumeratorIterator);
+ for (int keyCount = enumerator.keyCount(); d()->keyIterator < keyCount; ++d()->keyIterator) {
+ key = scope.engine->newString(QString::fromUtf8(enumerator.key(d()->keyIterator)));
+ value = QV4::Primitive::fromInt32(enumerator.value(d()->keyIterator));
+ o->put(key, value);
+ if (name && key->toQString() == *name) {
+ ++d()->keyIterator;
+ foundProperty = true;
+ return value->asReturnedValue();
+ }
+ }
+ d()->keyIterator = 0;
+ }
+ d()->enumeratorIterator = Heap::QtObject::Finished;
+ foundProperty = false;
+ return Encode::undefined();
+}
+
+ReturnedValue QtObject::get(const Managed *m, String *name, bool *hasProperty)
+{
+ bool hasProp = false;
+ if (hasProperty == nullptr) {
+ hasProperty = &hasProp;
+ }
+
+ ReturnedValue ret = QV4::Object::get(m, name, hasProperty);
+ if (*hasProperty) {
+ return ret;
+ }
+
+ auto that = static_cast<const QtObject*>(m);
+ if (!that->d()->isComplete()) {
+ const QString key = name->toQString();
+ ret = that->findAndAdd(&key, *hasProperty);
+ }
+
+ return ret;
+}
+
+void QtObject::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes)
+{
+ auto that = static_cast<QtObject*>(m);
+ if (!that->d()->isComplete()) {
+ that->addAll();
+ }
+
+ QV4::Object::advanceIterator(m, it, name, index, p, attributes);
+}
/*!
\qmlmethod bool Qt::isQtObject(object)
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
index 53468f062b..dc806c6031 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
@@ -67,6 +67,13 @@ struct QtObject : Object {
QtObject(QQmlEngine *qmlEngine);
QObject *platform;
QObject *application;
+
+ enum { Finished = -1 };
+ int enumeratorIterator;
+ int keyIterator;
+
+ bool isComplete() const
+ { return enumeratorIterator == Finished; }
};
struct ConsoleObject : Object {
@@ -86,6 +93,9 @@ struct QtObject : Object
{
V4_OBJECT2(QtObject, Object)
+ static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
+ static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
+
static ReturnedValue method_isQtObject(CallContext *ctx);
static ReturnedValue method_rgba(CallContext *ctx);
static ReturnedValue method_hsla(CallContext *ctx);
@@ -124,6 +134,10 @@ struct QtObject : Object
static ReturnedValue method_get_inputMethod(CallContext *ctx);
#endif
static ReturnedValue method_get_styleHints(CallContext *ctx);
+
+private:
+ void addAll();
+ ReturnedValue findAndAdd(const QString *name, bool &foundProperty) const;
};
struct ConsoleObject : Object
diff --git a/tests/auto/qml/qqmlqt/data/qtObjectContents.qml b/tests/auto/qml/qqmlqt/data/qtObjectContents.qml
new file mode 100644
index 0000000000..c85e7986e9
--- /dev/null
+++ b/tests/auto/qml/qqmlqt/data/qtObjectContents.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+QtObject {
+ property var values: Object()
+ Component.onCompleted: {
+ for (var key in Qt) {
+ values[key] = Qt[key]
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
index 01283dd587..2f44c34bc2 100644
--- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
+++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
@@ -87,6 +87,7 @@ private slots:
void fontFamilies();
void quit();
void resolvedUrl();
+ void qtObjectContents();
private:
QQmlEngine engine;
@@ -934,6 +935,51 @@ void tst_qqmlqt::resolvedUrl()
delete object;
}
+void tst_qqmlqt::qtObjectContents()
+{
+ struct StaticQtMetaObject : public QObject
+ {
+ static const QMetaObject *get()
+ { return &staticQtMetaObject; }
+ };
+
+ QQmlComponent component(&engine, testFileUrl("qtObjectContents.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QVERIFY(object->property("values").canConvert<QJSValue>());
+ QVariantMap values = object->property("values").value<QJSValue>().toVariant().toMap();
+
+ QSet<const char *> keys;
+ int uniqueKeys = 0;
+ const QMetaObject *qtMetaObject = StaticQtMetaObject::get();
+ for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) {
+ QMetaEnum enumerator = qtMetaObject->enumerator(ii);
+ for (int jj = 0; jj < enumerator.keyCount(); ++jj) {
+ auto key = enumerator.key(jj);
+// qDebug() << "key:" << key;
+ if (!keys.contains(key)) {
+ ++uniqueKeys;
+ keys.insert(key);
+ }
+ QVERIFY(values.contains(key));
+ QVariant value = values.value(key);
+ QVERIFY(value.canConvert<int>());
+ QCOMPARE(value.toInt(), enumerator.value(jj));
+ }
+ }
+ QVERIFY(values.contains("Asynchronous"));
+ QCOMPARE(values.value("Asynchronous").toInt(), 0);
+ ++uniqueKeys;
+ QVERIFY(values.contains("Synchronous"));
+ QCOMPARE(values.value("Synchronous").toInt(), 1);
+ ++uniqueKeys;
+ QCOMPARE(values.count(), uniqueKeys);
+
+ delete object;
+}
+
QTEST_MAIN(tst_qqmlqt)
#include "tst_qqmlqt.moc"