From 71338b4b2f01268759f7ac6b3eff5abb17420a7c Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 25 Oct 2013 14:23:39 +0200 Subject: Resolve member expressions of QObject members ...when the base is a QObject property itself or an ID referenced object. This patch resolves for example the width property in a parent.width expression to be a per-index lookup at run-time. That requires the base ("parent") however to be a final property or come from an object where expected revision is known, i.e. a QML imported object (scope or context). Change-Id: Iaa1f57ace452da5e059c1d4e63b52b316e1a6b08 Reviewed-by: Lars Knoll --- src/qml/compiler/qqmlcodegenerator.cpp | 54 +++++++++++++++++++++++++++++++--- src/qml/compiler/qqmlcodegenerator_p.h | 7 ++++- src/qml/compiler/qv4codegen_p.h | 2 +- src/qml/qml/qqmlcompiler.cpp | 3 +- src/qml/qml/qqmltypeloader.cpp | 5 ++-- 5 files changed, 62 insertions(+), 9 deletions(-) diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp index 7b1984fce0..5fefa61a7a 100644 --- a/src/qml/compiler/qqmlcodegenerator.cpp +++ b/src/qml/compiler/qqmlcodegenerator.cpp @@ -1198,8 +1198,9 @@ int QmlUnitGenerator::getStringId(const QString &str) const return jsUnitGenerator->getStringId(str); } -JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule, Engine *jsEngine, AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports) +JSCodeGen::JSCodeGen(QQmlEnginePrivate *enginePrivate, const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule, Engine *jsEngine, AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports) : QQmlJS::Codegen(/*strict mode*/false) + , engine(enginePrivate) , sourceCode(sourceCode) , jsEngine(jsEngine) , qmlRoot(qmlRoot) @@ -1283,14 +1284,16 @@ QVector JSCodeGen::generateJSCodeForFunctionsAndBindings(const QListproperty(name, /*object*/0, /*context*/0); // Q_INVOKABLEs can't be FINAL, so we have to look them up at run-time if (pd && pd->isFunction()) { - *propertyExistsButForceNameLookup = true; + if (propertyExistsButForceNameLookup) + *propertyExistsButForceNameLookup = true; pd = 0; } @@ -1300,6 +1303,49 @@ static QQmlPropertyData *lookupQmlCompliantProperty(QQmlPropertyCache *cache, co return pd; } +V4IR::Expr *JSCodeGen::member(V4IR::Expr *base, const QString *name) +{ + V4IR::Member *baseAsMember = base->asMember(); + if (baseAsMember) { + QQmlPropertyCache *cache = 0; + + if (baseAsMember->type == V4IR::Member::MemberOfQObject + && baseAsMember->property->isQObject()) { + + bool propertySuitable = baseAsMember->property->isFinal(); + + if (!propertySuitable) { + // Properties of the scope or context object do not need to be final, as we + // intend to find the version of a property available at compile time, not at run-time. + if (V4IR::Name *baseName = baseAsMember->base->asName()) + propertySuitable = baseName->builtin == V4IR::Name::builtin_qml_scope_object || baseName->builtin == V4IR::Name::builtin_qml_context_object; + } + + // Check if it's suitable for caching + if (propertySuitable) + cache = engine->propertyCacheForType(baseAsMember->property->propType); + } else if (baseAsMember->type == V4IR::Member::MemberByObjectId) { + // Similarly, properties of an id referenced object also don't need to be final, because + // we intend to find the version of a property available at compile time, not at run-time. + foreach (const IdMapping &mapping, _idObjects) { + if (baseAsMember->objectId == mapping.idIndex) { + cache = mapping.type; + break; + } + } + } + + if (cache) { + if (QQmlPropertyData *pd = lookupQmlCompliantProperty(cache, *name)) { + const unsigned baseTemp = _block->newTemp(); + move(_block->TEMP(baseTemp), base); + return _block->QML_QOBJECT_PROPERTY(_block->TEMP(baseTemp), name, pd); + } + } + } + return QQmlJS::Codegen::member(base, name); +} + V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col) { V4IR::Expr *result = 0; diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h index 43bc979205..d077bff6db 100644 --- a/src/qml/compiler/qqmlcodegenerator_p.h +++ b/src/qml/compiler/qqmlcodegenerator_p.h @@ -347,13 +347,14 @@ private: struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen { - JSCodeGen(const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule, + JSCodeGen(QQmlEnginePrivate *enginePrivate, const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule, QQmlJS::Engine *jsEngine, AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports); struct IdMapping { QString name; int idIndex; + QQmlPropertyCache *type; }; typedef QVector ObjectIdMapping; @@ -363,10 +364,14 @@ struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen // Returns mapping from input functions to index in V4IR::Module::functions / compiledData->runtimeFunctions QVector generateJSCodeForFunctionsAndBindings(const QList &functions); + // Resolve QObject members with the help of QQmlEngine's meta type registry + virtual V4IR::Expr *member(V4IR::Expr *base, const QString *name); + protected: virtual V4IR::Expr *fallbackNameLookup(const QString &name, int line, int col); private: + QQmlEnginePrivate *engine; QString sourceCode; QQmlJS::Engine *jsEngine; // needed for memory pool AST::UiProgram *qmlRoot; diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index f5cdd27efa..490e469dc7 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -291,7 +291,7 @@ protected: _exceptionHandlers.pop(); } - V4IR::Expr *member(V4IR::Expr *base, const QString *name); + virtual V4IR::Expr *member(V4IR::Expr *base, const QString *name); // Re-implemented by QML to resolve QObject property members V4IR::Expr *subscript(V4IR::Expr *base, V4IR::Expr *index); V4IR::Expr *argument(V4IR::Expr *expr); V4IR::Expr *reference(V4IR::Expr *expr); diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index 3f57d7c2ef..fc8570d128 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -3657,7 +3657,7 @@ bool QQmlCompiler::completeComponentBuild() const QString &sourceCode = jsEngine->code(); AST::UiProgram *qmlRoot = parser.qmlRoot(); - JSCodeGen jsCodeGen(unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, output->importCache); + JSCodeGen jsCodeGen(enginePrivate, unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, output->importCache); JSCodeGen::ObjectIdMapping idMapping; if (compileState->ids.count() > 0) { @@ -3666,6 +3666,7 @@ bool QQmlCompiler::completeComponentBuild() JSCodeGen::IdMapping m; m.name = o->id; m.idIndex = o->idIndex; + m.type = o->metatype; idMapping << m; } } diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index b3bc5eb4a1..8d9c4ef2fe 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2307,6 +2307,7 @@ void QQmlTypeData::compile() m_compiledData->importCache->addref(); QQmlEngine *engine = typeLoader()->engine(); + QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine); for (QHash::ConstIterator resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) { @@ -2357,7 +2358,7 @@ void QQmlTypeData::compile() // Compile JS binding expressions and signal handlers - JSCodeGen jsCodeGen(finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, m_compiledData->importCache); + JSCodeGen jsCodeGen(enginePrivate, finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, m_compiledData->importCache); const QVector runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(parsedQML->functions); QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine()); @@ -2389,7 +2390,7 @@ void QQmlTypeData::compile() m_compiledData->datas.reserve(qmlUnit->nObjects); m_compiledData->propertyCaches.reserve(qmlUnit->nObjects); - QQmlPropertyCacheCreator propertyCacheBuilder(QQmlEnginePrivate::get(m_typeLoader->engine()), + QQmlPropertyCacheCreator propertyCacheBuilder(enginePrivate, qmlUnit, m_compiledData->url, &m_imports, &m_compiledData->resolvedTypes); -- cgit v1.2.3