diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2014-04-01 11:00:27 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-04-02 14:04:17 +0200 |
commit | c494da09794209d120c8df6b78074c07ad594a15 (patch) | |
tree | dd3c689c102ab05fc3d603ee33bc534a530cec46 | |
parent | 4e012093462f07e7ffd42d4061539c54b4f43ace (diff) |
Reduce memory consumption of runtime compiled QML types
Don't store the string of binding scripts in the compiled data. The only
exception to the rule are properties of type QQmlScriptString as well as types
with custom parsers.
Change-Id: I7f53262bf957b442bac4db71d0a2c0bed74a9b54
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 19 | ||||
-rw-r--r-- | src/qml/compiler/qqmlirbuilder_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 57 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler_p.h | 17 |
4 files changed, 87 insertions, 7 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index e85703e9aa..1c10a49fd1 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -188,6 +188,17 @@ void Object::insertSorted(Binding *b) bindings->insertAfter(insertionPoint, b); } +QString Object::bindingAsString(Document *doc, int scriptIndex) const +{ + CompiledFunctionOrExpression *foe = functionsAndExpressions->slowAt(scriptIndex); + QQmlJS::AST::Node *node = foe->node; + if (QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(node)) + node = exprStmt->expression; + QQmlJS::AST::SourceLocation start = node->firstSourceLocation(); + QQmlJS::AST::SourceLocation end = node->lastSourceLocation(); + return doc->code.mid(start.offset, end.offset + end.length - start.offset); +} + QStringList Signal::parameterStringList(const QV4::Compiler::StringTableGenerator *stringPool) const { QStringList result; @@ -1252,11 +1263,9 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST expr->disableAcceleratedLookups = false; const int index = bindingsTarget()->functionsAndExpressions->append(expr); binding->value.compiledScriptIndex = index; - - QQmlJS::AST::Node *nodeForString = statement; - if (exprStmt) - nodeForString = exprStmt->expression; - binding->stringIndex = registerString(asStringRef(nodeForString).toString()); + // We don't need to store the binding script as string, except for script strings + // and types with custom parsers. Those will be added later in the compilation phase. + binding->stringIndex = emptyStringIndex; } } diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index cd67c52ed7..4ea7e05639 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -283,6 +283,7 @@ public: Binding *findBinding(quint32 nameIndex) const; Binding *unlinkBinding(Binding *before, Binding *binding) { return bindings->unlink(before, binding); } void insertSorted(Binding *b); + QString bindingAsString(Document *doc, int scriptIndex) const; PoolList<CompiledFunctionOrExpression> *functionsAndExpressions; FixedPoolArray<int> *runtimeFunctionIndices; diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index d79143fdc3..b44d4e285a 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -167,6 +167,11 @@ bool QQmlTypeCompiler::compile() } { + QQmlCustomParserScriptIndexer cpi(this); + cpi.annotateBindingsWithScriptStrings(); + } + + { QQmlAliasAnnotator annotator(this); annotator.annotateBindingsToAliases(); } @@ -403,6 +408,11 @@ void QQmlTypeCompiler::setDeferredBindingsPerObject(const QHash<int, QBitArray> compiledData->deferredBindingsPerObject = deferredBindingsPerObject; } +QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scriptIndex) const +{ + return object->bindingAsString(document, scriptIndex); +} + QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler) : compiler(typeCompiler) { @@ -1144,8 +1154,8 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property").arg(stringAt(binding->propertyNameIndex))); Q_ASSERT(binding->type = QV4::CompiledData::Binding::Type_Script); - QString string = stringAt(binding->stringIndex); - if (!string.at(0).isUpper()) + const QString string = compiler->bindingAsString(obj, binding->value.compiledScriptIndex); + if (!string.constData()->isUpper()) return true; int dot = string.indexOf(QLatin1Char('.')); @@ -1234,6 +1244,35 @@ int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &e return -1; } +QQmlCustomParserScriptIndexer::QQmlCustomParserScriptIndexer(QQmlTypeCompiler *typeCompiler) + : QQmlCompilePass(typeCompiler) + , qmlObjects(*typeCompiler->qmlObjects()) + , customParsers(typeCompiler->customParserCache()) +{ +} + +void QQmlCustomParserScriptIndexer::annotateBindingsWithScriptStrings() +{ + scanObjectRecursively(compiler->rootObjectIndex()); +} + +void QQmlCustomParserScriptIndexer::scanObjectRecursively(int objectIndex, bool annotateScriptBindings) +{ + const QmlIR::Object * const obj = qmlObjects.at(objectIndex); + if (!annotateScriptBindings) + annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex); + for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { + if (binding->type >= QV4::CompiledData::Binding::Type_Object) { + scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings); + continue; + } else if (binding->type != QV4::CompiledData::Binding::Type_Script) + continue; + if (!annotateScriptBindings) + continue; + const QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex); + binding->stringIndex = compiler->registerString(script); + } +} QQmlAliasAnnotator::QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler) : QQmlCompilePass(typeCompiler) @@ -1297,6 +1336,9 @@ void QQmlScriptStringScanner::scan() QmlIR::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex); if (foe) foe->disableAcceleratedLookups = true; + + QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex); + binding->stringIndex = compiler->registerString(script); } } } @@ -1702,6 +1744,17 @@ QQmlBinding::Identifier QQmlPropertyValidator::bindingIdentifier(const QV4::Comp return id; } +QString QQmlPropertyValidator::bindingAsString(int objectIndex, const QV4::CompiledData::Binding *binding) const +{ + const QmlIR::Object *object = compiler->qmlObjects()->value(objectIndex); + if (!object) + return QString(); + int reverseIndex = object->runtimeFunctionIndices->indexOf(binding->value.compiledScriptIndex); + if (reverseIndex == -1) + return QString(); + return compiler->bindingAsString(object, reverseIndex); +} + typedef QVarLengthArray<const QV4::CompiledData::Binding *, 8> GroupPropertyVector; static bool compareNameIndices(const QV4::CompiledData::Binding *binding, quint32 name) diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 3b449bf9bd..fb8ac94fcd 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -105,6 +105,8 @@ public: const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; } + QString bindingAsString(const QmlIR::Object *object, int scriptIndex) const; + private: QList<QQmlError> errors; QQmlEnginePrivate *engine; @@ -195,6 +197,20 @@ private: QHash<int, QQmlCompiledData::TypeReference *> *resolvedTypes; }; +class QQmlCustomParserScriptIndexer: public QQmlCompilePass +{ +public: + QQmlCustomParserScriptIndexer(QQmlTypeCompiler *typeCompiler); + + void annotateBindingsWithScriptStrings(); + +private: + void scanObjectRecursively(int objectIndex, bool annotateScriptBindings = false); + + const QList<QmlIR::Object*> &qmlObjects; + const QHash<int, QQmlCustomParser*> &customParsers; +}; + // Annotate properties bound to aliases with a flag class QQmlAliasAnnotator : public QQmlCompilePass { @@ -267,6 +283,7 @@ public: // Re-implemented for QQmlCustomParser virtual const QQmlImports &imports() const; virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *parser); + virtual QString bindingAsString(int objectIndex, const QV4::CompiledData::Binding *binding) const; private: bool validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false); |