aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@digia.com>2016-04-04 15:58:45 +0200
committerErik Verbruggen <erik.verbruggen@theqtcompany.com>2016-04-04 14:15:19 +0000
commitfcbbedc3c21ff69d9251264dd708d6ca66c09359 (patch)
treefad2efa8f745c9c461d3a9fd07f51d9ff505108d
parentad1b0b6e7a6b5d266a36138295e6a58ad98fd1ef (diff)
QML: do not re-use the resolver data for members.
On successful lookup, the resolver data was cleared and re-used for the resolved member. The effect is that a second time the resolver is used, it will not be able to do the same lookup, resulting in it returning an unknown type. Because the same expression might need to be resolved multiple times (e.g. when a dependency changes type), this results in the wrong type (var), and then more iterations to propagate this wrong type to all usages. Instead, return a new resolver with its own data for the resolved member. This way, a member access on this result can be resolved correctly by this new resolver. Change-Id: Ia930c08a2e4a2182d800192547fc03cba209c78c Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp66
-rw-r--r--src/qml/compiler/qv4jsir_p.h29
-rw-r--r--src/qml/compiler/qv4ssa.cpp23
3 files changed, 71 insertions, 47 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index a34c1cbf0e..1960f1d65b 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1589,7 +1589,9 @@ enum MetaObjectResolverFlags {
static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject);
-static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::MemberExpressionResolver *resolver, QV4::IR::Member *member)
+static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine,
+ const QV4::IR::MemberExpressionResolver *resolver,
+ QV4::IR::Member *member)
{
QV4::IR::Type result = QV4::IR::VarType;
@@ -1600,7 +1602,6 @@ static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::Membe
int value = type->enumValue(qmlEngine, *member->name, &ok);
if (ok) {
member->setEnumValue(value);
- resolver->clear();
return QV4::IR::SInt32Type;
}
}
@@ -1611,25 +1612,30 @@ static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::Membe
tdata->release(); // Decrease the reference count added from QQmlTypeLoader::getType()
// When a singleton tries to reference itself, it may not be complete yet.
if (tdata->isComplete()) {
- initMetaObjectResolver(resolver, qmlEngine->propertyCacheForType(tdata->compiledData()->metaTypeId));
- resolver->flags |= AllPropertiesAreFinal;
- return resolver->resolveMember(qmlEngine, resolver, member);
+ auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
+ newResolver->owner = resolver->owner;
+ initMetaObjectResolver(newResolver, qmlEngine->propertyCacheForType(tdata->compiledData()->metaTypeId));
+ newResolver->flags |= AllPropertiesAreFinal;
+ return newResolver->resolveMember(qmlEngine, newResolver, member);
}
} else if (type->isSingleton()) {
const QMetaObject *singletonMeta = type->singletonInstanceInfo()->instanceMetaObject;
if (singletonMeta) { // QJSValue-based singletons cannot be accelerated
- initMetaObjectResolver(resolver, qmlEngine->cache(singletonMeta));
+ auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
+ newResolver->owner = resolver->owner;
+ initMetaObjectResolver(newResolver, qmlEngine->cache(singletonMeta));
member->kind = QV4::IR::Member::MemberOfSingletonObject;
- return resolver->resolveMember(qmlEngine, resolver, member);
+ return newResolver->resolveMember(qmlEngine, newResolver, member);
}
} else if (const QMetaObject *attachedMeta = type->attachedPropertiesType(qmlEngine)) {
QQmlPropertyCache *cache = qmlEngine->cache(attachedMeta);
- initMetaObjectResolver(resolver, cache);
+ auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
+ newResolver->owner = resolver->owner;
+ initMetaObjectResolver(newResolver, cache);
member->setAttachedPropertiesId(type->attachedPropertiesId(qmlEngine));
- return resolver->resolveMember(qmlEngine, resolver, member);
+ return newResolver->resolveMember(qmlEngine, newResolver, member);
}
- resolver->clear();
return result;
}
@@ -1643,7 +1649,9 @@ static void initQmlTypeResolver(QV4::IR::MemberExpressionResolver *resolver, QQm
resolver->flags = 0;
}
-static QV4::IR::Type resolveImportNamespace(QQmlEnginePrivate *, QV4::IR::MemberExpressionResolver *resolver, QV4::IR::Member *member)
+static QV4::IR::DiscoveredType resolveImportNamespace(
+ QQmlEnginePrivate *, const QV4::IR::MemberExpressionResolver *resolver,
+ QV4::IR::Member *member)
{
QV4::IR::Type result = QV4::IR::VarType;
QQmlTypeNameCache *typeNamespace = static_cast<QQmlTypeNameCache*>(resolver->extraData);
@@ -1660,19 +1668,21 @@ static QV4::IR::Type resolveImportNamespace(QQmlEnginePrivate *, QV4::IR::Member
// through the singleton getter in the run-time. Until then we
// can't accelerate access :(
if (!r.type->isSingleton()) {
- initQmlTypeResolver(resolver, r.type);
- return QV4::IR::QObjectType;
+ auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
+ newResolver->owner = resolver->owner;
+ initQmlTypeResolver(newResolver, r.type);
+ return QV4::IR::DiscoveredType(newResolver);
}
} else {
Q_ASSERT(false); // How can this happen?
}
}
- resolver->clear();
return result;
}
-static void initImportNamespaceResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlTypeNameCache *imports, const void *importNamespace)
+static void initImportNamespaceResolver(QV4::IR::MemberExpressionResolver *resolver,
+ QQmlTypeNameCache *imports, const void *importNamespace)
{
resolver->resolveMember = &resolveImportNamespace;
resolver->data = const_cast<void*>(importNamespace);
@@ -1680,7 +1690,9 @@ static void initImportNamespaceResolver(QV4::IR::MemberExpressionResolver *resol
resolver->flags = 0;
}
-static QV4::IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, QV4::IR::MemberExpressionResolver *resolver, QV4::IR::Member *member)
+static QV4::IR::DiscoveredType resolveMetaObjectProperty(
+ QQmlEnginePrivate *qmlEngine, const QV4::IR::MemberExpressionResolver *resolver,
+ QV4::IR::Member *member)
{
QV4::IR::Type result = QV4::IR::VarType;
QQmlPropertyCache *metaObject = static_cast<QQmlPropertyCache*>(resolver->data);
@@ -1694,7 +1706,6 @@ static QV4::IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, QV4
int value = metaEnum.keyToValue(enumName.constData(), &ok);
if (ok) {
member->setEnumValue(value);
- resolver->clear();
return QV4::IR::SInt32Type;
}
}
@@ -1739,21 +1750,25 @@ static QV4::IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, QV4
default:
if (property->isQObject()) {
if (QQmlPropertyCache *cache = qmlEngine->propertyCacheForType(property->propType)) {
- initMetaObjectResolver(resolver, cache);
- return QV4::IR::QObjectType;
+ auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
+ newResolver->owner = resolver->owner;
+ initMetaObjectResolver(newResolver, cache);
+ return QV4::IR::DiscoveredType(newResolver);
}
} else if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType)) {
if (QQmlPropertyCache *cache = qmlEngine->cache(valueTypeMetaObject)) {
- initMetaObjectResolver(resolver, cache);
- resolver->flags |= ResolveTypeInformationOnly;
- return QV4::IR::QObjectType;
+ auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
+ newResolver->owner = resolver->owner;
+ initMetaObjectResolver(newResolver, cache);
+ newResolver->flags |= ResolveTypeInformationOnly;
+ return QV4::IR::DiscoveredType(newResolver);
}
}
break;
}
}
}
- resolver->clear();
+
return result;
}
@@ -1809,6 +1824,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int
result = _block->TEMP(result->index);
if (mapping.type) {
result->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>();
+ result->memberResolver->owner = _function;
initMetaObjectResolver(result->memberResolver, mapping.type);
result->memberResolver->flags |= AllPropertiesAreFinal;
}
@@ -1831,6 +1847,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int
result = _block->TEMP(result->index);
result->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>();
+ result->memberResolver->owner = _function;
initQmlTypeResolver(result->memberResolver, r.type);
return result;
} else {
@@ -1839,6 +1856,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int
namespaceName->freeOfSideEffects = true;
QV4::IR::Temp *result = _block->TEMP(_block->newTemp());
result->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>();
+ result->memberResolver->owner = _function;
initImportNamespaceResolver(result->memberResolver, imports, r.importNamespace);
_block->MOVE(result, namespaceName);
@@ -1855,6 +1873,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int
if (pd) {
QV4::IR::Temp *base = _block->TEMP(_qmlContextTemp);
base->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>();
+ base->memberResolver->owner = _function;
initMetaObjectResolver(base->memberResolver, _scopeObject);
return _block->MEMBER(base, _function->newString(name), pd, QV4::IR::Member::MemberOfQmlScopeObject);
}
@@ -1868,6 +1887,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int
if (pd) {
QV4::IR::Temp *base = _block->TEMP(_qmlContextTemp);
base->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>();
+ base->memberResolver->owner = _function;
initMetaObjectResolver(base->memberResolver, _contextObject);
return _block->MEMBER(base, _function->newString(name), pd, QV4::IR::Member::MemberOfQmlContextObject);
}
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 4dfd63705b..eafecae494 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -244,13 +244,37 @@ struct StmtVisitor {
virtual void visitPhi(Phi *) = 0;
};
+struct MemberExpressionResolver;
+
+struct DiscoveredType {
+ int type;
+ MemberExpressionResolver *memberResolver;
+
+ DiscoveredType() : type(UnknownType), memberResolver(0) {}
+ DiscoveredType(Type t) : type(t), memberResolver(0) { Q_ASSERT(type != QObjectType); }
+ explicit DiscoveredType(int t) : type(t), memberResolver(0) { Q_ASSERT(type != QObjectType); }
+ explicit DiscoveredType(MemberExpressionResolver *memberResolver)
+ : type(QObjectType)
+ , memberResolver(memberResolver)
+ { Q_ASSERT(memberResolver); }
+
+ bool test(Type t) const { return type & t; }
+ bool isNumber() const { return (type & NumberType) && !(type & ~NumberType); }
+
+ bool operator!=(Type other) const { return type != other; }
+ bool operator==(Type other) const { return type == other; }
+ bool operator==(const DiscoveredType &other) const { return type == other.type; }
+ bool operator!=(const DiscoveredType &other) const { return type != other.type; }
+};
struct MemberExpressionResolver
{
- typedef Type (*ResolveFunction)(QQmlEnginePrivate *engine, MemberExpressionResolver *resolver, Member *member);
+ typedef DiscoveredType (*ResolveFunction)(QQmlEnginePrivate *engine,
+ const MemberExpressionResolver *resolver,
+ Member *member);
MemberExpressionResolver()
- : resolveMember(0), data(0), extraData(0), flags(0) {}
+ : resolveMember(0), data(0), extraData(0), owner(nullptr), flags(0) {}
bool isValid() const { return !!resolveMember; }
void clear() { *this = MemberExpressionResolver(); }
@@ -258,6 +282,7 @@ struct MemberExpressionResolver
ResolveFunction resolveMember;
void *data; // Could be pointer to meta object, importNameSpace, etc. - depends on resolveMember implementation
void *extraData; // Could be QQmlTypeNameCache
+ Function *owner;
unsigned int flags;
};
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 39f23ffc71..6a4c1c54d6 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -2073,27 +2073,6 @@ protected:
}
};
-struct DiscoveredType {
- int type;
- MemberExpressionResolver *memberResolver;
-
- DiscoveredType() : type(UnknownType), memberResolver(0) {}
- DiscoveredType(Type t) : type(t), memberResolver(0) { Q_ASSERT(type != QObjectType); }
- explicit DiscoveredType(int t) : type(t), memberResolver(0) { Q_ASSERT(type != QObjectType); }
- explicit DiscoveredType(MemberExpressionResolver *memberResolver)
- : type(QObjectType)
- , memberResolver(memberResolver)
- { Q_ASSERT(memberResolver); }
-
- bool test(Type t) const { return type & t; }
- bool isNumber() const { return (type & NumberType) && !(type & ~NumberType); }
-
- bool operator!=(Type other) const { return type != other; }
- bool operator==(Type other) const { return type == other; }
- bool operator==(const DiscoveredType &other) const { return type == other.type; }
- bool operator!=(const DiscoveredType &other) const { return type != other.type; }
-};
-
class PropagateTempTypes: public StmtVisitor, ExprVisitor
{
const DefUses &defUses;
@@ -2449,7 +2428,7 @@ protected:
if (_ty.fullyTyped && _ty.type.memberResolver && _ty.type.memberResolver->isValid()) {
MemberExpressionResolver *resolver = _ty.type.memberResolver;
- _ty.type.type = resolver->resolveMember(qmlEngine, resolver, e);
+ _ty.type = resolver->resolveMember(qmlEngine, resolver, e);
} else
_ty.type = VarType;
}