diff options
-rw-r--r-- | src/qml/compiler/qqmlcodegenerator.cpp | 129 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 9 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm.cpp | 9 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth.cpp | 22 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.cpp | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir.cpp | 24 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir_p.h | 31 | ||||
-rw-r--r-- | src/qml/compiler/qv4regalloc.cpp | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4ssa.cpp | 18 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 47 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper_p.h | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 15 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlcontextwrapper.cpp | 6 | ||||
-rw-r--r-- | src/qml/qml/qqmldata_p.h | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 10 |
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); |