diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-11-29 16:00:17 +0100 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-11-29 16:00:17 +0100 |
commit | 7c7665bbd6609d5c0ee7abd635e37c626b60802b (patch) | |
tree | caf634b0df75f66a3812a0f839da3f0ad66d28ff /src | |
parent | 536e1cccf15963b586f3112a0654ddc0d101fa69 (diff) | |
parent | dd1bd3b01b506a05b475514fb2ba7e387f7b17fa (diff) |
Merge remote-tracking branch 'origin/stable' into dev
Change-Id: I4e057bf60ac718aa359750ea417377580acbfc69
Diffstat (limited to 'src')
35 files changed, 662 insertions, 236 deletions
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp index c32ad2958d..15004801f5 100644 --- a/src/qml/compiler/qqmlcodegenerator.cpp +++ b/src/qml/compiler/qqmlcodegenerator.cpp @@ -45,6 +45,7 @@ #include <private/qqmljsparser_p.h> #include <private/qqmljslexer_p.h> #include <private/qqmlcompiler_p.h> +#include <private/qqmlglobal_p.h> #include <QCoreApplication> #ifdef CONST @@ -53,6 +54,8 @@ QT_USE_NAMESPACE +DEFINE_BOOL_CONFIG_OPTION(lookupHints, QML_LOOKUP_HINTS); + using namespace QtQml; #define COMPILE_EXCEPTION(location, desc) \ @@ -1327,11 +1330,103 @@ QQmlPropertyData *JSCodeGen::lookupQmlCompliantProperty(QQmlPropertyCache *cache static void initMetaObjectResolver(V4IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject); enum MetaObjectResolverFlags { - AllPropertiesAreFinal = 0x1, - LookupsIncludeEnums = 0x2, - LookupsExcludeProperties = 0x4 + AllPropertiesAreFinal = 0x1, + LookupsIncludeEnums = 0x2, + LookupsExcludeProperties = 0x4, + ResolveTypeInformationOnly = 0x8 }; +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; @@ -1359,9 +1454,20 @@ static V4IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, V4IR:: if (QQmlPropertyData *candidate = metaObject->property(*member->name, /*object*/0, /*context*/0)) { const bool isFinalProperty = (candidate->isFinal() || (resolver->flags & AllPropertiesAreFinal)) && !candidate->isFunction(); + + if (lookupHints() + && !(resolver->flags & AllPropertiesAreFinal) + && !candidate->isFinal() + && !candidate->isFunction() + && candidate->isDirect()) { + qWarning() << "Hint: Access to property" << *member->name << "of" << metaObject->className() << "could be accelerated if it was marked as FINAL"; + } + if (isFinalProperty && metaObject->isAllowedInRevision(candidate)) { property = candidate; - member->property = candidate; // Cache for next iteration and isel needs it. + member->inhibitTypeConversionOnWrite = true; + if (!(resolver->flags & ResolveTypeInformationOnly)) + member->property = candidate; // Cache for next iteration and isel needs it. } } } @@ -1383,6 +1489,12 @@ static V4IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, V4IR:: initMetaObjectResolver(resolver, cache); return V4IR::QObjectType; } + } else if (QQmlValueType *valueType = QQmlValueTypeFactory::valueType(property->propType)) { + if (QQmlPropertyCache *cache = qmlEngine->cache(valueType->metaObject())) { + initMetaObjectResolver(resolver, cache); + resolver->flags |= ResolveTypeInformationOnly; + return V4IR::QObjectType; + } } break; } @@ -1397,6 +1509,7 @@ static void initMetaObjectResolver(V4IR::MemberExpressionResolver *resolver, QQm resolver->resolveMember = &resolveMetaObjectProperty; resolver->data = metaObject; resolver->flags = 0; + resolver->isQObjectResolver = true; } void JSCodeGen::beginFunctionBodyHook() @@ -1439,9 +1552,10 @@ V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col _function->idObjectDependencies.insert(mapping.idIndex); V4IR::Expr *s = subscript(_block->TEMP(_idArrayTemp), _block->CONST(V4IR::SInt32Type, mapping.idIndex)); V4IR::Temp *result = _block->TEMP(_block->newTemp()); - initMetaObjectResolver(&result->memberResolver, mapping.type); _block->MOVE(result, s); result = _block->TEMP(result->index); + initMetaObjectResolver(&result->memberResolver, mapping.type); + result->memberResolver.flags |= AllPropertiesAreFinal; result->isReadOnly = true; // don't allow use as lvalue return result; } @@ -1453,35 +1567,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..59e8d02bbc 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,39 @@ 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) + // This is set for example for for QObject properties. All sorts of extra behavior + // is defined when writing to them, for example resettable properties are reset + // when writing undefined to them, and an exception is thrown when they're missing + // a reset function. And then there's also Qt.binding(). + bool inhibitTypeConversionOnWrite: 1; + + 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; + this->inhibitTypeConversionOnWrite = property != 0; + } + + 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; + this->inhibitTypeConversionOnWrite = false; } virtual void accept(ExprVisitor *v) { v->visitMember(this); } @@ -869,7 +895,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..249dfab660 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(); } @@ -1904,12 +1906,8 @@ protected: } } - // Don't convert when writing to QObject properties. All sorts of extra behavior - // is defined when writing to them, for example resettable properties are reset - // when writing undefined to them, and an exception is thrown when they're missing - // a reset function. const Member *targetMember = s->target->asMember(); - const bool inhibitConversion = targetMember && targetMember->property; + const bool inhibitConversion = targetMember && targetMember->inhibitTypeConversionOnWrite; run(s->source, s->target->type, !inhibitConversion); } @@ -2514,14 +2512,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/debugger/qqmlprofilerservice.cpp b/src/qml/debugger/qqmlprofilerservice.cpp index 0ba939cdca..b83de937c6 100644 --- a/src/qml/debugger/qqmlprofilerservice.cpp +++ b/src/qml/debugger/qqmlprofilerservice.cpp @@ -425,4 +425,204 @@ void QQmlProfilerService::messageReceived(const QByteArray &message) m_initializeCondition.wakeAll(); } +/*! + * \brief QQmlVmeProfiler::Data::clear Reset to defaults + * Reset the profiling data to defaults. + */ +void QQmlVmeProfiler::Data::clear() +{ + url = QUrl(); + line = 0; + column = 0; + typeName = QString(); +} + +/*! + * \brief QQmlVmeProfiler::start Start profiler and set data + * \param url URL of file being executed + * \param line Curent line in file + * \param column Current column in file + * \param typeName Type of object be created + * Stops the profiler previously running in the foreground if there is one, then starts a + * new one and sets it up with the data given. + * Preconditions: Profiling must be enabled. + */ +void QQmlVmeProfiler::start(const QUrl &url, int line, int column, const QString &typeName) +{ + Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled."); + if (enabled) { + switchRange(); + updateLocation(url, line, column); + updateTypeName(typeName); + } +} + +/*! + * \brief QQmlVmeProfiler::start Start profiler without data + * Clears the current range data, then stops the profiler previously running in the + * foreground if any, then starts a new one. + * Preconditions: Profiling must be enabled. + */ +void QQmlVmeProfiler::start() +{ + Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled."); + if (enabled) { + currentRange.clear(); + switchRange(); + } +} + +/*! + * \brief QQmlVmeProfiler::switchRange Switch foreground profilers + * Stops the current profiler if any, and starts a new one. + */ +void QQmlVmeProfiler::switchRange() +{ + if (running) + QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating); + else + running = true; + QQmlProfilerService::instance->startRange(QQmlProfilerService::Creating); +} + +/*! + * \brief QQmlVmeProfiler::updateLocation Update current location information + * \param url URL of file being executed + * \param line line Curent line in file + * \param column column Current column in file + * Updates the current profiler's location information. + * Preconditions: Profiling must be enabled and a profiler must be running in the foreground. + */ +void QQmlVmeProfiler::updateLocation(const QUrl &url, int line, int column) +{ + Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled."); + Q_ASSERT_X(running, Q_FUNC_INFO, "trying to update location on stopped profiler"); + if (enabled && running) { + currentRange.url = url; + currentRange.line = line; + currentRange.column = column; + QQmlProfilerService::instance->rangeLocation( + QQmlProfilerService::Creating, url, line, column); + } +} + +/*! + * \brief QQmlVmeProfiler::updateTypeName Update current type information + * \param typeName Type of object being created + * Updates the current profiler's type information. + * Preconditions: Profiling must be enabled and a profiler must be running in the foreground. + */ +void QQmlVmeProfiler::updateTypeName(const QString &typeName) +{ + Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled."); + Q_ASSERT_X(running, Q_FUNC_INFO, "trying to update typeName on stopped profiler"); + if (enabled && running) { + currentRange.typeName = typeName; + QQmlProfilerService::instance->rangeData(QQmlProfilerService::Creating, typeName); + } +} + +/*! + * \brief QQmlVmeProfiler::pop Pops a paused profiler from the stack and restarts it + * Stops the currently running profiler, if any, then retrieves an old one from the stack + * of paused profilers and starts that. + * Preconditions: Profiling must be enabled and there must be at least one profiler on the + * stack. + */ +void QQmlVmeProfiler::pop() +{ + Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled."); + Q_ASSERT_X(ranges.count() > 0, Q_FUNC_INFO, "trying to pop an invalid profiler"); + if (enabled && ranges.count() > 0) { + start(); + currentRange = ranges.pop(); + QQmlProfilerService::instance->rangeLocation( + QQmlProfilerService::Creating, currentRange.url, currentRange.line, currentRange.column); + QQmlProfilerService::instance->rangeData(QQmlProfilerService::Creating, currentRange.typeName); + } +} + +/*! + * \brief QQmlVmeProfiler::push Pushes the currently running profiler on the stack. + * Pushes the currently running profiler on the stack of paused profilers. Note: The profiler + * isn't paused here. That's a separate step. If it's never paused, but pop()'ed later that + * won't do any harm, though. + * Preconditions: Profiling must be enabled and a profiler must be running in the foreground. + */ +void QQmlVmeProfiler::push() +{ + Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled."); + Q_ASSERT_X(running, Q_FUNC_INFO, "trying to push stopped profiler"); + if (enabled && running) + ranges.push(currentRange); +} + +/*! + * \brief QQmlVmeProfiler::clear Stop all running profilers and clear all data. + * Stops the currently running (foreground and background) profilers and removes all saved + * data about paused profilers. + * Precondtions: Profiling must be enabled. + */ +void QQmlVmeProfiler::clear() +{ + Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled."); + if (enabled) { + stop(); + ranges.clear(); + for (int i = 0; i < backgroundRanges.count(); ++i) { + QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating); + } + backgroundRanges.clear(); + } +} + +/*! + * \brief QQmlVmeProfiler::stop Stop profiler running in the foreground, if any. + * Precondition: Profiling must be enabled. + */ +void QQmlVmeProfiler::stop() +{ + Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled."); + if (enabled && running) { + QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating); + currentRange.clear(); + running = false; + } +} + +/*! + * \brief QQmlVmeProfiler::background Push the current profiler to the background. + * Push the profiler currently running in the foreground to the background so that it + * won't be stopped by stop() or start(). There can be multiple profilers in the background. + * You can retrieve them in reverse order by calling foreground(). + * Precondition: Profiling must be enabled and a profiler must be running in the foreground. + */ +void QQmlVmeProfiler::background() +{ + Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled."); + Q_ASSERT_X(running, Q_FUNC_INFO, "trying to push stopped profiler to the background."); + if (enabled && running) { + backgroundRanges.push(currentRange); + running = false; + } +} + +/*! + * \brief QQmlVmeProfiler::foreground Retrieve a profiler from the background + * Stop the profiler currently running in the foreground, if any and put the next profiler + * from the background in its place. + * Preconditions: Profiling must be enabled and there must be at least one profiler in the + * background. + */ +void QQmlVmeProfiler::foreground() +{ + Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled."); + Q_ASSERT_X(backgroundRanges.count() > 0, Q_FUNC_INFO, "trying to foreground stopped profiler."); + if (enabled && backgroundRanges.count() > 0) { + stop(); + currentRange = backgroundRanges.pop(); + running = true; + } +} + QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h index fb08a30c6a..c2e9eb421a 100644 --- a/src/qml/debugger/qqmlprofilerservice_p.h +++ b/src/qml/debugger/qqmlprofilerservice_p.h @@ -225,7 +225,7 @@ private: friend struct QQmlBindingProfiler; friend struct QQmlHandlingSignalProfiler; - friend struct QQmlObjectCreatingProfiler; + friend struct QQmlVmeProfiler; friend struct QQmlCompilingProfiler; friend struct QQmlPixmapProfiler; }; @@ -277,40 +277,6 @@ struct QQmlHandlingSignalProfiler { bool enabled; }; -struct QQmlObjectCreatingProfiler { - QQmlObjectCreatingProfiler() - { - enabled = QQmlProfilerService::instance - ? QQmlProfilerService::instance->profilingEnabled() : false; - if (enabled) { - QQmlProfilerService *service = QQmlProfilerService::instance; - service->startRange(QQmlProfilerService::Creating); - } - } - - void setTypeName(const QString &typeName) - { - Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled."); - QQmlProfilerService::instance->rangeData(QQmlProfilerService::Creating, typeName); - } - - void setLocation(const QUrl &url, int line, int column) - { - Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled."); - if (enabled) - QQmlProfilerService::instance->rangeLocation( - QQmlProfilerService::Creating, url, line, column); - } - - ~QQmlObjectCreatingProfiler() - { - if (enabled) - QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating); - } - - bool enabled; -}; - struct QQmlCompilingProfiler { QQmlCompilingProfiler(const QString &name) { @@ -333,6 +299,54 @@ struct QQmlCompilingProfiler { bool enabled; }; +struct QQmlVmeProfiler { +public: + const bool enabled; + + struct Data { + Data() : line(0), column(0) {} + QUrl url; + int line; + int column; + QString typeName; + void clear(); + }; + + QQmlVmeProfiler() : + enabled(QQmlProfilerService::instance ? QQmlProfilerService::instance->profilingEnabled() : false), + running(false) + {} + + ~QQmlVmeProfiler() + { + if (enabled) + clear(); + } + + void clear(); + + void start(const QUrl &url, int line, int column, const QString &typeName); + void start(); + void stop(); + + void updateLocation(const QUrl &url, int line, int column); + void updateTypeName(const QString &typeName); + + void pop(); + void push(); + + void background(); + void foreground(); + +private: + void switchRange(); + + Data currentRange; + QStack<Data> ranges; + QStack<Data> backgroundRanges; + bool running; +}; + struct QQmlPixmapProfiler { QQmlPixmapProfiler() { QQmlProfilerService *instance = QQmlProfilerService::instance; diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index e4df95716d..743d35fa69 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -1262,13 +1262,9 @@ void Object::arraySort(ExecutionContext *context, ObjectRef thisObject, const Va ArrayElementLessThan lessThan(context, thisObject, comparefn); + if (!len) + return; Property *begin = arrayData; - // We deliberately choose qSort over std::sort here, because with - // MSVC in debug builds, std::sort has an ASSERT() that verifies - // that the return values of lessThan are perfectly consistent - // and aborts otherwise. We do not want JavaScript to easily crash - // the entire application and therefore choose qSort, which doesn't - // have this property. std::sort(begin, begin + len, lessThan); } diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index f1b0e0bdc4..85e6878f7b 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(); } @@ -851,7 +848,7 @@ ReturnedValue QObjectWrapper::method_connect(CallContext *ctx) QPair<QObject *, int> signalInfo = extractQtSignal(ctx->callData->thisObject); QObject *signalObject = signalInfo.first; - int signalIndex = signalInfo.second; + int signalIndex = signalInfo.second; // in method range, not signal range! if (signalIndex < 0) V4THROW_ERROR("Function.prototype.connect: this object is not a signal"); @@ -885,6 +882,11 @@ ReturnedValue QObjectWrapper::method_connect(CallContext *ctx) slot->thisObject = thisObject; slot->function = f; + if (QQmlData *ddata = QQmlData::get(signalObject)) { + if (QQmlPropertyCache *propertyCache = ddata->propertyCache) { + QQmlPropertyPrivate::flushSignal(signalObject, propertyCache->methodIndexToSignalIndex(signalIndex)); + } + } QObjectPrivate::connect(signalObject, signalIndex, slot, Qt::AutoConnection); return Encode::undefined(); 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/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h index 3ca4566e41..05c877d98b 100644 --- a/src/qml/qml/qqmlcompiler_p.h +++ b/src/qml/qml/qqmlcompiler_p.h @@ -169,7 +169,7 @@ public: int addInstruction(const QQmlInstructionData<Instr> &data) { QQmlInstruction genericInstr; - QQmlInstructionMeta<Instr>::setData(genericInstr, data); + QQmlInstructionMeta<Instr>::setDataNoCommon(genericInstr, data); return addInstructionHelper(static_cast<QQmlInstruction::Type>(Instr), genericInstr); } int nextInstructionIndex(); diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 2973944215..ae246f5cd4 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -52,7 +52,6 @@ #include "qqmlbinding_p.h" #include "qqmlglobal_p.h" #include "qqmlscript_p.h" -#include <private/qqmlprofilerservice_p.h> #include <private/qqmlenginedebugservice_p.h> #include "qqmlincubator.h" #include "qqmlincubator_p.h" @@ -884,11 +883,6 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context) QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine); - if (enginePriv->inProgressCreations == 0) { - // only track root, since further ones might not be properly nested - profiler = new QQmlObjectCreatingProfiler(); - } - enginePriv->inProgressCreations++; state.errors.clear(); state.completePending = true; @@ -924,13 +918,6 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context) if (!context->isInternal) context->asQQmlContextPrivate()->instances.append(rv); QQmlEngineDebugService::instance()->objectCreated(engine, rv); - - if (profiler && profiler->enabled) { - profiler->setTypeName(buildTypeNameForDebug(rv->metaObject())); - QQmlData *data = QQmlData::get(rv); - Q_ASSERT(data); - profiler->setLocation(cc->url, data->lineNumber, data->columnNumber); - } } return rv; @@ -995,9 +982,6 @@ void QQmlComponentPrivate::completeCreate() if (state.completePending) { QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); complete(ep, &state); - - delete profiler; - profiler = 0; } if (depthIncreased) { diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index d9a2427cd5..8bf4005dd6 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -61,7 +61,6 @@ #include "qqmlvme_p.h" #include "qqmlerror.h" #include "qqml.h" -#include <private/qqmlprofilerservice_p.h> #include <private/qqmlobjectcreator_p.h> #include <QtCore/QString> @@ -85,7 +84,7 @@ class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public public: QQmlComponentPrivate() - : typeData(0), progress(0.), start(-1), cc(0), engine(0), creationContext(0), profiler(0), depthIncreased(false) {} + : typeData(0), progress(0.), start(-1), cc(0), engine(0), creationContext(0), depthIncreased(false) {} void loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous); @@ -131,7 +130,6 @@ public: QQmlEngine *engine; QQmlGuardedContextData creationContext; - QQmlObjectCreatingProfiler *profiler; bool depthIncreased; void clear(); 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..1f45cba732 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1339,14 +1339,6 @@ void qmlExecuteDeferred(QObject *object) QQmlData *data = QQmlData::get(object); if (data && data->deferredData && !data->wasDeleted(object)) { - QQmlObjectCreatingProfiler prof; - if (prof.enabled) { - QQmlType *type = QQmlMetaType::qmlType(object->metaObject()); - prof.setTypeName(type ? type->qmlTypeName() - : QString::fromUtf8(object->metaObject()->className())); - if (data->outerContext) - prof.setLocation(data->outerContext->url, data->lineNumber, data->columnNumber); - } QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine); QQmlComponentPrivate::ConstructionState state; @@ -1734,6 +1726,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); diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h index 150ee8df19..bda8c3db0d 100644 --- a/src/qml/qml/qqmlinstruction_p.h +++ b/src/qml/qml/qqmlinstruction_p.h @@ -536,7 +536,11 @@ struct QQmlInstructionMeta { typedef QQmlInstruction::instr_##FMT DataType; \ static const DataType &data(const QQmlInstruction &instr) { return instr.FMT; } \ static void setData(QQmlInstruction &instr, const DataType &v) { memcpy(&instr.FMT, &v, Size); } \ - }; + static void setDataNoCommon(QQmlInstruction &instr, const DataType &v) \ + { memcpy(reinterpret_cast<char *>(&instr.FMT) + sizeof(QQmlInstruction::instr_common), \ + reinterpret_cast<const char *>(&v) + sizeof(QQmlInstruction::instr_common), \ + Size - sizeof(QQmlInstruction::instr_common)); } \ + }; FOR_EACH_QML_INSTR(QML_INSTR_META_TEMPLATE); #undef QML_INSTR_META_TEMPLATE diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h index c55b86b55a..bd44dfb0cf 100644 --- a/src/qml/qml/qqmlvaluetype_p.h +++ b/src/qml/qml/qqmlvaluetype_p.h @@ -169,8 +169,8 @@ public: class Q_QML_PRIVATE_EXPORT QQmlPointFValueType : public QQmlValueTypeBase<QPointF> { - Q_PROPERTY(qreal x READ x WRITE setX) - Q_PROPERTY(qreal y READ y WRITE setY) + Q_PROPERTY(qreal x READ x WRITE setX FINAL) + Q_PROPERTY(qreal y READ y WRITE setY FINAL) Q_OBJECT public: QQmlPointFValueType(QObject *parent = 0); @@ -185,8 +185,8 @@ public: class Q_QML_PRIVATE_EXPORT QQmlPointValueType : public QQmlValueTypeBase<QPoint> { - Q_PROPERTY(int x READ x WRITE setX) - Q_PROPERTY(int y READ y WRITE setY) + Q_PROPERTY(int x READ x WRITE setX FINAL) + Q_PROPERTY(int y READ y WRITE setY FINAL) Q_OBJECT public: QQmlPointValueType(QObject *parent = 0); @@ -201,8 +201,8 @@ public: class Q_QML_PRIVATE_EXPORT QQmlSizeFValueType : public QQmlValueTypeBase<QSizeF> { - Q_PROPERTY(qreal width READ width WRITE setWidth) - Q_PROPERTY(qreal height READ height WRITE setHeight) + Q_PROPERTY(qreal width READ width WRITE setWidth FINAL) + Q_PROPERTY(qreal height READ height WRITE setHeight FINAL) Q_OBJECT public: QQmlSizeFValueType(QObject *parent = 0); @@ -217,8 +217,8 @@ public: class Q_QML_PRIVATE_EXPORT QQmlSizeValueType : public QQmlValueTypeBase<QSize> { - Q_PROPERTY(int width READ width WRITE setWidth) - Q_PROPERTY(int height READ height WRITE setHeight) + Q_PROPERTY(int width READ width WRITE setWidth FINAL) + Q_PROPERTY(int height READ height WRITE setHeight FINAL) Q_OBJECT public: QQmlSizeValueType(QObject *parent = 0); @@ -233,10 +233,10 @@ public: class Q_QML_PRIVATE_EXPORT QQmlRectFValueType : public QQmlValueTypeBase<QRectF> { - Q_PROPERTY(qreal x READ x WRITE setX) - Q_PROPERTY(qreal y READ y WRITE setY) - Q_PROPERTY(qreal width READ width WRITE setWidth) - Q_PROPERTY(qreal height READ height WRITE setHeight) + Q_PROPERTY(qreal x READ x WRITE setX FINAL) + Q_PROPERTY(qreal y READ y WRITE setY FINAL) + Q_PROPERTY(qreal width READ width WRITE setWidth FINAL) + Q_PROPERTY(qreal height READ height WRITE setHeight FINAL) Q_OBJECT public: QQmlRectFValueType(QObject *parent = 0); @@ -256,10 +256,10 @@ public: class Q_QML_PRIVATE_EXPORT QQmlRectValueType : public QQmlValueTypeBase<QRect> { - Q_PROPERTY(int x READ x WRITE setX) - Q_PROPERTY(int y READ y WRITE setY) - Q_PROPERTY(int width READ width WRITE setWidth) - Q_PROPERTY(int height READ height WRITE setHeight) + Q_PROPERTY(int x READ x WRITE setX FINAL) + Q_PROPERTY(int y READ y WRITE setY FINAL) + Q_PROPERTY(int width READ width WRITE setWidth FINAL) + Q_PROPERTY(int height READ height WRITE setHeight FINAL) Q_OBJECT public: QQmlRectValueType(QObject *parent = 0); @@ -282,11 +282,11 @@ class Q_QML_PRIVATE_EXPORT QQmlEasingValueType : public QQmlValueTypeBase<QEasin Q_OBJECT Q_ENUMS(Type) - Q_PROPERTY(QQmlEasingValueType::Type type READ type WRITE setType) - Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude) - Q_PROPERTY(qreal overshoot READ overshoot WRITE setOvershoot) - Q_PROPERTY(qreal period READ period WRITE setPeriod) - Q_PROPERTY(QVariantList bezierCurve READ bezierCurve WRITE setBezierCurve) + Q_PROPERTY(QQmlEasingValueType::Type type READ type WRITE setType FINAL) + Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude FINAL) + Q_PROPERTY(qreal overshoot READ overshoot WRITE setOvershoot FINAL) + Q_PROPERTY(qreal period READ period WRITE setPeriod FINAL) + Q_PROPERTY(QVariantList bezierCurve READ bezierCurve WRITE setBezierCurve FINAL) public: enum Type { Linear = QEasingCurve::Linear, diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index 983136a846..ad1e9d862e 100644 --- a/src/qml/qml/qqmlvme.cpp +++ b/src/qml/qml/qqmlvme.cpp @@ -503,6 +503,12 @@ QObject *QQmlVME::run(QList<QQmlError> *errors, const QQmlCompiledData::TypeReference &type = TYPES.at(instr.type); Q_ASSERT(type.component); + if (profiler.enabled) { + profiler.start(); + profiler.updateTypeName(type.component->name); + profiler.background(); + } + states.push(State()); State *cState = &states[states.count() - 2]; @@ -524,6 +530,11 @@ QObject *QQmlVME::run(QList<QQmlError> *errors, QML_END_INSTR(CreateQMLObject) QML_BEGIN_INSTR(CompleteQMLObject) + if (profiler.enabled) { + profiler.foreground(); + profiler.updateLocation(CTXT->url, instr.line, instr.column); + } + QObject *o = objects.top(); Q_ASSERT(o); @@ -566,6 +577,8 @@ QObject *QQmlVME::run(QList<QQmlError> *errors, QML_BEGIN_INSTR(CreateCppObject) const QQmlCompiledData::TypeReference &type = TYPES.at(instr.type); Q_ASSERT(type.type); + if (profiler.enabled) + profiler.start(CTXT->url, instr.line, instr.column, type.type->qmlTypeName()); QObject *o = 0; void *memory = 0; @@ -637,12 +650,14 @@ QObject *QQmlVME::run(QList<QQmlError> *errors, QML_END_INSTR(CreateCppObject) QML_BEGIN_INSTR(CreateSimpleObject) + const QQmlCompiledData::TypeReference &ref = TYPES.at(instr.type); + if (profiler.enabled) + profiler.start(CTXT->url, instr.line, instr.column, ref.type->qmlTypeName()); QObject *o = (QObject *)operator new(instr.typeSize + sizeof(QQmlData)); ::memset(static_cast<void *>(o), 0, instr.typeSize + sizeof(QQmlData)); instr.create(o); QQmlData *ddata = (QQmlData *)(((const char *)o) + instr.typeSize); - const QQmlCompiledData::TypeReference &ref = TYPES.at(instr.type); if (!ddata->propertyCache && ref.typePropertyCache) { ddata->propertyCache = ref.typePropertyCache; ddata->propertyCache->addref(); @@ -817,6 +832,8 @@ QObject *QQmlVME::run(QList<QQmlError> *errors, QML_END_INSTR(StoreScriptString) QML_BEGIN_INSTR(BeginObject) + if (profiler.enabled) + profiler.push(); QObject *target = objects.top(); QQmlParserStatus *status = reinterpret_cast<QQmlParserStatus *>(reinterpret_cast<char *>(target) + instr.castValue); parserStatus.push(status); @@ -1074,6 +1091,8 @@ normalExit: objects.deallocate(); lists.deallocate(); states.clear(); + if (profiler.enabled) + profiler.stop(); return rv; } @@ -1111,6 +1130,8 @@ void QQmlVME::reset() states.clear(); rootContext = 0; creationContext = 0; + if (profiler.enabled) + profiler.clear(); } #ifdef QML_THREADED_VME_INTERPRETER @@ -1170,6 +1191,8 @@ QQmlContextData *QQmlVME::complete(const Interrupt &interrupt) if (componentCompleteEnabled()) { // the qml designer does the component complete later QQmlTrace trace("VME Component Complete"); while (!parserStatus.isEmpty()) { + if (profiler.enabled) + profiler.pop(); QQmlParserStatus *status = parserStatus.pop(); #ifdef QML_ENABLE_TRACE QQmlData *data = parserStatusData.pop(); @@ -1189,6 +1212,8 @@ QQmlContextData *QQmlVME::complete(const Interrupt &interrupt) return 0; } parserStatus.deallocate(); + if (profiler.enabled) + profiler.clear(); } { diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h index e76b485a5c..d5afd4c67a 100644 --- a/src/qml/qml/qqmlvme_p.h +++ b/src/qml/qml/qqmlvme_p.h @@ -68,6 +68,7 @@ #include <private/qfinitestack_p.h> #include <private/qqmltrace_p.h> +#include <private/qqmlprofilerservice_p.h> QT_BEGIN_NAMESPACE @@ -171,6 +172,7 @@ private: #ifdef QML_ENABLE_TRACE QFiniteStack<QQmlData *> parserStatusData; #endif + QQmlVmeProfiler profiler; QQmlGuardedContextData rootContext; QQmlGuardedContextData creationContext; diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index c56f3648e6..d4427eb47e 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -2533,7 +2533,7 @@ void QQuickTextInputPrivate::handleFocusEvent(QFocusEvent *event) && !persistentSelection) deselect(); - if (hasAcceptableInput(m_text) || fixup()) + if (q->hasAcceptableInput() || fixup()) emit q->editingFinished(); #ifndef QT_NO_IM @@ -4117,7 +4117,7 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event) Q_Q(QQuickTextInput); if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { - if (hasAcceptableInput(m_text) || fixup()) { + if (q->hasAcceptableInput() || fixup()) { emit q->accepted(); emit q->editingFinished(); } diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index afde7939f2..90803db9fe 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -454,6 +454,8 @@ void QSGRenderContext::initialize(QOpenGLContext *context) const char *renderer = (const char *) glGetString(GL_RENDERER); if (strstr(renderer, "llvmpipe")) m_serializedRender = true; + if (strstr(vendor, "Hisilicon Technologies") && strstr(renderer, "Immersion.16")) + m_brokenIBOs = true; #endif emit initialized(); diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index aa0d7b5a6c..52df55fa92 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -122,6 +122,7 @@ public: QSGRenderContext *rc; QImage grabContent; + int m_update_timer; bool eventPending; }; @@ -384,7 +385,8 @@ void QSGGuiThreadRenderLoop::maybeUpdate(QQuickWindow *window) m_windows[window].updatePending = true; if (!eventPending) { - QCoreApplication::postEvent(this, new QEvent(QEvent::User)); + const int exhaust_delay = 5; + m_update_timer = startTimer(exhaust_delay, Qt::PreciseTimer); eventPending = true; } } @@ -399,8 +401,10 @@ QSGContext *QSGGuiThreadRenderLoop::sceneGraphContext() const bool QSGGuiThreadRenderLoop::event(QEvent *e) { - if (e->type() == QEvent::User) { + if (e->type() == QEvent::Timer) { eventPending = false; + killTimer(m_update_timer); + m_update_timer = 0; for (QHash<QQuickWindow *, WindowData>::const_iterator it = m_windows.constBegin(); it != m_windows.constEnd(); ++it) { const WindowData &data = it.value(); diff --git a/src/quick/scenegraph/shaders/distancefieldshiftedtext.frag b/src/quick/scenegraph/shaders/distancefieldshiftedtext.frag index 60c1c7468b..42fead8713 100644 --- a/src/quick/scenegraph/shaders/distancefieldshiftedtext.frag +++ b/src/quick/scenegraph/shaders/distancefieldshiftedtext.frag @@ -1,7 +1,7 @@ varying highp vec2 sampleCoord; varying highp vec2 shiftedSampleCoord; -uniform sampler2D _qt_texture; +uniform mediump sampler2D _qt_texture; uniform lowp vec4 color; uniform lowp vec4 styleColor; uniform mediump float alphaMin; diff --git a/src/quick/util/qquickvaluetypes_p.h b/src/quick/util/qquickvaluetypes_p.h index 88570f3b6e..94db7a8729 100644 --- a/src/quick/util/qquickvaluetypes_p.h +++ b/src/quick/util/qquickvaluetypes_p.h @@ -64,10 +64,10 @@ void registerValueTypes(); class Q_AUTOTEST_EXPORT QQuickColorValueType : public QQmlValueTypeBase<QColor> { - Q_PROPERTY(qreal r READ r WRITE setR) - Q_PROPERTY(qreal g READ g WRITE setG) - Q_PROPERTY(qreal b READ b WRITE setB) - Q_PROPERTY(qreal a READ a WRITE setA) + Q_PROPERTY(qreal r READ r WRITE setR FINAL) + Q_PROPERTY(qreal g READ g WRITE setG FINAL) + Q_PROPERTY(qreal b READ b WRITE setB FINAL) + Q_PROPERTY(qreal a READ a WRITE setA FINAL) Q_OBJECT public: QQuickColorValueType(QObject *parent = 0); @@ -86,8 +86,8 @@ public: class Q_AUTOTEST_EXPORT QQuickVector2DValueType : public QQmlValueTypeBase<QVector2D> { - Q_PROPERTY(qreal x READ x WRITE setX) - Q_PROPERTY(qreal y READ y WRITE setY) + Q_PROPERTY(qreal x READ x WRITE setX FINAL) + Q_PROPERTY(qreal y READ y WRITE setY FINAL) Q_OBJECT public: QQuickVector2DValueType(QObject *parent = 0); @@ -115,9 +115,9 @@ public: class Q_AUTOTEST_EXPORT QQuickVector3DValueType : public QQmlValueTypeBase<QVector3D> { - Q_PROPERTY(qreal x READ x WRITE setX) - Q_PROPERTY(qreal y READ y WRITE setY) - Q_PROPERTY(qreal z READ z WRITE setZ) + Q_PROPERTY(qreal x READ x WRITE setX FINAL) + Q_PROPERTY(qreal y READ y WRITE setY FINAL) + Q_PROPERTY(qreal z READ z WRITE setZ FINAL) Q_OBJECT public: QQuickVector3DValueType(QObject *parent = 0); @@ -149,10 +149,10 @@ public: class Q_AUTOTEST_EXPORT QQuickVector4DValueType : public QQmlValueTypeBase<QVector4D> { - Q_PROPERTY(qreal x READ x WRITE setX) - Q_PROPERTY(qreal y READ y WRITE setY) - Q_PROPERTY(qreal z READ z WRITE setZ) - Q_PROPERTY(qreal w READ w WRITE setW) + Q_PROPERTY(qreal x READ x WRITE setX FINAL) + Q_PROPERTY(qreal y READ y WRITE setY FINAL) + Q_PROPERTY(qreal z READ z WRITE setZ FINAL) + Q_PROPERTY(qreal w READ w WRITE setW FINAL) Q_OBJECT public: QQuickVector4DValueType(QObject *parent = 0); @@ -207,22 +207,22 @@ public: class Q_AUTOTEST_EXPORT QQuickMatrix4x4ValueType : public QQmlValueTypeBase<QMatrix4x4> { - Q_PROPERTY(qreal m11 READ m11 WRITE setM11) - Q_PROPERTY(qreal m12 READ m12 WRITE setM12) - Q_PROPERTY(qreal m13 READ m13 WRITE setM13) - Q_PROPERTY(qreal m14 READ m14 WRITE setM14) - Q_PROPERTY(qreal m21 READ m21 WRITE setM21) - Q_PROPERTY(qreal m22 READ m22 WRITE setM22) - Q_PROPERTY(qreal m23 READ m23 WRITE setM23) - Q_PROPERTY(qreal m24 READ m24 WRITE setM24) - Q_PROPERTY(qreal m31 READ m31 WRITE setM31) - Q_PROPERTY(qreal m32 READ m32 WRITE setM32) - Q_PROPERTY(qreal m33 READ m33 WRITE setM33) - Q_PROPERTY(qreal m34 READ m34 WRITE setM34) - Q_PROPERTY(qreal m41 READ m41 WRITE setM41) - Q_PROPERTY(qreal m42 READ m42 WRITE setM42) - Q_PROPERTY(qreal m43 READ m43 WRITE setM43) - Q_PROPERTY(qreal m44 READ m44 WRITE setM44) + Q_PROPERTY(qreal m11 READ m11 WRITE setM11 FINAL) + Q_PROPERTY(qreal m12 READ m12 WRITE setM12 FINAL) + Q_PROPERTY(qreal m13 READ m13 WRITE setM13 FINAL) + Q_PROPERTY(qreal m14 READ m14 WRITE setM14 FINAL) + Q_PROPERTY(qreal m21 READ m21 WRITE setM21 FINAL) + Q_PROPERTY(qreal m22 READ m22 WRITE setM22 FINAL) + Q_PROPERTY(qreal m23 READ m23 WRITE setM23 FINAL) + Q_PROPERTY(qreal m24 READ m24 WRITE setM24 FINAL) + Q_PROPERTY(qreal m31 READ m31 WRITE setM31 FINAL) + Q_PROPERTY(qreal m32 READ m32 WRITE setM32 FINAL) + Q_PROPERTY(qreal m33 READ m33 WRITE setM33 FINAL) + Q_PROPERTY(qreal m34 READ m34 WRITE setM34 FINAL) + Q_PROPERTY(qreal m41 READ m41 WRITE setM41 FINAL) + Q_PROPERTY(qreal m42 READ m42 WRITE setM42 FINAL) + Q_PROPERTY(qreal m43 READ m43 WRITE setM43 FINAL) + Q_PROPERTY(qreal m44 READ m44 WRITE setM44 FINAL) Q_OBJECT public: QQuickMatrix4x4ValueType(QObject *parent = 0); @@ -288,18 +288,18 @@ class Q_AUTOTEST_EXPORT QQuickFontValueType : public QQmlValueTypeBase<QFont> Q_ENUMS(FontWeight) Q_ENUMS(Capitalization) - Q_PROPERTY(QString family READ family WRITE setFamily) - Q_PROPERTY(bool bold READ bold WRITE setBold) - Q_PROPERTY(FontWeight weight READ weight WRITE setWeight) - Q_PROPERTY(bool italic READ italic WRITE setItalic) - Q_PROPERTY(bool underline READ underline WRITE setUnderline) - Q_PROPERTY(bool overline READ overline WRITE setOverline) - Q_PROPERTY(bool strikeout READ strikeout WRITE setStrikeout) - Q_PROPERTY(qreal pointSize READ pointSize WRITE setPointSize) - Q_PROPERTY(int pixelSize READ pixelSize WRITE setPixelSize) - Q_PROPERTY(Capitalization capitalization READ capitalization WRITE setCapitalization) - Q_PROPERTY(qreal letterSpacing READ letterSpacing WRITE setLetterSpacing) - Q_PROPERTY(qreal wordSpacing READ wordSpacing WRITE setWordSpacing) + Q_PROPERTY(QString family READ family WRITE setFamily FINAL) + Q_PROPERTY(bool bold READ bold WRITE setBold FINAL) + Q_PROPERTY(FontWeight weight READ weight WRITE setWeight FINAL) + Q_PROPERTY(bool italic READ italic WRITE setItalic FINAL) + Q_PROPERTY(bool underline READ underline WRITE setUnderline FINAL) + Q_PROPERTY(bool overline READ overline WRITE setOverline FINAL) + Q_PROPERTY(bool strikeout READ strikeout WRITE setStrikeout FINAL) + Q_PROPERTY(qreal pointSize READ pointSize WRITE setPointSize FINAL) + Q_PROPERTY(int pixelSize READ pixelSize WRITE setPixelSize FINAL) + Q_PROPERTY(Capitalization capitalization READ capitalization WRITE setCapitalization FINAL) + Q_PROPERTY(qreal letterSpacing READ letterSpacing WRITE setLetterSpacing FINAL) + Q_PROPERTY(qreal wordSpacing READ wordSpacing WRITE setWordSpacing FINAL) public: enum FontWeight { Light = QFont::Light, |