aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2014-04-25 16:19:02 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-06-04 08:25:52 +0200
commit52e07d564b65ed6ce26955a676c7692ad67686c1 (patch)
tree04354cdf1d56776e9b52819f4329b70c57e235dc /src/qml/qml
parent481447ae664fa2998cb03f93f0c066caa2782bf0 (diff)
Rework custom parser integration
The custom parser design used to be so that the custom parser operates on the "AST", creates its own binary representation of the data it needs, stores it in a QByteArray and gets that at object instantiation time. That meant serializing everything necessary. With the introduction of the "binary" QML data structure, that process of serialization becomes obsolete and would require extra work in the custom parsers for example for QQuickStates to store the translation parameters. The clean solution is to eliminate this unnecessary serialization process and instead let the custom parsers do a verification pass at type compile time and then simply operate directly on the QV4::CompiledData::Bindings at object instantiation time. That simplifies the code, and allows for support of translations throughout all list model properties. Additionally this speeds up the creation of state objects and reduces memory consumption. Previously a text: qsTr("foo") binding in states would result in an actual java script binding. After this patch it is merely stored as a string and translated at object instantiation time. Change-Id: I7550274513f54abb09a0ab4de51c4c0bcdb23cae Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/qml')
-rw-r--r--src/qml/qml/qqmlbinding.cpp28
-rw-r--r--src/qml/qml/qqmlbinding_p.h2
-rw-r--r--src/qml/qml/qqmlcompiler_p.h12
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp46
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h10
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp17
6 files changed, 53 insertions, 62 deletions
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 571d78312e..074f568d09 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -71,34 +71,6 @@ QQmlAbstractBinding::VTable QQmlBinding_vtable = {
QQmlBinding::Identifier QQmlBinding::Invalid = -1;
-QQmlBinding *
-QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt)
-{
- if (id < 0)
- return 0;
-
- QQmlBinding *rv = 0;
-
- QQmlContextData *ctxtdata = QQmlContextData::get(ctxt);
- QQmlEnginePrivate *engine = QQmlEnginePrivate::get(ctxt->engine());
- if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
- QQmlTypeData *typeData = engine->typeLoader.getType(ctxtdata->url);
- Q_ASSERT(typeData);
-
- if (QQmlCompiledData *cdata = typeData->compiledData()) {
- QV4::ExecutionEngine *v4 = engine->v4engine();
- QV4::Scope valueScope(v4);
- QV4::Function *runtimeFunction = cdata->compilationUnit->runtimeFunctions[cdata->customParserBindings[id]];
- QV4::ScopedValue function(valueScope, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, obj, runtimeFunction));
- rv = new QQmlBinding(function, obj, ctxtdata);
- }
-
- typeData->release();
- }
-
- return rv;
-}
-
static QQmlJavaScriptExpression::VTable QQmlBinding_jsvtable = {
QQmlBinding::expressionIdentifier,
QQmlBinding::expressionChanged
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index 3c2c832e0c..879129fe85 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -112,8 +112,6 @@ public:
typedef int Identifier;
static Identifier Invalid;
- static QQmlBinding *createBinding(Identifier, QObject *, QQmlContext *);
-
QVariant evaluate();
static QString expressionIdentifier(QQmlJavaScriptExpression *);
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index f3b6f621ce..9f0f80063b 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -136,13 +136,8 @@ public:
// index in first hash is component index, hash inside maps from object index in that scope to integer id
QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
QHash<int, int> objectIndexToIdForRoot;
- // hash key is object index
- struct CustomParserData {
- QByteArray compilationArtifact; // produced by custom parser
- QBitArray bindings; // bindings covered by the custom parser
- };
- QHash<int, CustomParserData> customParserData;
- QVector<int> customParserBindings; // index is binding identifier, value is compiled function index.
+ // hash key is object index, value is indicies of bindings covered by custom parser
+ QHash<int, QBitArray> customParserBindings;
QHash<int, QBitArray> deferredBindingsPerObject; // index is object index
int totalBindingsCount; // Number of bindings used in this type
int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses
@@ -154,9 +149,6 @@ public:
bool isInitialized() const { return hasEngine(); }
void initialize(QQmlEngine *);
- QV4::Function *functionForBindingId(int bindingId) const
- { return compilationUnit->runtimeFunctions[customParserBindings[bindingId]]; }
-
protected:
virtual void destroy(); // From QQmlRefCount
virtual void clear(); // From QQmlCleanup
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index 75acbdb778..312c4a8a10 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -109,6 +109,12 @@ void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const
exceptions << error;
}
+struct StaticQtMetaObject : public QObject
+{
+ static const QMetaObject *get()
+ { return &staticQtMetaObject; }
+};
+
/*!
If \a script is a simple enumeration expression (eg. Text.AlignLeft),
returns the integer equivalent (eg. 1), and sets \a ok to true.
@@ -125,7 +131,34 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
if (dot == -1)
return -1;
- return compiler->evaluateEnum(QString::fromUtf8(script.left(dot)), script.mid(dot+1), ok);
+
+ QString scope = QString::fromUtf8(script.left(dot));
+ QByteArray enumValue = script.mid(dot+1);
+
+ if (scope != QLatin1String("Qt")) {
+ if (imports.isNull())
+ return -1;
+ QQmlType *type = 0;
+
+ if (imports.isT1()) {
+ imports.asT1()->resolveType(scope, &type, 0, 0, 0);
+ } else {
+ QQmlTypeNameCache::Result result = imports.asT2()->query(scope);
+ if (result.isValid())
+ type = result.type;
+ }
+
+ return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1;
+ }
+
+ const QMetaObject *mo = StaticQtMetaObject::get();
+ int i = mo->enumeratorCount();
+ while (i--) {
+ int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
+ if (*ok)
+ return v;
+ }
+ return -1;
}
/*!
@@ -137,17 +170,6 @@ const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const
return compiler->resolveType(name);
}
-QQmlBinding::Identifier QQmlCustomParser::bindingIdentifier(const QV4::CompiledData::Binding *binding)
-{
- return compiler->bindingIdentifier(binding, this);
-}
-
-struct StaticQtMetaObject : public QObject
-{
- static const QMetaObject *get()
- { return &staticQtMetaObject; }
-};
-
int QQmlCustomParserCompilerBackend::evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const
{
Q_ASSERT_X(ok, "QQmlCompiler::evaluateEnum", "ok must not be a null pointer");
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
index 2ce6375870..9e3f810738 100644
--- a/src/qml/qml/qqmlcustomparser_p.h
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -71,8 +71,6 @@ struct QQmlCustomParserCompilerBackend
int evaluateEnum(const QString &scope, const QByteArray& enumValue, bool *ok) const;
const QMetaObject *resolveType(const QString& name) const;
-
- virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *, QQmlCustomParser *) { return QQmlBinding::Invalid; }
};
class Q_QML_PRIVATE_EXPORT QQmlCustomParser
@@ -92,8 +90,8 @@ public:
void clearErrors();
Flags flags() const { return m_flags; }
- virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) = 0;
- virtual void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *cdata) = 0;
+ virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) = 0;
+ virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) = 0;
QList<QQmlError> errors() const { return exceptions; }
@@ -108,13 +106,13 @@ protected:
const QMetaObject *resolveType(const QString&) const;
- QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding);
-
private:
QList<QQmlError> exceptions;
QQmlCustomParserCompilerBackend *compiler;
Flags m_flags;
+ QBiPointer<const QQmlImports, QQmlTypeNameCache> imports;
friend class QQmlPropertyValidator;
+ friend class QQmlObjectCreator;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlCustomParser::Flags)
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 2ebf90c9be..efdf4d86da 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -1123,10 +1123,19 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
QBitArray bindingsToSkip;
if (customParser) {
- QHash<int, QQmlCompiledData::CustomParserData>::ConstIterator entry = compiledData->customParserData.find(index);
- if (entry != compiledData->customParserData.constEnd()) {
- customParser->setCustomData(instance, entry->compilationArtifact, compiledData);
- bindingsToSkip = entry->bindings;
+ QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.find(index);
+ if (customParserBindings != compiledData->customParserBindings.constEnd()) {
+ customParser->imports = compiledData->importCache;
+
+ QList<const QV4::CompiledData::Binding *> bindings;
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
+ for (int i = 0; i < customParserBindings->count(); ++i)
+ if (customParserBindings->testBit(i))
+ bindings << obj->bindingTable() + i;
+ customParser->applyBindings(instance, compiledData, bindings);
+
+ customParser->imports = (QQmlTypeNameCache*)0;
+ bindingsToSkip = *customParserBindings;
}
}