aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-11-15 00:06:18 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-11-28 13:47:40 +0100
commitf474eede801ed7bec712069e95bbe2f4ab5558ae (patch)
tree94470e17070c1ff1b9805c38ed2bec10cc9110ff /src
parent140400be0f8a8c91ce02ad5691d81d7604e5a4db (diff)
Add support for accelerated property access to QML types and namespace support
* Resolve lookups in namespaces at compile time and instruct the SSA optimizer to eliminate reads from the namespace (QQmlTypeWrapper) if possible. For example access to attached properties of types (i.e. MyNameSpace.ListView.isCurrentItem) requires neither reading the namespace nor the type. * Add support for accelerated lookup of attached properties Change-Id: Ib0b66404ed7e70e1d4a46a1ac8218743a4cc8608 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp129
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h9
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp9
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h2
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp22
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h2
-rw-r--r--src/qml/compiler/qv4isel_p.cpp6
-rw-r--r--src/qml/compiler/qv4isel_p.h2
-rw-r--r--src/qml/compiler/qv4jsir.cpp24
-rw-r--r--src/qml/compiler/qv4jsir_p.h31
-rw-r--r--src/qml/compiler/qv4regalloc.cpp2
-rw-r--r--src/qml/compiler/qv4ssa.cpp18
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp47
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h6
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp15
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h1
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp4
-rw-r--r--src/qml/qml/qqmlcontextwrapper.cpp6
-rw-r--r--src/qml/qml/qqmldata_p.h3
-rw-r--r--src/qml/qml/qqmlengine.cpp10
20 files changed, 261 insertions, 87 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index c32ad2958d..d80c4d120d 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -1332,6 +1332,97 @@ enum MetaObjectResolverFlags {
LookupsExcludeProperties = 0x4
};
+static void initMetaObjectResolver(V4IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject);
+
+static V4IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, V4IR::MemberExpressionResolver *resolver, V4IR::Member *member)
+{
+ V4IR::Type result = V4IR::VarType;
+
+ QQmlType *type = static_cast<QQmlType*>(resolver->data);
+ if (type->isSingleton()) {
+ if (type->isCompositeSingleton()) {
+ QQmlTypeData *tdata = qmlEngine->typeLoader.getType(type->singletonInstanceInfo()->url);
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+ initMetaObjectResolver(resolver, qmlEngine->propertyCacheForType(tdata->compiledData()->metaTypeId));
+ resolver->flags |= AllPropertiesAreFinal;
+ } else {
+ const QMetaObject *singletonMo = type->singletonInstanceInfo()->instanceMetaObject;
+ if (!singletonMo) { // We can only accelerate C++ singletons that were registered with their meta-type
+ resolver->clear();
+ return result;
+ }
+ initMetaObjectResolver(resolver, qmlEngine->cache(singletonMo));
+ resolver->flags |= LookupsIncludeEnums;
+ }
+ return resolver->resolveMember(qmlEngine, resolver, member);
+ } else {
+ if (member->name->constData()->isUpper()) {
+ bool ok = false;
+ int value = type->enumValue(*member->name, &ok);
+ if (ok) {
+ member->memberIsEnum = true;
+ member->enumValue = value;
+ resolver->clear();
+ return V4IR::SInt32Type;
+ }
+ } else if (const QMetaObject *attachedMeta = type->attachedPropertiesType()) {
+ QQmlPropertyCache *cache = qmlEngine->cache(attachedMeta);
+ initMetaObjectResolver(resolver, cache);
+ member->attachedPropertiesId = type->attachedPropertiesId();
+ return resolver->resolveMember(qmlEngine, resolver, member);
+ }
+ }
+
+ resolver->clear();
+ return result;
+}
+
+static void initQmlTypeResolver(V4IR::MemberExpressionResolver *resolver, QQmlType *qmlType)
+{
+ resolver->resolveMember = &resolveQmlType;
+ resolver->data = qmlType;
+ resolver->extraData = 0;
+ resolver->flags = 0;
+}
+
+static V4IR::Type resolveImportNamespace(QQmlEnginePrivate *, V4IR::MemberExpressionResolver *resolver, V4IR::Member *member)
+{
+ V4IR::Type result = V4IR::VarType;
+ QQmlTypeNameCache *typeNamespace = static_cast<QQmlTypeNameCache*>(resolver->extraData);
+ void *importNamespace = resolver->data;
+
+ QQmlTypeNameCache::Result r = typeNamespace->query(*member->name, importNamespace);
+ if (r.isValid()) {
+ member->freeOfSideEffects = true;
+ if (r.scriptIndex != -1) {
+ // TODO: remember the index and replace with subscript later.
+ result = V4IR::VarType;
+ } else if (r.type) {
+ // TODO: Propagate singleton information, so that it is loaded
+ // through the singleton getter in the run-time. Until then we
+ // can't accelerate access :(
+ if (!r.type->isSingleton()) {
+ initQmlTypeResolver(resolver, r.type);
+ return V4IR::QObjectType;
+ }
+ } else {
+ Q_ASSERT(false); // How can this happen?
+ }
+ }
+
+ resolver->clear();
+ return result;
+}
+
+static void initImportNamespaceResolver(V4IR::MemberExpressionResolver *resolver, QQmlTypeNameCache *imports, const void *importNamespace)
+{
+ resolver->resolveMember = &resolveImportNamespace;
+ resolver->data = const_cast<void*>(importNamespace);
+ resolver->extraData = imports;
+ resolver->flags = 0;
+}
+
static V4IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, V4IR::MemberExpressionResolver *resolver, V4IR::Member *member)
{
V4IR::Type result = V4IR::VarType;
@@ -1397,6 +1488,7 @@ static void initMetaObjectResolver(V4IR::MemberExpressionResolver *resolver, QQm
resolver->resolveMember = &resolveMetaObjectProperty;
resolver->data = metaObject;
resolver->flags = 0;
+ resolver->isQObjectResolver = true;
}
void JSCodeGen::beginFunctionBodyHook()
@@ -1453,35 +1545,24 @@ V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col
return subscript(_block->TEMP(_importedScriptsTemp), _block->CONST(V4IR::SInt32Type, r.scriptIndex));
} else if (r.type) {
V4IR::Name *typeName = _block->NAME(name, line, col);
- V4IR::Temp *result = _block->TEMP(_block->newTemp());
+ // Make sure the run-time loads this through the more efficient singleton getter.
+ typeName->qmlSingleton = r.type->isSingleton();
+ typeName->freeOfSideEffects = true;
- if (r.type->isSingleton()) {
- if (r.type->isCompositeSingleton()) {
- QQmlTypeData *tdata = engine->typeLoader.getType(r.type->singletonInstanceInfo()->url);
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
- initMetaObjectResolver(&result->memberResolver, engine->propertyCacheForType(tdata->compiledData()->metaTypeId));
- result->memberResolver.flags |= AllPropertiesAreFinal;
- } else {
- const QMetaObject *singletonMo = r.type->singletonInstanceInfo()->instanceMetaObject;
- if (!singletonMo) // We can only accelerate C++ singletons that were registered with their meta-type
- return 0;
- initMetaObjectResolver(&result->memberResolver, engine->cache(singletonMo));
- }
+ V4IR::Temp *result = _block->TEMP(_block->newTemp());
+ initQmlTypeResolver(&result->memberResolver, r.type);
- // Instruct the isel to not load this as activation property but through the
- // run-time's singleton getter.
- typeName->qmlSingleton = true;
- } else {
- initMetaObjectResolver(&result->memberResolver,engine->cache(r.type->metaObject()));
- result->memberResolver.flags |= LookupsExcludeProperties;
- }
- typeName->freeOfSideEffects = true;
- result->memberResolver.flags |= LookupsIncludeEnums;
_block->MOVE(result, typeName);
return _block->TEMP(result->index);
} else {
- return 0; // TODO: We can't do fast lookup for these yet.
+ Q_ASSERT(r.importNamespace);
+ V4IR::Name *namespaceName = _block->NAME(name, line, col);
+ namespaceName->freeOfSideEffects = true;
+ V4IR::Temp *result = _block->TEMP(_block->newTemp());
+ initImportNamespaceResolver(&result->memberResolver, imports, r.importNamespace);
+
+ _block->MOVE(result, namespaceName);
+ return _block->TEMP(result->index);
}
}
}
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 180391ff33..5b5667abb4 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -67,6 +67,7 @@ QT_BEGIN_NAMESPACE
F(SetLookup, setLookup) \
F(StoreQObjectProperty, storeQObjectProperty) \
F(LoadQObjectProperty, loadQObjectProperty) \
+ F(LoadAttachedQObjectProperty, loadAttachedQObjectProperty) \
F(Push, push) \
F(CallValue, callValue) \
F(CallProperty, callProperty) \
@@ -288,8 +289,15 @@ union Instr
int propertyIndex;
Param base;
Param result;
+ int attachedPropertiesId;
bool captureRequired;
};
+ struct instr_loadAttachedQObjectProperty {
+ MOTH_INSTR_HEADER
+ int propertyIndex;
+ Param result;
+ int attachedPropertiesId;
+ };
struct instr_storeProperty {
MOTH_INSTR_HEADER
int name;
@@ -692,6 +700,7 @@ union Instr
instr_loadProperty loadProperty;
instr_getLookup getLookup;
instr_loadQObjectProperty loadQObjectProperty;
+ instr_loadAttachedQObjectProperty loadAttachedQObjectProperty;
instr_storeProperty storeProperty;
instr_setLookup setLookup;
instr_storeQObjectProperty storeQObjectProperty;
diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp
index ed57852cd6..67c4f672c6 100644
--- a/src/qml/compiler/qv4isel_masm.cpp
+++ b/src/qml/compiler/qv4isel_masm.cpp
@@ -983,10 +983,13 @@ void InstructionSelection::getProperty(V4IR::Expr *base, const QString &name, V4
}
}
-void InstructionSelection::getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, V4IR::Temp *target)
+void InstructionSelection::getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, V4IR::Temp *target)
{
- generateFunctionCall(target, __qmljs_get_qobject_property, Assembler::ContextRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
- Assembler::TrustedImm32(captureRequired));
+ if (attachedPropertiesId != 0)
+ generateFunctionCall(target, __qmljs_get_attached_property, Assembler::ContextRegister, Assembler::TrustedImm32(attachedPropertiesId), Assembler::TrustedImm32(propertyIndex));
+ else
+ generateFunctionCall(target, __qmljs_get_qobject_property, Assembler::ContextRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
+ Assembler::TrustedImm32(captureRequired));
}
void InstructionSelection::setProperty(V4IR::Expr *source, V4IR::Expr *targetBase,
diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h
index 4b0d19df07..f7987aac5c 100644
--- a/src/qml/compiler/qv4isel_masm_p.h
+++ b/src/qml/compiler/qv4isel_masm_p.h
@@ -1471,7 +1471,7 @@ protected:
virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target);
virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName);
virtual void setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex);
- virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, V4IR::Temp *target);
+ virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, V4IR::Temp *target);
virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target);
virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex);
virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index ee7e8ce2e8..bf9af178fe 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -526,14 +526,22 @@ void InstructionSelection::setQObjectProperty(V4IR::Expr *source, V4IR::Expr *ta
addInstruction(store);
}
-void InstructionSelection::getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, V4IR::Temp *target)
+void InstructionSelection::getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, V4IR::Temp *target)
{
- Instruction::LoadQObjectProperty load;
- load.base = getParam(base);
- load.propertyIndex = propertyIndex;
- load.result = getResultParam(target);
- load.captureRequired = captureRequired;
- addInstruction(load);
+ if (attachedPropertiesId != 0) {
+ Instruction::LoadAttachedQObjectProperty load;
+ load.propertyIndex = propertyIndex;
+ load.result = getResultParam(target);
+ load.attachedPropertiesId = attachedPropertiesId;
+ addInstruction(load);
+ } else {
+ Instruction::LoadQObjectProperty load;
+ load.base = getParam(base);
+ load.propertyIndex = propertyIndex;
+ load.result = getResultParam(target);
+ load.captureRequired = captureRequired;
+ addInstruction(load);
+ }
}
void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target)
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index 031c2d838a..d8a85ff249 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -126,7 +126,7 @@ protected:
virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target);
virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName);
virtual void setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex);
- virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, V4IR::Temp *target);
+ virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, V4IR::Temp *target);
virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target);
virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex);
virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index 96a3370903..7f0d8313fe 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -148,11 +148,11 @@ void IRDecoder::visitMove(V4IR::Move *s)
} else if (V4IR::Member *m = s->source->asMember()) {
if (m->property) {
bool captureRequired = true;
- if (_function) {
+ if (_function && m->attachedPropertiesId == 0) {
captureRequired = !_function->contextObjectDependencies.contains(m->property)
&& !_function->scopeObjectDependencies.contains(m->property);
}
- getQObjectProperty(m->base, m->property->coreIndex, captureRequired, t);
+ getQObjectProperty(m->base, m->property->coreIndex, captureRequired, m->attachedPropertiesId, t);
return;
} else if (m->base->asTemp() || m->base->asConst()) {
getProperty(m->base, *m->name, t);
@@ -191,7 +191,7 @@ void IRDecoder::visitMove(V4IR::Move *s)
} else if (V4IR::Member *m = s->target->asMember()) {
if (m->base->asTemp() || m->base->asConst()) {
if (s->source->asTemp() || s->source->asConst()) {
- if (m->property) {
+ if (m->property && m->attachedPropertiesId == 0) {
setQObjectProperty(s->source, m->base, m->property->coreIndex);
return;
} else {
diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h
index 7ee5cbba4e..5ddafc07ab 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -156,7 +156,7 @@ public: // to implement by subclasses:
virtual void setActivationProperty(V4IR::Expr *source, const QString &targetName) = 0;
virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target) = 0;
virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target) = 0;
- virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, V4IR::Temp *targetTemp) = 0;
+ virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, V4IR::Temp *targetTemp) = 0;
virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName) = 0;
virtual void setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex) = 0;
virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target) = 0;
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index 41502dbd4f..a2dbf44375 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -278,7 +278,7 @@ static QString dumpStart(const Expr *e) {
QString result = typeName(e->type);
const Temp *temp = const_cast<Expr*>(e)->asTemp();
- if (e->type == QObjectType && temp && temp->memberResolver.data) {
+ if (e->type == QObjectType && temp && temp->memberResolver.isQObjectResolver) {
result += QLatin1Char('<');
result += QString::fromUtf8(static_cast<QQmlPropertyCache*>(temp->memberResolver.data)->className());
result += QLatin1Char('>');
@@ -554,7 +554,10 @@ void Subscript::dump(QTextStream &out) const
void Member::dump(QTextStream &out) const
{
- base->dump(out);
+ if (attachedPropertiesId != 0 && !base->asTemp())
+ out << "[[attached property from " << attachedPropertiesId << "]]";
+ else
+ base->dump(out);
out << '.' << *name;
if (property)
out << " (meta-property " << property->coreIndex << " <" << QMetaType::typeName(property->propType) << ">)";
@@ -840,10 +843,17 @@ Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index)
return e;
}
-Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *property)
+Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *property, int attachedPropertiesId)
+{
+ Member*e = function->New<Member>();
+ e->init(base, name, property, attachedPropertiesId);
+ return e;
+}
+
+Expr *BasicBlock::MEMBER(Expr *base, const QString *name, int enumValue)
{
Member*e = function->New<Member>();
- e->init(base, name, property);
+ e->init(base, name, enumValue);
return e;
}
@@ -1033,7 +1043,11 @@ void CloneExpr::visitSubscript(Subscript *e)
void CloneExpr::visitMember(Member *e)
{
- cloned = block->MEMBER(clone(e->base), e->name, e->property);
+ Expr *clonedBase = clone(e->base);
+ if (e->memberIsEnum)
+ cloned = block->MEMBER(clonedBase, e->name, e->enumValue);
+ else
+ cloned = block->MEMBER(clonedBase, e->name, e->property, e->attachedPropertiesId);
}
} // end of namespace IR
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index aa85c4cf3c..9105a9137d 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -236,14 +236,16 @@ struct MemberExpressionResolver
typedef Type (*ResolveFunction)(QQmlEnginePrivate *engine, MemberExpressionResolver *resolver, Member *member);
MemberExpressionResolver()
- : resolveMember(0), data(0), flags(0) {}
+ : resolveMember(0), data(0), extraData(0), flags(0), isQObjectResolver(false) {}
bool isValid() const { return !!resolveMember; }
void clear() { *this = MemberExpressionResolver(); }
ResolveFunction resolveMember;
- void *data; // Could be pointer to meta object, QQmlTypeNameCache, etc. - depends on resolveMember implementation
- int flags;
+ void *data; // Could be pointer to meta object, importNameSpace, etc. - depends on resolveMember implementation
+ void *extraData; // Could be QQmlTypeNameCache
+ unsigned int flags : 31;
+ unsigned int isQObjectResolver; // neede for IR dump helpers
};
struct Expr {
@@ -555,15 +557,31 @@ struct Member: Expr {
Expr *base;
const QString *name;
QQmlPropertyData *property;
+ int attachedPropertiesId;
int enumValue;
- bool memberIsEnum;
+ bool memberIsEnum : 1;
+ bool freeOfSideEffects : 1;
- void init(Expr *base, const QString *name, QQmlPropertyData *property = 0)
+ void init(Expr *base, const QString *name, QQmlPropertyData *property = 0, int attachedPropertiesId = 0)
{
this->base = base;
this->name = name;
this->property = property;
+ this->attachedPropertiesId = attachedPropertiesId;
+ this->enumValue = 0;
this->memberIsEnum = false;
+ this->freeOfSideEffects = false;
+ }
+
+ void init(Expr *base, const QString *name, int enumValue)
+ {
+ this->base = base;
+ this->name = name;
+ this->property = 0;
+ this->attachedPropertiesId = 0;
+ this->enumValue = enumValue;
+ this->memberIsEnum = true;
+ this->freeOfSideEffects = false;
}
virtual void accept(ExprVisitor *v) { v->visitMember(this); }
@@ -869,7 +887,8 @@ struct BasicBlock {
Expr *CALL(Expr *base, ExprList *args = 0);
Expr *NEW(Expr *base, ExprList *args = 0);
Expr *SUBSCRIPT(Expr *base, Expr *index);
- Expr *MEMBER(Expr *base, const QString *name, QQmlPropertyData *property = 0);
+ Expr *MEMBER(Expr *base, const QString *name, QQmlPropertyData *property = 0, int attachedPropertiesId = 0);
+ Expr *MEMBER(Expr *base, const QString *name, int enumValue);
Stmt *EXP(Expr *expr);
diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp
index 5d1dc14500..5d341ed149 100644
--- a/src/qml/compiler/qv4regalloc.cpp
+++ b/src/qml/compiler/qv4regalloc.cpp
@@ -435,7 +435,7 @@ protected: // IRDecoder
addCall();
}
- virtual void getQObjectProperty(V4IR::Expr *base, int /*propertyIndex*/, bool /*captureRequired*/, V4IR::Temp *target)
+ virtual void getQObjectProperty(V4IR::Expr *base, int /*propertyIndex*/, bool /*captureRequired*/, int /*attachedPropertiesId*/, V4IR::Temp *target)
{
addDef(target);
addUses(base->asTemp(), Use::CouldHaveRegister);
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index f9acf99a65..5e2c7ba722 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -1260,6 +1260,8 @@ protected:
virtual void visitMember(Member *e) {
e->base->accept(this);
+ if (e->freeOfSideEffects)
+ return;
markAsSideEffect();
}
@@ -2514,14 +2516,22 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses)
}
continue;
}
- if (Member *potentialEnumMember = m->source->asMember()) {
- if (potentialEnumMember->memberIsEnum) {
+ if (Member *member = m->source->asMember()) {
+ if (member->memberIsEnum) {
Const *c = function->New<Const>();
- c->init(SInt32Type, potentialEnumMember->enumValue);
+ c->init(SInt32Type, member->enumValue);
W += replaceUses(targetTemp, c);
defUses.removeDef(*targetTemp);
*ref[s] = 0;
- defUses.removeUse(s, *potentialEnumMember->base->asTemp());
+ defUses.removeUse(s, *member->base->asTemp());
+ continue;
+ } else if (member->attachedPropertiesId != 0 && member->property && member->base->asTemp()) {
+ // Attached properties have no dependency on their base. Isel doesn't
+ // need it and we can eliminate the temp used to initialize it.
+ defUses.removeUse(s, *member->base->asTemp());
+ Const *c = function->New<Const>();
+ c->init(SInt32Type, 0);
+ member->base = c;
continue;
}
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index f1b0e0bdc4..c48b6bf61d 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -331,23 +331,23 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD
if (hasProperty)
*hasProperty = true;
- return getProperty(ctx, result);
+ return getProperty(m_object, ctx, result);
}
-ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired)
+ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired)
{
QV4::Scope scope(ctx);
if (property->isFunction() && !property->isVarProperty()) {
if (property->isVMEFunction()) {
- QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_object);
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmemo);
return vmemo->vmeMethod(property->coreIndex);
} else if (property->isV4Function()) {
QV4::Scoped<QV4::Object> qmlcontextobject(scope, ctx->engine->qmlContextObject());
- return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, property->coreIndex, qmlcontextobject);
+ return QV4::QObjectMethod::create(ctx->engine->rootContext, object, property->coreIndex, qmlcontextobject);
} else if (property->isSignalHandler()) {
- QV4::Scoped<QV4::QmlSignalHandler> handler(scope, new (ctx->engine->memoryManager) QV4::QmlSignalHandler(ctx->engine, m_object, property->coreIndex));
+ QV4::Scoped<QV4::QmlSignalHandler> handler(scope, new (ctx->engine->memoryManager) QV4::QmlSignalHandler(ctx->engine, object, property->coreIndex));
QV4::ScopedString connect(scope, ctx->engine->newIdentifier(QStringLiteral("connect")));
QV4::ScopedString disconnect(scope, ctx->engine->newIdentifier(QStringLiteral("disconnect")));
@@ -356,7 +356,7 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyDat
return handler.asReturnedValue();
} else {
- return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, property->coreIndex);
+ return QV4::QObjectMethod::create(ctx->engine->rootContext, object, property->coreIndex);
}
}
@@ -369,14 +369,14 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyDat
if (ep && ep->propertyCapture && property->accessors->notifier)
nptr = &n;
- QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->engine->v8Engine, m_object, *property, nptr));
+ QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->engine->v8Engine, object, *property, nptr));
if (captureRequired) {
if (property->accessors->notifier) {
if (n)
ep->captureProperty(n);
} else {
- ep->captureProperty(m_object, property->coreIndex, property->notifyIndex);
+ ep->captureProperty(object, property->coreIndex, property->notifyIndex);
}
}
@@ -384,16 +384,16 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyDat
}
if (captureRequired && ep && !property->isConstant())
- ep->captureProperty(m_object, property->coreIndex, property->notifyIndex);
+ ep->captureProperty(object, property->coreIndex, property->notifyIndex);
if (property->isVarProperty()) {
- QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_object);
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmemo);
return vmemo->vmeProperty(property->coreIndex);
} else if (property->isDirect()) {
- return LoadProperty<ReadAccessor::Direct>(ctx->engine->v8Engine, m_object, *property, 0);
+ return LoadProperty<ReadAccessor::Direct>(ctx->engine->v8Engine, object, *property, 0);
} else {
- return LoadProperty<ReadAccessor::Indirect>(ctx->engine->v8Engine, m_object, *property, 0);
+ return LoadProperty<ReadAccessor::Indirect>(ctx->engine->v8Engine, object, *property, 0);
}
}
@@ -583,7 +583,7 @@ ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object)
ddata->jsEngineId == 0 || // No one owns the QObject
!ddata->hasTaintedV8Object)) { // Someone else has used the QObject, but it isn't tainted
- QV4::ScopedValue rv(scope, create(engine, ddata, object));
+ QV4::ScopedValue rv(scope, create(engine, object));
ddata->jsWrapper = rv;
ddata->jsEngineId = engine->m_engineId;
return rv.asReturnedValue();
@@ -598,14 +598,14 @@ ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object)
// If our tainted handle doesn't exist or has been collected, and there isn't
// a handle in the ddata, we can assume ownership of the ddata->v8object
if (ddata->jsWrapper.isUndefined() && !alternateWrapper) {
- QV4::ScopedValue result(scope, create(engine, ddata, object));
+ QV4::ScopedValue result(scope, create(engine, object));
ddata->jsWrapper = result;
ddata->jsEngineId = engine->m_engineId;
return result.asReturnedValue();
}
if (!alternateWrapper) {
- alternateWrapper = create(engine, ddata, object);
+ alternateWrapper = create(engine, object);
if (!engine->m_multiplyWrappedQObjects)
engine->m_multiplyWrappedQObjects = new MultiplyWrappedQObjectMap;
engine->m_multiplyWrappedQObjects->insert(object, alternateWrapper.getPointer());
@@ -616,11 +616,11 @@ ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object)
}
}
-ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, int propertyIndex, bool captureRequired)
+ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx, int propertyIndex, bool captureRequired)
{
- if (QQmlData::wasDeleted(m_object))
+ if (QQmlData::wasDeleted(object))
return QV4::Encode::null();
- QQmlData *ddata = QQmlData::get(m_object, /*create*/false);
+ QQmlData *ddata = QQmlData::get(object, /*create*/false);
if (!ddata)
return QV4::Encode::undefined();
@@ -628,7 +628,7 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, int propertyInd
Q_ASSERT(cache);
QQmlPropertyData *property = cache->property(propertyIndex);
Q_ASSERT(property); // We resolved this property earlier, so it better exist!
- return getProperty(ctx, property, captureRequired);
+ return getProperty(object, ctx, property, captureRequired);
}
void QObjectWrapper::setProperty(ExecutionContext *ctx, int propertyIndex, const ValueRef value)
@@ -655,14 +655,11 @@ bool QObjectWrapper::isEqualTo(Managed *a, Managed *b)
return false;
}
-ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QQmlData *ddata, QObject *object)
+ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QObject *object)
{
QQmlEngine *qmlEngine = engine->v8Engine->engine();
- if (!ddata->propertyCache && qmlEngine) {
- ddata->propertyCache = QQmlEnginePrivate::get(qmlEngine)->cache(object);
- if (ddata->propertyCache) ddata->propertyCache->addref();
- }
-
+ if (qmlEngine)
+ QQmlData::ensurePropertyCache(qmlEngine, object);
return (new (engine->memoryManager) QV4::QObjectWrapper(engine, object))->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index a73c96d098..07de1933c5 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -94,17 +94,17 @@ struct Q_QML_EXPORT QObjectWrapper : public QV4::Object
using Object::get;
- ReturnedValue getProperty(ExecutionContext *ctx, int propertyIndex, bool captureRequired);
+ static ReturnedValue getProperty(QObject *object, ExecutionContext *ctx, int propertyIndex, bool captureRequired);
void setProperty(ExecutionContext *ctx, int propertyIndex, const ValueRef value);
protected:
static bool isEqualTo(Managed *that, Managed *o);
private:
- ReturnedValue getProperty(ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired = true);
+ static ReturnedValue getProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired = true);
static void setProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, const ValueRef value);
- static ReturnedValue create(ExecutionEngine *engine, QQmlData *ddata, QObject *object);
+ static ReturnedValue create(ExecutionEngine *engine, QObject *object);
QObjectWrapper(ExecutionEngine *engine, QObject *object);
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index a5a93e1f84..50fea04b2f 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -53,6 +53,7 @@
#include "qv4scopedvalue_p.h"
#include <private/qqmlcontextwrapper_p.h>
#include "qv4qobjectwrapper_p.h"
+#include <private/qv8engine_p.h>
#include <QtCore/qmath.h>
#include <QtCore/qnumeric.h>
@@ -1268,7 +1269,19 @@ ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef
ctx->throwTypeError(QStringLiteral("Cannot read property of null"));
return Encode::undefined();
}
- return wrapper->getProperty(ctx, propertyIndex, captureRequired);
+ return QV4::QObjectWrapper::getProperty(wrapper->object(), ctx, propertyIndex, captureRequired);
+}
+
+QV4::ReturnedValue __qmljs_get_attached_property(ExecutionContext *ctx, int attachedPropertiesId, int propertyIndex)
+{
+ Scope scope(ctx);
+ QV4::Scoped<QmlContextWrapper> c(scope, ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>());
+ QObject *scopeObject = c->getScopeObject();
+ QObject *attachedObject = qmlAttachedPropertiesObjectById(attachedPropertiesId, scopeObject);
+
+ QQmlEngine *qmlEngine = ctx->engine->v8Engine->engine();
+ QQmlData::ensurePropertyCache(qmlEngine, attachedObject);
+ return QV4::QObjectWrapper::getProperty(attachedObject, ctx, propertyIndex, /*captureRequired*/true);
}
void __qmljs_set_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value)
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index da596b180c..9524b2459c 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -176,6 +176,7 @@ QV4::ReturnedValue __qmljs_get_imported_scripts(NoThrowContext *ctx);
QV4::ReturnedValue __qmljs_get_context_object(NoThrowContext *ctx);
QV4::ReturnedValue __qmljs_get_scope_object(NoThrowContext *ctx);
QV4::ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, bool captureRequired);
+QV4::ReturnedValue __qmljs_get_attached_property(ExecutionContext *ctx, int attachedPropertiesId, int propertyIndex);
void __qmljs_set_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value);
QV4::ReturnedValue __qmljs_get_qml_singleton(NoThrowContext *ctx, const QV4::StringRef name);
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 00672fea0f..9d6540ebe9 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -320,6 +320,10 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
STOREVALUE(instr.result, __qmljs_get_qobject_property(context, VALUEPTR(instr.base), instr.propertyIndex, instr.captureRequired));
MOTH_END_INSTR(LoadQObjectProperty)
+ MOTH_BEGIN_INSTR(LoadAttachedQObjectProperty)
+ STOREVALUE(instr.result, __qmljs_get_attached_property(context, instr.attachedPropertiesId, instr.propertyIndex));
+ MOTH_END_INSTR(LoadAttachedQObjectProperty)
+
MOTH_BEGIN_INSTR(Push)
TRACE(inline, "stack size: %u", instr.value);
stackSize = instr.value;
diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp
index 0b3b282061..54b540bb4c 100644
--- a/src/qml/qml/qqmlcontextwrapper.cpp
+++ b/src/qml/qml/qqmlcontextwrapper.cpp
@@ -53,6 +53,7 @@
#include <private/qv4compileddata_p.h>
#include <private/qqmltypewrapper_p.h>
#include <private/qqmllistwrapper_p.h>
+#include <private/qjsvalue_p.h>
QT_BEGIN_NAMESPACE
@@ -427,8 +428,9 @@ ReturnedValue QmlContextWrapper::qmlSingletonWrapper(const StringRef &name)
QQmlType::SingletonInstanceInfo *siinfo = r.type->singletonInstanceInfo();
siinfo->init(e);
- QObject *qobjectSingleton = siinfo->qobjectApi(e);
- return QV4::QObjectWrapper::wrap(engine(), qobjectSingleton);
+ if (QObject *qobjectSingleton = siinfo->qobjectApi(e))
+ return QV4::QObjectWrapper::wrap(engine(), qobjectSingleton);
+ return QJSValuePrivate::get(siinfo->scriptApi(e))->getValue(engine());
}
DEFINE_MANAGED_VTABLE(QQmlIdObjectsArray);
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 621b3d3c2e..982156ea15 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -61,6 +61,7 @@
QT_BEGIN_NAMESPACE
template <class Key, class T> class QHash;
+class QQmlEngine;
class QQmlGuardImpl;
class QQmlCompiledData;
class QQmlAbstractBinding;
@@ -222,6 +223,8 @@ public:
static inline void flushPendingBinding(QObject *, int coreIndex);
+ static void ensurePropertyCache(QQmlEngine *engine, QObject *object);
+
private:
// For attachedProperties
mutable QQmlDataExtended *extendedData;
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 1eec710c84..5b05576129 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -1734,6 +1734,16 @@ void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex)
QQmlData_setBit(this, obj, coreIndex * 2 + 1);
}
+void QQmlData::ensurePropertyCache(QQmlEngine *engine, QObject *object)
+{
+ Q_ASSERT(engine);
+ QQmlData *ddata = QQmlData::get(object, /*create*/true);
+ if (ddata->propertyCache)
+ return;
+ ddata->propertyCache = QQmlEnginePrivate::get(engine)->cache(object);
+ if (ddata->propertyCache) ddata->propertyCache->addref();
+}
+
void QQmlEnginePrivate::sendQuit()
{
Q_Q(QQmlEngine);