aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-10-25 14:23:39 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-31 16:00:58 +0100
commit71338b4b2f01268759f7ac6b3eff5abb17420a7c (patch)
tree9be8f7484e1a70e3d1d52c75f8bcf971448a3d44
parent76684fd3edcdc8e120c67f82cbd0625bf9bcc0bb (diff)
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 <lars.knoll@digia.com>
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp54
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h7
-rw-r--r--src/qml/compiler/qv4codegen_p.h2
-rw-r--r--src/qml/qml/qqmlcompiler.cpp3
-rw-r--r--src/qml/qml/qqmltypeloader.cpp5
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<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<AST::N
return runtimeFunctionIndices;
}
-static QQmlPropertyData *lookupQmlCompliantProperty(QQmlPropertyCache *cache, const QString &name, bool *propertyExistsButForceNameLookup)
+static QQmlPropertyData *lookupQmlCompliantProperty(QQmlPropertyCache *cache, const QString &name, bool *propertyExistsButForceNameLookup = 0)
{
- *propertyExistsButForceNameLookup = false;
+ if (propertyExistsButForceNameLookup)
+ *propertyExistsButForceNameLookup = false;
QQmlPropertyData *pd = cache->property(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<IdMapping> 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<int> generateJSCodeForFunctionsAndBindings(const QList<AST::Node*> &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<int, TypeReference>::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<int> 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);