aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);