diff options
Diffstat (limited to 'src')
65 files changed, 1250 insertions, 748 deletions
diff --git a/src/3rdparty/masm/assembler/X86Assembler.h b/src/3rdparty/masm/assembler/X86Assembler.h index e8ae687036..8f9ee29a4d 100644 --- a/src/3rdparty/masm/assembler/X86Assembler.h +++ b/src/3rdparty/masm/assembler/X86Assembler.h @@ -201,12 +201,12 @@ private: TwoByteOpcodeID jccRel32(Condition cond) { - return (TwoByteOpcodeID)(OP2_JCC_rel32 + cond); + return (TwoByteOpcodeID)(int(OP2_JCC_rel32) + cond); } TwoByteOpcodeID setccOpcode(Condition cond) { - return (TwoByteOpcodeID)(OP_SETCC + cond); + return (TwoByteOpcodeID)(int(OP_SETCC) + cond); } typedef enum { diff --git a/src/imports/layouts/qquickstacklayout.cpp b/src/imports/layouts/qquickstacklayout.cpp index d6ee4afe84..1d67d2058d 100644 --- a/src/imports/layouts/qquickstacklayout.cpp +++ b/src/imports/layouts/qquickstacklayout.cpp @@ -192,10 +192,8 @@ QSizeF QQuickStackLayout::sizeHint(Qt::SizeHint whichSizeHint) const maxS = QSizeF(std::numeric_limits<qreal>::infinity(), std::numeric_limits<qreal>::infinity()); const int count = itemCount(); - m_cachedItemSizeHints.resize(count); for (int i = 0; i < count; ++i) { - SizeHints &hints = m_cachedItemSizeHints[i]; - QQuickStackLayout::collectItemSizeHints(itemAt(i), hints.array); + SizeHints &hints = cachedItemSizeHints(i); minS = minS.expandedTo(hints.min()); prefS = prefS.expandedTo(hints.pref()); //maxS = maxS.boundedTo(hints.max()); // Can be resized to be larger than any of its items. @@ -286,6 +284,7 @@ void QQuickStackLayout::updateLayoutItems() if (count != d->count) { d->count = count; emit countChanged(); + m_cachedItemSizeHints.resize(count); } for (int i = 0; i < count; ++i) { QQuickItem *child = itemAt(i); @@ -294,6 +293,13 @@ void QQuickStackLayout::updateLayoutItems() } } +QQuickStackLayout::SizeHints &QQuickStackLayout::cachedItemSizeHints(int index) const { + SizeHints &hints = m_cachedItemSizeHints[index]; + if (!hints.min().isValid()) + QQuickStackLayout::collectItemSizeHints(itemAt(index), hints.array); + return hints; +} + void QQuickStackLayout::rearrange(const QSizeF &newSize) { Q_D(QQuickStackLayout); @@ -305,7 +311,7 @@ void QQuickStackLayout::rearrange(const QSizeF &newSize) if (d->currentIndex == -1 || d->currentIndex >= m_cachedItemSizeHints.count()) return; - QQuickStackLayout::SizeHints &hints = m_cachedItemSizeHints[d->currentIndex]; + QQuickStackLayout::SizeHints &hints = cachedItemSizeHints(d->currentIndex); QQuickItem *item = itemAt(d->currentIndex); Q_ASSERT(item); item->setPosition(QPointF(0,0)); // ### respect alignment? diff --git a/src/imports/layouts/qquickstacklayout_p.h b/src/imports/layouts/qquickstacklayout_p.h index 0319e259d4..5349adfa36 100644 --- a/src/imports/layouts/qquickstacklayout_p.h +++ b/src/imports/layouts/qquickstacklayout_p.h @@ -97,6 +97,7 @@ private: mutable QVector<SizeHints> m_cachedItemSizeHints; mutable QSizeF m_cachedSizeHints[Qt::NSizeHints]; + SizeHints &cachedItemSizeHints(int index) const; }; class QQuickStackLayoutPrivate : public QQuickLayoutPrivate diff --git a/src/imports/statemachine/signaltransition.cpp b/src/imports/statemachine/signaltransition.cpp index 8c37f8368f..eb7095bc2a 100644 --- a/src/imports/statemachine/signaltransition.cpp +++ b/src/imports/statemachine/signaltransition.cpp @@ -166,7 +166,7 @@ void SignalTransition::connectTriggered() Q_ASSERT(m_bindings.count() == 1); const QV4::CompiledData::Binding *binding = m_bindings.at(0); - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script); + Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script); QV4::ExecutionEngine *jsEngine = QQmlEngine::contextForObject(this)->engine()->handle(); QV4::Scope scope(jsEngine); @@ -198,7 +198,7 @@ void SignalTransitionParser::verifyBindings(const QQmlRefPointer<QV4::Executable return; } - if (binding->type != QV4::CompiledData::Binding::Type_Script) { + if (binding->type() != QV4::CompiledData::Binding::Type_Script) { error(binding, SignalTransition::tr("SignalTransition: script expected")); return; } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp index d435e82390..ec7f91d045 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp @@ -812,9 +812,9 @@ bool QQmlEngineDebugServiceImpl::setMethodBody(int objectId, const QString &meth int lineNumber = 0; QV4::ScopedFunctionObject oldMethod(scope, vmeMetaObject->vmeMethod(prop->coreIndex())); - if (oldMethod && oldMethod->d()->function) { - lineNumber = oldMethod->d()->function->compiledFunction->location.line; - } + if (oldMethod && oldMethod->d()->function) + lineNumber = oldMethod->d()->function->compiledFunction->location.line(); + QV4::ScopedValue v(scope, QQmlJavaScriptExpression::evalFunction(contextData, object, jsfunction, contextData->urlString(), lineNumber)); vmeMetaObject->setVmeMethod(prop->coreIndex(), v); return true; diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h index be0ca3f477..413edead2a 100644 --- a/src/qml/common/qv4compileddata_p.h +++ b/src/qml/common/qv4compileddata_p.h @@ -120,18 +120,35 @@ struct TableIterator struct Location { - union { - quint32 _dummy; - quint32_le_bitfield<0, 20> line; - quint32_le_bitfield<20, 12> column; - }; - - Location() : _dummy(0) { } + Location() : m_data(QSpecialIntegerBitfieldZero) {} + Location(quint32 l, quint32 c) : Location() + { + m_data.set<LineField>(l); + m_data.set<ColumnField>(c); + Q_ASSERT(m_data.get<LineField>() == l); + Q_ASSERT(m_data.get<ColumnField>() == c); + } inline bool operator<(const Location &other) const { - return line < other.line || - (line == other.line && column < other.column); + return m_data.get<LineField>() < other.m_data.get<LineField>() + || (m_data.get<LineField>() == other.m_data.get<LineField>() + && m_data.get<ColumnField>() < other.m_data.get<ColumnField>()); } + + void set(quint32 line, quint32 column) + { + m_data.set<LineField>(line); + m_data.set<ColumnField>(column); + } + + quint32 line() const { return m_data.get<LineField>(); } + quint32 column() const { return m_data.get<ColumnField>(); } + +private: + using LineField = quint32_le_bitfield_member<0, 20>; + using ColumnField = quint32_le_bitfield_member<20, 12>; + + quint32_le_bitfield_union<LineField, ColumnField> m_data; }; static_assert(sizeof(Location) == 4, "Location structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); @@ -145,13 +162,21 @@ struct RegExp RegExp_Unicode = 0x08, RegExp_Sticky = 0x10 }; - union { - quint32 _dummy; - quint32_le_bitfield<0, 5> flags; - quint32_le_bitfield<5, 27> stringIndex; - }; - RegExp() : _dummy(0) { } + RegExp() : m_data(QSpecialIntegerBitfieldZero) {} + RegExp(quint32 flags, quint32 stringIndex) : RegExp() + { + m_data.set<FlagsField>(flags); + m_data.set<StringIndexField>(stringIndex); + } + + quint32 flags() const { return m_data.get<FlagsField>(); } + quint32 stringIndex() const { return m_data.get<StringIndexField>(); } + +private: + using FlagsField = quint32_le_bitfield_member<0, 5>; + using StringIndexField = quint32_le_bitfield_member<5, 27>; + quint32_le_bitfield_union<FlagsField, StringIndexField> m_data; }; static_assert(sizeof(RegExp) == 4, "RegExp structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); @@ -164,25 +189,40 @@ struct Lookup Type_QmlContextPropertyGetter = 3 }; - union { - quint32 _dummy; - quint32_le_bitfield<0, 4> type_and_flags; - quint32_le_bitfield<4, 28> nameIndex; - }; + quint32 typeAndFlags() const { return m_data.get<TypeAndFlagsField>(); } + quint32 nameIndex() const { return m_data.get<NameIndexField>(); } - Lookup() : _dummy(0) { } + Lookup() : m_data(QSpecialIntegerBitfieldZero) {} + Lookup(Type type, quint32 nameIndex) : Lookup() + { + m_data.set<TypeAndFlagsField>(type); + m_data.set<NameIndexField>(nameIndex); + } + +private: + using TypeAndFlagsField = quint32_le_bitfield_member<0, 4>; + using NameIndexField = quint32_le_bitfield_member<4, 28>; + quint32_le_bitfield_union<TypeAndFlagsField, NameIndexField> m_data; }; static_assert(sizeof(Lookup) == 4, "Lookup structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); struct JSClassMember { - union { - quint32 _dummy; - quint32_le_bitfield<0, 31> nameOffset; - quint32_le_bitfield<31, 1> isAccessor; - }; + JSClassMember() : m_data(QSpecialIntegerBitfieldZero) {} - JSClassMember() : _dummy(0) { } + void set(quint32 nameOffset, bool isAccessor) + { + m_data.set<NameOffsetField>(nameOffset); + m_data.set<IsAccessorField>(isAccessor ? 1 : 0); + } + + quint32 nameOffset() const { return m_data.get<NameOffsetField>(); } + bool isAccessor() const { return m_data.get<IsAccessorField>() != 0; } + +private: + using NameOffsetField = quint32_le_bitfield_member<0, 31>; + using IsAccessorField = quint32_le_bitfield_member<31, 1>; + quint32_le_bitfield_union<NameOffsetField, IsAccessorField> m_data; }; static_assert(sizeof(JSClassMember) == 4, "JSClassMember structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); @@ -265,11 +305,26 @@ enum class BuiltinType : unsigned int { struct ParameterType { - union { - quint32 _dummy; - quint32_le_bitfield<0, 1> indexIsBuiltinType; - quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType; - }; + void set(bool indexIsBuiltinType, quint32 typeNameIndexOrBuiltinType) + { + m_data.set<IndexIsBuiltinTypeField>(indexIsBuiltinType ? 1 : 0); + m_data.set<TypeNameIndexOrBuiltinTypeField>(typeNameIndexOrBuiltinType); + } + + bool indexIsBuiltinType() const + { + return m_data.get<IndexIsBuiltinTypeField>() != 0; + } + + quint32 typeNameIndexOrBuiltinType() const + { + return m_data.get<TypeNameIndexOrBuiltinTypeField>(); + } + +private: + using IndexIsBuiltinTypeField = quint32_le_bitfield_member<0, 1>; + using TypeNameIndexOrBuiltinTypeField = quint32_le_bitfield_member<1, 31>; + quint32_le_bitfield_union<IndexIsBuiltinTypeField, TypeNameIndexOrBuiltinTypeField> m_data; }; static_assert(sizeof(ParameterType) == 4, "ParameterType structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); @@ -448,7 +503,7 @@ struct Binding { quint32_le propertyNameIndex; - enum ValueType : unsigned int { + enum Type : unsigned int { Type_Invalid, Type_Boolean, Type_Number, @@ -462,7 +517,7 @@ struct Binding Type_GroupProperty }; - enum Flags : unsigned int { + enum Flag : unsigned int { IsSignalHandlerExpression = 0x1, IsSignalHandlerObject = 0x2, IsOnAssignment = 0x4, @@ -474,11 +529,20 @@ struct Binding IsCustomParserBinding = 0x100, IsFunctionExpression = 0x200 }; + Q_DECLARE_FLAGS(Flags, Flag); + + using FlagsField = quint32_le_bitfield_member<0, 16>; + using TypeField = quint32_le_bitfield_member<16, 16>; + quint32_le_bitfield_union<FlagsField, TypeField> flagsAndType; + + void clearFlags() { flagsAndType.set<FlagsField>(0); } + void setFlag(Flag flag) { flagsAndType.set<FlagsField>(flagsAndType.get<FlagsField>() | flag); } + bool hasFlag(Flag flag) const { return Flags(flagsAndType.get<FlagsField>()) & flag; } + Flags flags() const { return Flags(flagsAndType.get<FlagsField>()); } + + void setType(Type type) { flagsAndType.set<TypeField>(type); } + Type type() const { return Type(flagsAndType.get<TypeField>()); } - union { - quint32_le_bitfield<0, 16> flags; - quint32_le_bitfield<16, 16> type; - }; union { bool b; quint32_le constantValueIndex; @@ -492,23 +556,29 @@ struct Binding Location location; Location valueLocation; + bool hasSignalHandlerBindingFlag() const + { + const Flags bindingFlags = flags(); + return (bindingFlags & IsSignalHandlerExpression || bindingFlags & IsSignalHandlerObject); + } + bool isValueBinding() const { - if (type == Type_AttachedProperty - || type == Type_GroupProperty) + switch (type()) { + case Type_AttachedProperty: + case Type_GroupProperty: return false; - if (flags & IsSignalHandlerExpression - || flags & IsSignalHandlerObject) - return false; - return true; + default: + return !hasSignalHandlerBindingFlag(); + } } - bool isValueBindingNoAlias() const { return isValueBinding() && !(flags & IsBindingToAlias); } - bool isValueBindingToAlias() const { return isValueBinding() && (flags & IsBindingToAlias); } + bool isValueBindingNoAlias() const { return isValueBinding() && !hasFlag(IsBindingToAlias); } + bool isValueBindingToAlias() const { return isValueBinding() && hasFlag(IsBindingToAlias); } bool isSignalHandler() const { - if (flags & IsSignalHandlerExpression || flags & IsSignalHandlerObject) { + if (hasSignalHandlerBindingFlag()) { Q_ASSERT(!isValueBinding()); Q_ASSERT(!isAttachedProperty()); Q_ASSERT(!isGroupProperty()); @@ -519,7 +589,7 @@ struct Binding bool isAttachedProperty() const { - if (type == Type_AttachedProperty) { + if (type() == Type_AttachedProperty) { Q_ASSERT(!isValueBinding()); Q_ASSERT(!isSignalHandler()); Q_ASSERT(!isGroupProperty()); @@ -530,7 +600,7 @@ struct Binding bool isGroupProperty() const { - if (type == Type_GroupProperty) { + if (type() == Type_GroupProperty) { Q_ASSERT(!isValueBinding()); Q_ASSERT(!isSignalHandler()); Q_ASSERT(!isAttachedProperty()); @@ -539,7 +609,7 @@ struct Binding return false; } - bool isFunctionExpression() const { return (flags & IsFunctionExpression); } + bool isFunctionExpression() const { return hasFlag(IsFunctionExpression); } //reverse of Lexer::singleEscape() static QString escapedString(const QString &string) @@ -584,16 +654,19 @@ struct Binding return tmp; } - bool isTranslationBinding() const { return type == Type_Translation || type == Type_TranslationById; } - bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); } + bool isTranslationBinding() const + { + const Binding::Type bindingType = type(); + return bindingType == Type_Translation || bindingType == Type_TranslationById; + } + bool evaluatesToString() const { return type() == Type_String || isTranslationBinding(); } bool valueAsBoolean() const { - if (type == Type_Boolean) + if (type() == Type_Boolean) return value.b; return false; } - }; static_assert(sizeof(Binding) == 24, "Binding structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); @@ -666,32 +739,57 @@ static_assert(sizeof(Signal) == 12, "Signal structure needs to have the expected struct Property { - quint32_le nameIndex; - union { - quint32_le_bitfield<0, 28> builtinTypeOrTypeNameIndex; - quint32_le_bitfield<28, 1> isRequired; - quint32_le_bitfield<29, 1> isBuiltinType; - quint32_le_bitfield<30, 1> isList; - quint32_le_bitfield<31, 1> isReadOnly; - }; +private: + using BuiltinTypeOrTypeNameIndexField = quint32_le_bitfield_member<0, 28>; + using IsRequiredField = quint32_le_bitfield_member<28, 1>; + using IsBuiltinTypeField = quint32_le_bitfield_member<29, 1>; + using IsListField = quint32_le_bitfield_member<30, 1>; + using IsReadOnlyField = quint32_le_bitfield_member<31, 1>; +public: + quint32_le nameIndex; + quint32_le_bitfield_union< + BuiltinTypeOrTypeNameIndexField, + IsRequiredField, + IsBuiltinTypeField, + IsListField, + IsReadOnlyField> data; Location location; void setBuiltinType(BuiltinType t) { - builtinTypeOrTypeNameIndex = static_cast<quint32>(t); - isBuiltinType = true; + data.set<BuiltinTypeOrTypeNameIndexField>(static_cast<quint32>(t)); + data.set<IsBuiltinTypeField>(true); } + BuiltinType builtinType() const { - if (isBuiltinType) - return static_cast<BuiltinType>(quint32(builtinTypeOrTypeNameIndex)); + if (data.get<IsBuiltinTypeField>() != 0) + return BuiltinType(data.get<BuiltinTypeOrTypeNameIndexField>()); return BuiltinType::InvalidBuiltin; } + void setCustomType(int nameIndex) { - builtinTypeOrTypeNameIndex = nameIndex; - isBuiltinType = false; + data.set<BuiltinTypeOrTypeNameIndexField>(nameIndex); + data.set<IsBuiltinTypeField>(false); } + + int customType() const + { + return data.get<IsBuiltinTypeField>() ? -1 : data.get<BuiltinTypeOrTypeNameIndexField>(); + } + + bool isBuiltinType() const { return data.get<IsBuiltinTypeField>(); } + uint builtinTypeOrTypeNameIndex() const { return data.get<BuiltinTypeOrTypeNameIndexField>(); } + + bool isList() const { return data.get<IsListField>(); } + void setIsList(bool isList) { data.set<IsListField>(isList); } + + bool isRequired() const { return data.get<IsRequiredField>(); } + void setIsRequired(bool isRequired) { data.set<IsRequiredField>(isRequired); } + + bool isReadOnly() const { return data.get<IsReadOnlyField>(); } + void setIsReadOnly(bool isReadOnly) { data.set<IsReadOnlyField>(isReadOnly); } }; static_assert(sizeof(Property) == 12, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); @@ -702,20 +800,31 @@ struct RequiredPropertyExtraData { static_assert (sizeof(RequiredPropertyExtraData) == 4, "RequiredPropertyExtraData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); struct Alias { - enum Flags : unsigned int { +private: + using NameIndexField = quint32_le_bitfield_member<0, 29>; + using FlagsField = quint32_le_bitfield_member<29, 3>; + + // object id index (in QQmlContextData::idValues) + using TargetObjectIdField = quint32_le_bitfield_member<0, 31>; + using AliasToLocalAliasField = quint32_le_bitfield_member<31, 1>; + +public: + + enum Flag : unsigned int { IsReadOnly = 0x1, Resolved = 0x2, AliasPointsToPointerObject = 0x4 }; - union { - quint32_le_bitfield<0, 29> nameIndex; - quint32_le_bitfield<29, 3> flags; - }; + Q_DECLARE_FLAGS(Flags, Flag) + + quint32_le_bitfield_union<NameIndexField, FlagsField> nameIndexAndFlags; + union { quint32_le idIndex; // string index - quint32_le_bitfield<0, 31> targetObjectId; // object id index (in QQmlContextData::idValues) - quint32_le_bitfield<31, 1> aliasToLocalAlias; + quint32_le_bitfield_union<TargetObjectIdField, AliasToLocalAliasField> + targetObjectIdAndAliasToLocalAlias; }; + union { quint32_le propertyNameIndex; // string index qint32_le encodedMetaPropertyIndex; @@ -724,16 +833,67 @@ struct Alias { Location location; Location referenceLocation; - bool isObjectAlias() const { - Q_ASSERT(flags & Resolved); + bool hasFlag(Flag flag) const + { + return nameIndexAndFlags.get<FlagsField>() & flag; + } + + void setFlag(Flag flag) + { + nameIndexAndFlags.set<FlagsField>(nameIndexAndFlags.get<FlagsField>() | flag); + } + + void clearFlags() + { + nameIndexAndFlags.set<FlagsField>(0); + } + + quint32 nameIndex() const + { + return nameIndexAndFlags.get<NameIndexField>(); + } + + void setNameIndex(quint32 nameIndex) + { + nameIndexAndFlags.set<NameIndexField>(nameIndex); + } + + bool isObjectAlias() const + { + Q_ASSERT(hasFlag(Resolved)); return encodedMetaPropertyIndex == -1; } + + bool isAliasToLocalAlias() const + { + return targetObjectIdAndAliasToLocalAlias.get<AliasToLocalAliasField>(); + } + + void setIsAliasToLocalAlias(bool isAliasToLocalAlias) + { + targetObjectIdAndAliasToLocalAlias.set<AliasToLocalAliasField>(isAliasToLocalAlias); + } + + quint32 targetObjectId() const + { + return targetObjectIdAndAliasToLocalAlias.get<TargetObjectIdField>(); + } + + void setTargetObjectId(quint32 targetObjectId) + { + targetObjectIdAndAliasToLocalAlias.set<TargetObjectIdField>(targetObjectId); + } }; static_assert(sizeof(Alias) == 20, "Alias structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); struct Object { - enum Flags : unsigned int { +private: + using FlagsField = quint32_le_bitfield_member<0, 15>; + using DefaultPropertyIsAliasField = quint32_le_bitfield_member<15, 1>; + using IdField = quint32_le_bitfield_member<16, 16, qint32>; +public: + enum Flag : unsigned int { NoFlag = 0x0, IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary HasDeferredBindings = 0x2, // any of the bindings are deferred @@ -741,17 +901,15 @@ struct Object IsInlineComponentRoot = 0x8, InPartOfInlineComponent = 0x10 }; + Q_DECLARE_FLAGS(Flags, Flag); // Depending on the use, this may be the type name to instantiate before instantiating this // object. For grouped properties the type name will be empty and for attached properties // it will be the name of the attached type. quint32_le inheritedTypeNameIndex; quint32_le idNameIndex; - union { - quint32_le_bitfield<0, 15> flags; - quint32_le_bitfield<15, 1> defaultPropertyIsAlias; - qint32_le_bitfield<16, 16> id; - }; + quint32_le_bitfield_union<FlagsField, DefaultPropertyIsAliasField, IdField> + flagsAndDefaultPropertyIsAliasAndId; qint32_le indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object quint16_le nFunctions; quint16_le nProperties; @@ -780,6 +938,48 @@ struct Object // InlineComponent[] // RequiredPropertyExtraData[] + Flags flags() const + { + return Flags(flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>()); + } + + bool hasFlag(Flag flag) const + { + return flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() & flag; + } + + void setFlag(Flag flag) + { + flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>( + flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() | flag); + } + + void setFlags(Flags flags) + { + flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>(flags); + } + + bool hasAliasAsDefaultProperty() const + { + return flagsAndDefaultPropertyIsAliasAndId.get<DefaultPropertyIsAliasField>(); + } + + void setHasAliasAsDefaultProperty(bool defaultAlias) + { + flagsAndDefaultPropertyIsAliasAndId.set<DefaultPropertyIsAliasField>(defaultAlias); + } + + qint32 objectId() const + { + return flagsAndDefaultPropertyIsAliasAndId.get<IdField>(); + } + + void setObjectId(qint32 id) + { + flagsAndDefaultPropertyIsAliasAndId.set<IdField>(id); + } + + static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents, int nRequiredPropertyExtraData) { return ( sizeof(Object) @@ -1129,8 +1329,8 @@ struct TypeReferenceMap : QHash<int, TypeReference> auto prop = obj->propertiesBegin(); auto const propEnd = obj->propertiesEnd(); for ( ; prop != propEnd; ++prop) { - if (!prop->isBuiltinType) { - TypeReference &r = this->add(prop->builtinTypeOrTypeNameIndex, prop->location); + if (!prop->isBuiltinType()) { + TypeReference &r = this->add(prop->builtinTypeOrTypeNameIndex(), prop->location); r.errorWhenNotFound = true; } } @@ -1138,7 +1338,7 @@ struct TypeReferenceMap : QHash<int, TypeReference> auto binding = obj->bindingsBegin(); auto const bindingEnd = obj->bindingsEnd(); for ( ; binding != bindingEnd; ++binding) { - if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) + if (binding->type() == QV4::CompiledData::Binding::Type_AttachedProperty) this->add(binding->propertyNameIndex, binding->location); } diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 36b7f68de9..36269691fc 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -76,7 +76,7 @@ void Object::simplifyRequiredProperties() { for (auto it = this->propertiesBegin(); it != this->propertiesEnd(); ++it) { auto requiredIt = required.find(it->nameIndex); if (requiredIt != required.end()) { - it->isRequired = true; + it->setIsRequired(true); required.erase(requiredIt); } } @@ -106,20 +106,18 @@ bool Parameter::init(QV4::CompiledData::Parameter *param, const QV4::Compiler::J bool Parameter::initType(QV4::CompiledData::ParameterType *paramType, const QV4::Compiler::JSUnitGenerator *stringGenerator, int typeNameIndex) { - paramType->indexIsBuiltinType = false; - paramType->typeNameIndexOrBuiltinType = 0; const QString typeName = stringGenerator->stringForIndex(typeNameIndex); auto builtinType = stringToBuiltinType(typeName); if (builtinType == QV4::CompiledData::BuiltinType::InvalidBuiltin) { - if (typeName.isEmpty() || !typeName.at(0).isUpper()) + if (typeName.isEmpty() || !typeName.at(0).isUpper()) { + paramType->set(false, 0); return false; - paramType->indexIsBuiltinType = false; - paramType->typeNameIndexOrBuiltinType = typeNameIndex; + } Q_ASSERT(quint32(typeNameIndex) < (1u << 31)); + paramType->set(false, typeNameIndex); } else { - paramType->indexIsBuiltinType = true; - paramType->typeNameIndexOrBuiltinType = static_cast<quint32>(builtinType); Q_ASSERT(quint32(builtinType) < (1u << 31)); + paramType->set(true, static_cast<quint32>(builtinType)); } return true; } @@ -173,9 +171,7 @@ void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, cons { inheritedTypeNameIndex = typeNameIndex; - location.line = loc.startLine; - location.column = loc.startColumn; - + location.set(loc.startLine, loc.startColumn); idNameIndex = idIndex; id = -1; indexOfDefaultPropertyOrAlias = -1; @@ -198,8 +194,8 @@ QString IRBuilder::sanityCheckFunctionNames(Object *obj, const QSet<QString> &il QSet<int> functionNames; for (auto functionit = obj->functionsBegin(); functionit != obj->functionsEnd(); ++functionit) { Function *f = functionit.ptr; - errorLocation->startLine = f->location.line; - errorLocation->startColumn = f->location.column; + errorLocation->startLine = f->location.line(); + errorLocation->startColumn = f->location.column(); if (functionNames.contains(f->nameIndex)) return tr("Duplicate method name"); functionNames.insert(f->nameIndex); @@ -280,7 +276,7 @@ QString Object::appendAlias(Alias *alias, const QString &aliasName, bool isDefau target = this; auto aliasWithSameName = std::find_if(target->aliases->begin(), target->aliases->end(), [&alias](const Alias &targetAlias){ - return targetAlias.nameIndex == alias->nameIndex; + return targetAlias.nameIndex() == alias->nameIndex(); }); if (aliasWithSameName != target->aliases->end()) return tr("Duplicate alias name"); @@ -323,13 +319,17 @@ void Object::appendRequiredPropertyExtraData(RequiredPropertyExtraData *extraDat QString Object::appendBinding(Binding *b, bool isListBinding) { const bool bindingToDefaultProperty = (b->propertyNameIndex == quint32(0)); - if (!isListBinding && !bindingToDefaultProperty - && b->type != QV4::CompiledData::Binding::Type_GroupProperty - && b->type != QV4::CompiledData::Binding::Type_AttachedProperty - && !(b->flags & QV4::CompiledData::Binding::IsOnAssignment)) { + if (!isListBinding + && !bindingToDefaultProperty + && b->type() != QV4::CompiledData::Binding::Type_GroupProperty + && b->type() != QV4::CompiledData::Binding::Type_AttachedProperty + && !b->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) { Binding *existing = findBinding(b->propertyNameIndex); - if (existing && existing->isValueBinding() == b->isValueBinding() && !(existing->flags & QV4::CompiledData::Binding::IsOnAssignment)) + if (existing + && existing->isValueBinding() == b->isValueBinding() + && !existing->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) { return tr("Property value set multiple times"); + } } if (bindingToDefaultProperty) insertSorted(b); @@ -397,8 +397,7 @@ void ScriptDirectivesCollector::importFile(const QString &jsfile, const QString import->type = QV4::CompiledData::Import::ImportScript; import->uriIndex = jsGenerator->registerString(jsfile); import->qualifierIndex = jsGenerator->registerString(module); - import->location.line = lineNumber; - import->location.column = column; + import->location.set(lineNumber, column); document->imports << import; } @@ -413,8 +412,7 @@ void ScriptDirectivesCollector::importModule(const QString &uri, const QString & import->majorVersion = vmaj; import->minorVersion = vmin; import->qualifierIndex = jsGenerator->registerString(module); - import->location.line = lineNumber; - import->location.column = column; + import->location.set(lineNumber, column); document->imports << import; } @@ -575,8 +573,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiInlineComponent *ast) inlineComponent->nameIndex = registerString(ast->name.toString()); inlineComponent->objectIndex = idx; auto location = ast->firstSourceLocation(); - inlineComponent->location.line = location.startLine; - inlineComponent->location.column = location.startColumn; + inlineComponent->location.set(location.startLine, location.startColumn); _object->appendInlineComponent(inlineComponent); return false; } @@ -772,8 +769,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node) import->minorVersion = -1; } - import->location.line = node->importToken.startLine; - import->location.column = node->importToken.startColumn; + import->location.set(node->importToken.startLine, node->importToken.startColumn); import->uriIndex = registerString(uri); @@ -801,8 +797,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPragma *node) return false; } - pragma->location.line = node->pragmaToken.startLine; - pragma->location.column = node->pragmaToken.startColumn; + pragma->location.set(node->pragmaToken.startLine, node->pragmaToken.startColumn); _pragmas.append(pragma); return false; @@ -835,8 +830,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiEnumDeclaration *node) if (enumName.at(0).isLower()) COMPILE_EXCEPTION(node->enumToken, tr("Scoped enum names must begin with an upper case letter")); - enumeration->location.line = node->enumToken.startLine; - enumeration->location.column = node->enumToken.startColumn; + enumeration->location.set(node->enumToken.startLine, node->enumToken.startColumn); enumeration->enumValues = New<PoolList<EnumValue>>(); @@ -855,8 +849,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiEnumDeclaration *node) COMPILE_EXCEPTION(e->valueToken, tr("Enum value out of range")); enumValue->value = e->value; - enumValue->location.line = e->memberToken.startLine; - enumValue->location.column = e->memberToken.startColumn; + enumValue->location.set(e->memberToken.startLine, e->memberToken.startColumn); enumeration->enumValues->append(enumValue); e = e->next; @@ -880,8 +873,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) signal->nameIndex = registerString(signalName); QQmlJS::SourceLocation loc = node->typeToken; - signal->location.line = loc.startLine; - signal->location.column = loc.startColumn; + signal->location.set(loc.startLine, loc.startColumn); signal->parameters = New<PoolList<Parameter> >(); @@ -930,8 +922,8 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) const QStringRef &name = node->name; Property *property = New<Property>(); - property->isReadOnly = node->isReadonlyMember; - property->isRequired = node->isRequired; + property->setIsReadOnly(node->isReadonlyMember); + property->setIsRequired(node->isRequired); QV4::CompiledData::BuiltinType builtinPropertyType = Parameter::stringToBuiltinType(memberType); bool typeFound = builtinPropertyType != QV4::CompiledData::BuiltinType::InvalidBuiltin; @@ -943,7 +935,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) property->setCustomType(registerString(memberType)); if (typeModifier == QLatin1String("list")) { - property->isList = true; + property->setIsList(true); } else if (!typeModifier.isEmpty()) { recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier")); return false; @@ -963,8 +955,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) property->nameIndex = registerString(propName); QQmlJS::SourceLocation loc = node->firstSourceLocation(); - property->location.line = loc.startLine; - property->location.column = loc.startColumn; + property->location.set(loc.startLine, loc.startColumn); QQmlJS::SourceLocation errorLocation; QString error; @@ -1008,8 +999,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node) Function *f = New<Function>(); QQmlJS::SourceLocation loc = funDecl->identifierToken; - f->location.line = loc.startLine; - f->location.column = loc.startColumn; + f->location.set(loc.startLine, loc.startColumn); f->index = index; f->nameIndex = registerString(funDecl->name.toString()); @@ -1089,26 +1079,25 @@ QStringRef IRBuilder::textRefAt(const QQmlJS::SourceLocation &first, const QQmlJ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement, QQmlJS::AST::Node *parentNode) { QQmlJS::SourceLocation loc = statement->firstSourceLocation(); - binding->valueLocation.line = loc.startLine; - binding->valueLocation.column = loc.startColumn; - binding->type = QV4::CompiledData::Binding::Type_Invalid; - if (_propertyDeclaration && _propertyDeclaration->isReadOnly) - binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration; + binding->valueLocation.set(loc.startLine, loc.startColumn); + binding->setType(QV4::CompiledData::Binding::Type_Invalid); + if (_propertyDeclaration && _propertyDeclaration->isReadOnly()) + binding->setFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration); QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement); if (exprStmt) { QQmlJS::AST::ExpressionNode * const expr = exprStmt->expression; if (QQmlJS::AST::StringLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(expr)) { - binding->type = QV4::CompiledData::Binding::Type_String; + binding->setType(QV4::CompiledData::Binding::Type_String); binding->stringIndex = registerString(lit->value.toString()); } else if (expr->kind == QQmlJS::AST::Node::Kind_TrueLiteral) { - binding->type = QV4::CompiledData::Binding::Type_Boolean; + binding->setType(QV4::CompiledData::Binding::Type_Boolean); binding->value.b = true; } else if (expr->kind == QQmlJS::AST::Node::Kind_FalseLiteral) { - binding->type = QV4::CompiledData::Binding::Type_Boolean; + binding->setType(QV4::CompiledData::Binding::Type_Boolean); binding->value.b = false; } else if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(expr)) { - binding->type = QV4::CompiledData::Binding::Type_Number; + binding->setType(QV4::CompiledData::Binding::Type_Number); binding->value.constantValueIndex = jsGenerator->registerConstant(QV4::Encode(lit->value)); } else if (QQmlJS::AST::CallExpression *call = QQmlJS::AST::cast<QQmlJS::AST::CallExpression *>(expr)) { if (QQmlJS::AST::IdentifierExpression *base = QQmlJS::AST::cast<QQmlJS::AST::IdentifierExpression *>(call->base)) { @@ -1117,21 +1106,21 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST // below. } } else if (QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression *>(expr)) { - binding->flags |= QV4::CompiledData::Binding::IsFunctionExpression; + binding->setFlag(QV4::CompiledData::Binding::IsFunctionExpression); } else if (QQmlJS::AST::UnaryMinusExpression *unaryMinus = QQmlJS::AST::cast<QQmlJS::AST::UnaryMinusExpression *>(expr)) { if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(unaryMinus->expression)) { - binding->type = QV4::CompiledData::Binding::Type_Number; + binding->setType(QV4::CompiledData::Binding::Type_Number); binding->value.constantValueIndex = jsGenerator->registerConstant(QV4::Encode(-lit->value)); } } else if (QQmlJS::AST::cast<QQmlJS::AST::NullExpression *>(expr)) { - binding->type = QV4::CompiledData::Binding::Type_Null; + binding->setType(QV4::CompiledData::Binding::Type_Null); binding->value.nullMarker = 0; } } // Do binding instead - if (binding->type == QV4::CompiledData::Binding::Type_Invalid) { - binding->type = QV4::CompiledData::Binding::Type_Script; + if (binding->type() == QV4::CompiledData::Binding::Type_Invalid) { + binding->setType(QV4::CompiledData::Binding::Type_Script); CompiledFunctionOrExpression *expr = New<CompiledFunctionOrExpression>(); expr->node = statement; @@ -1187,7 +1176,7 @@ void IRBuilder::tryGeneratingTranslationBinding(const QStringRef &base, AST::Arg if (args) return; // too many arguments, stop - binding->type = QV4::CompiledData::Binding::Type_Translation; + binding->setType(QV4::CompiledData::Binding::Type_Translation); binding->value.translationDataIndex = jsGenerator->registerTranslation(translationData); } else if (base == QLatin1String("qsTrId")) { QV4::CompiledData::TranslationData translationData; @@ -1220,7 +1209,7 @@ void IRBuilder::tryGeneratingTranslationBinding(const QStringRef &base, AST::Arg if (args) return; // too many arguments, stop - binding->type = QV4::CompiledData::Binding::Type_TranslationById; + binding->setType(QV4::CompiledData::Binding::Type_TranslationById); binding->value.translationDataIndex = jsGenerator->registerTranslation(translationData); } else if (base == QLatin1String("QT_TR_NOOP") || base == QLatin1String("QT_TRID_NOOP")) { if (!args || !args->expression) @@ -1237,7 +1226,7 @@ void IRBuilder::tryGeneratingTranslationBinding(const QStringRef &base, AST::Arg if (args) return; // too many arguments, stop - binding->type = QV4::CompiledData::Binding::Type_String; + binding->setType(QV4::CompiledData::Binding::Type_String); binding->stringIndex = jsGenerator->registerString(str.toString()); } else if (base == QLatin1String("QT_TRANSLATE_NOOP")) { if (!args || !args->expression) @@ -1258,7 +1247,7 @@ void IRBuilder::tryGeneratingTranslationBinding(const QStringRef &base, AST::Arg if (args) return; // too many arguments, stop - binding->type = QV4::CompiledData::Binding::Type_String; + binding->setType(QV4::CompiledData::Binding::Type_String); binding->stringIndex = jsGenerator->registerString(str.toString()); } } @@ -1295,9 +1284,8 @@ void IRBuilder::appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocatio Binding *binding = New<Binding>(); binding->propertyNameIndex = propertyNameIndex; binding->offset = nameLocation.offset; - binding->location.line = nameLocation.startLine; - binding->location.column = nameLocation.startColumn; - binding->flags = 0; + binding->location.set(nameLocation.startLine, nameLocation.startColumn); + binding->clearFlags(); setBindingValue(binding, value, parentNode); QString error = bindingsTarget()->appendBinding(binding, /*isListBinding*/false); if (!error.isEmpty()) { @@ -1315,27 +1303,26 @@ void IRBuilder::appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocatio Binding *binding = New<Binding>(); binding->propertyNameIndex = propertyNameIndex; binding->offset = nameLocation.offset; - binding->location.line = nameLocation.startLine; - binding->location.column = nameLocation.startColumn; + binding->location.set(nameLocation.startLine, nameLocation.startColumn); const Object *obj = _objects.at(objectIndex); binding->valueLocation = obj->location; - binding->flags = 0; + binding->clearFlags(); - if (_propertyDeclaration && _propertyDeclaration->isReadOnly) - binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration; + if (_propertyDeclaration && _propertyDeclaration->isReadOnly()) + binding->setFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration); // No type name on the initializer means it must be a group property if (_objects.at(objectIndex)->inheritedTypeNameIndex == emptyStringIndex) - binding->type = QV4::CompiledData::Binding::Type_GroupProperty; + binding->setType(Binding::Type_GroupProperty); else - binding->type = QV4::CompiledData::Binding::Type_Object; + binding->setType(Binding::Type_Object); if (isOnAssignment) - binding->flags |= QV4::CompiledData::Binding::IsOnAssignment; + binding->setFlag(Binding::IsOnAssignment); if (isListItem) - binding->flags |= QV4::CompiledData::Binding::IsListItem; + binding->setFlag(Binding::IsListItem); binding->value.objectIndex = objectIndex; QString error = bindingsTarget()->appendBinding(binding, isListItem); @@ -1347,16 +1334,15 @@ void IRBuilder::appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocatio bool IRBuilder::appendAlias(QQmlJS::AST::UiPublicMember *node) { Alias *alias = New<Alias>(); - alias->flags = 0; + alias->clearFlags(); if (node->isReadonlyMember) - alias->flags |= QV4::CompiledData::Alias::IsReadOnly; + alias->setFlag(QV4::CompiledData::Alias::IsReadOnly); const QString propName = node->name.toString(); - alias->nameIndex = registerString(propName); + alias->setNameIndex(registerString(propName)); QQmlJS::SourceLocation loc = node->firstSourceLocation(); - alias->location.line = loc.startLine; - alias->location.column = loc.startColumn; + alias->location.set(loc.startLine, loc.startColumn); alias->propertyNameIndex = emptyStringIndex; @@ -1370,8 +1356,7 @@ bool IRBuilder::appendAlias(QQmlJS::AST::UiPublicMember *node) rhsLoc = node->statement->firstSourceLocation(); else rhsLoc = node->semicolonToken; - alias->referenceLocation.line = rhsLoc.startLine; - alias->referenceLocation.column = rhsLoc.startColumn; + alias->referenceLocation.set(rhsLoc.startLine, rhsLoc.startColumn); QStringList aliasReference; @@ -1466,8 +1451,7 @@ bool IRBuilder::setId(const QQmlJS::SourceLocation &idLocation, QQmlJS::AST::Sta COMPILE_EXCEPTION(idLocation, tr("Property value set multiple times")); _object->idNameIndex = registerString(idQString); - _object->locationOfIdProperty.line = idLocation.startLine; - _object->locationOfIdProperty.column = idLocation.startColumn; + _object->locationOfIdProperty.set(idLocation.startLine, idLocation.startColumn); return true; } @@ -1513,19 +1497,23 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O binding = New<Binding>(); binding->propertyNameIndex = propertyNameIndex; binding->offset = qualifiedIdElement->identifierToken.offset; - binding->location.line = qualifiedIdElement->identifierToken.startLine; - binding->location.column = qualifiedIdElement->identifierToken.startColumn; - binding->valueLocation.line = qualifiedIdElement->next->identifierToken.startLine; - binding->valueLocation.column = qualifiedIdElement->next->identifierToken.startColumn; - binding->flags = 0; + binding->location.set(qualifiedIdElement->identifierToken.startLine, + qualifiedIdElement->identifierToken.startColumn); + binding->valueLocation.set(qualifiedIdElement->next->identifierToken.startLine, + qualifiedIdElement->next->identifierToken.startColumn); + binding->location.set(qualifiedIdElement->identifierToken.startLine, + qualifiedIdElement->identifierToken.startColumn); + binding->valueLocation.set(qualifiedIdElement->next->identifierToken.startLine, + qualifiedIdElement->next->identifierToken.startColumn); + binding->clearFlags(); if (onAssignment) - binding->flags |= QV4::CompiledData::Binding::IsOnAssignment; + binding->setFlag(QV4::CompiledData::Binding::IsOnAssignment); if (isAttachedProperty) - binding->type = QV4::CompiledData::Binding::Type_AttachedProperty; + binding->setType(QV4::CompiledData::Binding::Type_AttachedProperty); else - binding->type = QV4::CompiledData::Binding::Type_GroupProperty; + binding->setType(QV4::CompiledData::Binding::Type_GroupProperty); int objIndex = 0; if (!defineQMLObject(&objIndex, nullptr, QQmlJS::SourceLocation(), nullptr, nullptr)) @@ -1586,7 +1574,7 @@ bool IRBuilder::isStatementNodeScript(QQmlJS::AST::Statement *statement) bool IRBuilder::isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement) { - if (property->isBuiltinType || property->isList) + if (property->isBuiltinType() || property->isList()) return false; QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement); if (!exprStmt) @@ -1684,10 +1672,10 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen QV4::CompiledData::Object *objectToWrite = reinterpret_cast<QV4::CompiledData::Object*>(objectPtr); objectToWrite->inheritedTypeNameIndex = o->inheritedTypeNameIndex; objectToWrite->indexOfDefaultPropertyOrAlias = o->indexOfDefaultPropertyOrAlias; - objectToWrite->defaultPropertyIsAlias = o->defaultPropertyIsAlias; - objectToWrite->flags = o->flags; + objectToWrite->setHasAliasAsDefaultProperty(o->defaultPropertyIsAlias); + objectToWrite->setFlags(QV4::CompiledData::Object::Flags(o->flags)); objectToWrite->idNameIndex = o->idNameIndex; - objectToWrite->id = o->id; + objectToWrite->setObjectId(o->id); objectToWrite->location = o->location; objectToWrite->locationOfIdProperty = o->locationOfIdProperty; @@ -1862,7 +1850,7 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, Binding continue; QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr); *bindingToWrite = *b; - if (b->type == QV4::CompiledData::Binding::Type_Script) + if (b->type() == QV4::CompiledData::Binding::Type_Script) bindingToWrite->value.compiledScriptIndex = o->runtimeFunctionIndices.at(b->value.compiledScriptIndex); bindingPtr += sizeof(QV4::CompiledData::Binding); } @@ -1972,7 +1960,7 @@ bool JSCodeGen::compileComponent(int contextObject) if (obj->flags & QV4::CompiledData::Object::IsComponent && !obj->isInlineComponent) { Q_ASSERT(obj->bindingCount() == 1); const QV4::CompiledData::Binding *componentBinding = obj->firstBinding(); - Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object); + Q_ASSERT(componentBinding->type() == QV4::CompiledData::Binding::Type_Object); contextObject = componentBinding->value.objectIndex; } for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) @@ -2000,11 +1988,12 @@ bool JSCodeGen::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int s } for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) { - if (binding->type < QV4::CompiledData::Binding::Type_Object) + const Binding::Type bindingType = binding->type(); + if (bindingType < QV4::CompiledData::Binding::Type_Object) continue; int target = binding->value.objectIndex; - int scope = binding->type == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex; + int scope = bindingType == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex; if (!compileJavaScriptCodeInObjectsRecursively(binding->value.objectIndex, scope)) return false; diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 9629a73199..8996777289 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -394,6 +394,10 @@ public: int namedObjectsInComponentCount() const { return namedObjectsInComponent.size(); } const quint32 *namedObjectsInComponentTable() const { return namedObjectsInComponent.begin(); } + bool hasFlag(QV4::CompiledData::Object::Flag flag) const { return flags & flag; } + qint32 objectId() const { return id; } + bool hasAliasAsDefaultProperty() const { return defaultPropertyIsAlias; } + private: friend struct ::QQmlIRLoader; diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 14cf0a0c8f..18e19cf01c 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -160,10 +160,7 @@ int QV4::Compiler::JSUnitGenerator::registerGetterLookup(const QString &name) int QV4::Compiler::JSUnitGenerator::registerGetterLookup(int nameIndex) { - CompiledData::Lookup l; - l.type_and_flags = CompiledData::Lookup::Type_Getter; - l.nameIndex = nameIndex; - lookups << l; + lookups << CompiledData::Lookup(CompiledData::Lookup::Type_Getter, nameIndex); return lookups.size() - 1; } @@ -174,49 +171,37 @@ int QV4::Compiler::JSUnitGenerator::registerSetterLookup(const QString &name) int QV4::Compiler::JSUnitGenerator::registerSetterLookup(int nameIndex) { - CompiledData::Lookup l; - l.type_and_flags = CompiledData::Lookup::Type_Setter; - l.nameIndex = nameIndex; - lookups << l; + lookups << CompiledData::Lookup(CompiledData::Lookup::Type_Setter, nameIndex); return lookups.size() - 1; } int QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(int nameIndex) { - CompiledData::Lookup l; - l.type_and_flags = CompiledData::Lookup::Type_GlobalGetter; - l.nameIndex = nameIndex; - lookups << l; + lookups << CompiledData::Lookup(CompiledData::Lookup::Type_GlobalGetter, nameIndex); return lookups.size() - 1; } int QV4::Compiler::JSUnitGenerator::registerQmlContextPropertyGetterLookup(int nameIndex) { - CompiledData::Lookup l; - l.type_and_flags = CompiledData::Lookup::Type_QmlContextPropertyGetter; - l.nameIndex = nameIndex; - lookups << l; + lookups << CompiledData::Lookup(CompiledData::Lookup::Type_QmlContextPropertyGetter, nameIndex); return lookups.size() - 1; } int QV4::Compiler::JSUnitGenerator::registerRegExp(QQmlJS::AST::RegExpLiteral *regexp) { - CompiledData::RegExp re; - re.stringIndex = registerString(regexp->pattern.toString()); - - re.flags = 0; + quint32 flags = 0; if (regexp->flags & QQmlJS::Lexer::RegExp_Global) - re.flags |= CompiledData::RegExp::RegExp_Global; + flags |= CompiledData::RegExp::RegExp_Global; if (regexp->flags & QQmlJS::Lexer::RegExp_IgnoreCase) - re.flags |= CompiledData::RegExp::RegExp_IgnoreCase; + flags |= CompiledData::RegExp::RegExp_IgnoreCase; if (regexp->flags & QQmlJS::Lexer::RegExp_Multiline) - re.flags |= CompiledData::RegExp::RegExp_Multiline; + flags |= CompiledData::RegExp::RegExp_Multiline; if (regexp->flags & QQmlJS::Lexer::RegExp_Unicode) - re.flags |= CompiledData::RegExp::RegExp_Unicode; + flags |= CompiledData::RegExp::RegExp_Unicode; if (regexp->flags & QQmlJS::Lexer::RegExp_Sticky) - re.flags |= CompiledData::RegExp::RegExp_Sticky; + flags |= CompiledData::RegExp::RegExp_Sticky; - regexps.append(re); + regexps.append(CompiledData::RegExp(flags, registerString(regexp->pattern.toString()))); return regexps.size() - 1; } @@ -249,8 +234,7 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(const QStringList &members) CompiledData::JSClassMember *member = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + 1); for (const auto &name : members) { - member->nameOffset = registerString(name); - member->isAccessor = false; + member->set(registerString(name), false); ++member; } @@ -468,8 +452,7 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte currentOffset += function->nLabelInfos * sizeof(quint32); } - function->location.line = irFunction->line; - function->location.column = irFunction->column; + function->location.set(irFunction->line, irFunction->column); function->codeOffset = currentOffset; function->codeSize = irFunction->code.size(); diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp index a1ddee8234..bd3a456c36 100644 --- a/src/qml/compiler/qv4compilerscanfunctions.cpp +++ b/src/qml/compiler/qv4compilerscanfunctions.cpp @@ -57,10 +57,7 @@ using namespace QQmlJS::AST; static CompiledData::Location location(const QQmlJS::SourceLocation &astLocation) { - CompiledData::Location target; - target.line = astLocation.startLine; - target.column = astLocation.startColumn; - return target; + return CompiledData::Location(astLocation.startLine, astLocation.startColumn); } diff --git a/src/qml/configure.pri b/src/qml/configure.pri index fcd2eacace..4506a5790d 100644 --- a/src/qml/configure.pri +++ b/src/qml/configure.pri @@ -13,7 +13,7 @@ defineTest(qtConfTest_detectPython) { } # Make tests.python.location available in configure.json. - $${1}.location = $$shell_path($$python_path) + $${1}.location = $$shell_quote($$shell_path($$python_path)) export($${1}.location) $${1}.cache += location export($${1}.cache) diff --git a/src/qml/debugger/qqmldebug.cpp b/src/qml/debugger/qqmldebug.cpp index 58b8ea2c4f..0ca56f3a70 100644 --- a/src/qml/debugger/qqmldebug.cpp +++ b/src/qml/debugger/qqmldebug.cpp @@ -44,17 +44,26 @@ #include <private/qqmlengine_p.h> #include <private/qv4compileddata_p.h> +#include <atomic> #include <cstdio> QT_REQUIRE_CONFIG(qml_debug); QT_BEGIN_NAMESPACE +#if __cplusplus >= 202002L +# define Q_ATOMIC_FLAG_INIT {} +#else +# define Q_ATOMIC_FLAG_INIT ATOMIC_FLAG_INIT // deprecated in C++20 +#endif + +static std::atomic_flag s_printedWarning = Q_ATOMIC_FLAG_INIT; + QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning) { - if (!QQmlEnginePrivate::qml_debugging_enabled && printWarning) + if (printWarning && !s_printedWarning.test_and_set(std::memory_order_relaxed)) fprintf(stderr, "QML debugging is enabled. Only use this in a safe environment.\n"); - QQmlEnginePrivate::qml_debugging_enabled = true; + QQmlEnginePrivate::qml_debugging_enabled.store(true, std::memory_order_relaxed); } /*! diff --git a/src/qml/debugger/qqmldebugconnector.cpp b/src/qml/debugger/qqmldebugconnector.cpp index 0ef40d6911..01a0723b76 100644 --- a/src/qml/debugger/qqmldebugconnector.cpp +++ b/src/qml/debugger/qqmldebugconnector.cpp @@ -111,7 +111,7 @@ QQmlDebugConnector *QQmlDebugConnector::instance() if (!params) return nullptr; - if (!QQmlEnginePrivate::qml_debugging_enabled) { + if (!QQmlEnginePrivate::qml_debugging_enabled.load(std::memory_order_relaxed)) { if (!params->arguments.isEmpty()) { qWarning().noquote() << QString::fromLatin1( "QML Debugger: Ignoring \"-qmljsdebugger=%1\". Debugging " diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h index d3eedab1c6..ed1e011830 100644 --- a/src/qml/debugger/qqmlprofiler_p.h +++ b/src/qml/debugger/qqmlprofiler_p.h @@ -176,7 +176,7 @@ public: RefLocation(QV4::ExecutableCompilationUnit *ref, const QUrl &url, const QV4::CompiledData::Object *obj, const QString &type) - : Location(QQmlSourceLocation(type, obj->location.line, obj->location.column), url), + : Location(QQmlSourceLocation(type, obj->location.line(), obj->location.column()), url), locationType(Creating), sent(false) { unit = ref; diff --git a/src/qml/inlinecomponentutils_p.h b/src/qml/inlinecomponentutils_p.h index 7666457d98..c3ab0e1fe5 100644 --- a/src/qml/inlinecomponentutils_p.h +++ b/src/qml/inlinecomponentutils_p.h @@ -55,26 +55,38 @@ namespace icutils { struct Node { +private: + using IndexType = std::vector<QV4::CompiledData::InlineComponent>::size_type; + using IndexField = quint32_le_bitfield_member<0, 30, IndexType>; + using TemporaryMarkField = quint32_le_bitfield_member<30, 1>; + using PermanentMarkField = quint32_le_bitfield_member<31, 1>; + quint32_le_bitfield_union<IndexField, TemporaryMarkField, PermanentMarkField> m_data; + +public: Node() = default; Node(const Node &) = default; Node(Node &&) = default; Node& operator=(Node const &) = default; Node& operator=(Node &&) = default; - bool operator==(Node const &other) const {return index == other.index;} + bool operator==(Node const &other) const {return m_data.data() == other.m_data.data(); } + + Node(IndexType s) : m_data(QSpecialIntegerBitfieldZero) { m_data.set<IndexField>(s); } + + bool hasPermanentMark() const { return m_data.get<PermanentMarkField>(); } + bool hasTemporaryMark() const { return m_data.get<TemporaryMarkField>(); } + + void setPermanentMark() + { + m_data.set<TemporaryMarkField>(0); + m_data.set<PermanentMarkField>(1); + } - Node(std::vector<QV4::CompiledData::InlineComponent>::size_type s) - : index{0} + void setTemporaryMark() { - index = quint32(s); - temporaryMark = 0; - permanentMark = 0; + m_data.set<TemporaryMarkField>(1); } - union { - quint32_le_bitfield<0, 30> index; - quint32_le_bitfield<30, 1> temporaryMark; - quint32_le_bitfield<31, 1> permanentMark; - }; + IndexType index() const { return m_data.get<IndexField>(); } }; using AdjacencyList = std::vector<std::vector<Node*>>; @@ -109,8 +121,11 @@ void fillAdjacencyListForInlineComponents(ObjectContainer *objectContainer, Adja auto referencedInICObjectIndex = ic.objectIndex + 1; while (int(referencedInICObjectIndex) < objectContainer->objectCount()) { auto potentiallyReferencedInICObject = objectContainer->objectAt(referencedInICObjectIndex); - bool stillInIC = !(potentiallyReferencedInICObject-> flags & QV4::CompiledData::Object::IsInlineComponentRoot) - && (potentiallyReferencedInICObject-> flags & QV4::CompiledData::Object::InPartOfInlineComponent); + bool stillInIC + = !potentiallyReferencedInICObject->hasFlag( + QV4::CompiledData::Object::IsInlineComponentRoot) + && potentiallyReferencedInICObject->hasFlag( + QV4::CompiledData::Object::InPartOfInlineComponent); if (!stillInIC) break; createEdgeFromTypeRef(objectContainer->resolvedType(potentiallyReferencedInICObject->inheritedTypeNameIndex)); @@ -120,21 +135,20 @@ void fillAdjacencyListForInlineComponents(ObjectContainer *objectContainer, Adja }; inline void topoVisit(Node *node, AdjacencyList &adjacencyList, bool &hasCycle, std::vector<Node> &nodesSorted) { - if (node->permanentMark) + if (node->hasPermanentMark()) return; - if (node->temporaryMark) { + if (node->hasTemporaryMark()) { hasCycle = true; return; } - node->temporaryMark = 1; + node->setTemporaryMark(); - auto const &edges = adjacencyList[node->index]; + auto const &edges = adjacencyList[node->index()]; for (auto edgeTarget =edges.begin(); edgeTarget != edges.end(); ++edgeTarget) { topoVisit(*edgeTarget, adjacencyList, hasCycle, nodesSorted); } - node->temporaryMark = 0; - node->permanentMark = 1; + node->setPermanentMark(); nodesSorted.push_back(*node); }; @@ -145,7 +159,7 @@ inline std::vector<Node> topoSort(std::vector<Node> &nodes, AdjacencyList &adjac hasCycle = false; auto currentNodeIt = std::find_if(nodes.begin(), nodes.end(), [](const Node& node) { - return node.permanentMark == 0; + return !node.hasPermanentMark(); }); // Do a topological sort of all inline components // afterwards, nodesSorted contains the nodes for the inline components in reverse topological order @@ -153,7 +167,7 @@ inline std::vector<Node> topoSort(std::vector<Node> &nodes, AdjacencyList &adjac Node& currentNode = *currentNodeIt; topoVisit(¤tNode, adjacencyList, hasCycle, nodesSorted); currentNodeIt = std::find_if(nodes.begin(), nodes.end(), [](const Node& node) { - return node.permanentMark == 0; + return !node.hasPermanentMark(); }); } return nodesSorted; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index d26e991d3f..f5dca60559 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -300,6 +300,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) if (ok && envMaxGCStackSize > 0) m_maxGCStackSize = envMaxGCStackSize; + // We allocate guard pages around our stacks. + const size_t guardPages = 2 * WTF::pageSize(); + memoryManager = new QV4::MemoryManager(this); if (maxCallDepth == -1) { @@ -327,9 +330,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) // reserve space for the JS stack // we allow it to grow to a bit more than m_maxJSStackSize, as we can overshoot due to ScopedValues // allocated outside of JIT'ed methods. - *jsStack = WTF::PageAllocation::allocate(m_maxJSStackSize + 256*1024, WTF::OSAllocator::JSVMStackPages, - /* writable */ true, /* executable */ false, - /* includesGuardPages */ true); + *jsStack = WTF::PageAllocation::allocate( + m_maxJSStackSize + 256*1024 + guardPages, WTF::OSAllocator::JSVMStackPages, + /* writable */ true, /* executable */ false, /* includesGuardPages */ true); jsStackBase = (Value *)jsStack->base(); #ifdef V4_USE_VALGRIND VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, m_maxJSStackSize + 256*1024); @@ -337,9 +340,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) jsStackTop = jsStackBase; - *gcStack = WTF::PageAllocation::allocate(m_maxGCStackSize, WTF::OSAllocator::JSVMStackPages, - /* writable */ true, /* executable */ false, - /* includesGuardPages */ true); + *gcStack = WTF::PageAllocation::allocate( + m_maxGCStackSize + guardPages, WTF::OSAllocator::JSVMStackPages, + /* writable */ true, /* executable */ false, /* includesGuardPages */ true); { ok = false; @@ -2030,7 +2033,7 @@ void ExecutionEngine::setQmlEngine(QQmlEngine *engine) static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object) { - if (object->as<QV4::QObjectWrapper>() || object->internalClass()->isFrozen) + if (object->as<QV4::QObjectWrapper>() || object->internalClass()->isFrozen()) return; QV4::Scope scope(v4); diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp index 5eb0e889b0..09a1e936ad 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit.cpp +++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp @@ -155,10 +155,10 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine) data->regexpTableSize * sizeof(QV4::Value)); for (uint i = 0; i < data->regexpTableSize; ++i) { const CompiledData::RegExp *re = data->regexpAt(i); - uint f = re->flags; + uint f = re->flags(); const CompiledData::RegExp::Flags flags = static_cast<CompiledData::RegExp::Flags>(f); runtimeRegularExpressions[i] = QV4::RegExp::create( - engine, stringAt(re->stringIndex), flags); + engine, stringAt(re->stringIndex()), flags); } if (data->lookupTableSize) { @@ -169,7 +169,7 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine) QV4::Lookup *l = runtimeLookups + i; CompiledData::Lookup::Type type - = CompiledData::Lookup::Type(uint(compiledLookups[i].type_and_flags)); + = CompiledData::Lookup::Type(uint(compiledLookups[i].typeAndFlags())); if (type == CompiledData::Lookup::Type_Getter) l->getter = QV4::Lookup::getterGeneric; else if (type == CompiledData::Lookup::Type_Setter) @@ -178,7 +178,7 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine) l->globalGetter = QV4::Lookup::globalGetterGeneric; else if (type == CompiledData::Lookup::Type_QmlContextPropertyGetter) l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter; - l->nameIndex = compiledLookups[i].nameIndex; + l->nameIndex = compiledLookups[i].nameIndex(); } } @@ -199,8 +199,8 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine) runtimeClasses[i] = runtimeClasses[i]->addMember( engine->identifierTable->asPropertyKey( - runtimeStrings[member->nameOffset]), - member->isAccessor + runtimeStrings[member->nameOffset()]), + member->isAccessor() ? QV4::Attr_Accessor : QV4::Attr_Data); } @@ -368,7 +368,7 @@ IdentifierHash ExecutableCompilationUnit::createNamedObjectsPerComponent(int com const quint32_le *namedObjectIndexPtr = component->namedObjectsInComponentTable(); for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) { const CompiledData::Object *namedObject = objectAt(*namedObjectIndexPtr); - namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id); + namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->objectId()); } return *namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache); } @@ -421,13 +421,14 @@ void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngi // We need to first iterate over all inline components, as the containing component might create instances of them // and in that case we need to add its object count for (auto nodeIt = nodesSorted.rbegin(); nodeIt != nodesSorted.rend(); ++nodeIt) { - const auto &ic = allICs.at(nodeIt->index); + const auto &ic = allICs.at(nodeIt->index()); int lastICRoot = ic.objectIndex; for (int i = ic.objectIndex; i<objectCount(); ++i) { const QV4::CompiledData::Object *obj = objectAt(i); - bool leftCurrentInlineComponent = - (i != lastICRoot && obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot) - || !(obj->flags & QV4::CompiledData::Object::InPartOfInlineComponent); + bool leftCurrentInlineComponent + = (i != lastICRoot + && obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot)) + || !obj->hasFlag(QV4::CompiledData::Object::InPartOfInlineComponent); if (leftCurrentInlineComponent) break; inlineComponentData[lastICRoot].totalBindingCount += obj->nBindings; @@ -457,9 +458,9 @@ void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngi int objectCount = 0; for (quint32 i = 0, count = this->objectCount(); i < count; ++i) { const QV4::CompiledData::Object *obj = objectAt(i); - if (obj->flags & QV4::CompiledData::Object::InPartOfInlineComponent) { + if (obj->hasFlag(QV4::CompiledData::Object::InPartOfInlineComponent)) continue; - } + bindingCount += obj->nBindings; if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) { if (typeRef->type.isValid() && typeRef->type.parserStatusCast() != -1) @@ -571,7 +572,9 @@ Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine) if (!valuePtr) { QString referenceErrorMessage = QStringLiteral("Unable to resolve import reference "); referenceErrorMessage += importName->toQString(); - engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column); + engine->throwReferenceError( + referenceErrorMessage, fileName(), + entry.location.line(), entry.location.column()); return nullptr; } imports[i] = valuePtr; @@ -587,7 +590,9 @@ Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine) if (!dependentModuleUnit->resolveExport(importName)) { QString referenceErrorMessage = QStringLiteral("Unable to resolve re-export reference "); referenceErrorMessage += importName->toQString(); - engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column); + engine->throwReferenceError( + referenceErrorMessage, fileName(), + entry.location.line(), entry.location.column()); return nullptr; } } @@ -858,7 +863,7 @@ bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *e QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Binding *binding) const { using namespace CompiledData; - switch (binding->type) { + switch (binding->type()) { case Binding::Type_Script: case Binding::Type_String: return stringAt(binding->stringIndex); @@ -906,7 +911,7 @@ QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Bind QString ExecutableCompilationUnit::bindingValueAsScriptString( const CompiledData::Binding *binding) const { - return (binding->type == CompiledData::Binding::Type_String) + return (binding->type() == CompiledData::Binding::Type_String) ? CompiledData::Binding::escapedString(stringAt(binding->stringIndex)) : bindingValueAsString(binding); } diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h index 7bfb68da9d..29e82bf2d5 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit_p.h +++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h @@ -282,7 +282,7 @@ public: QString bindingValueAsScriptString(const CompiledData::Binding *binding) const; double bindingValueAsNumber(const CompiledData::Binding *binding) const { - if (binding->type != CompiledData::Binding::Type_Number) + if (binding->type() != CompiledData::Binding::Type_Number) return 0.0; return constants[binding->value.constantValueIndex].doubleValue(); } diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index aeb4835c40..cf8a53cf9f 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -176,7 +176,8 @@ QString Function::prettyName(const Function *function, const void *code) QQmlSourceLocation Function::sourceLocation() const { - return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column); + return QQmlSourceLocation( + sourceFile(), compiledFunction->location.line(), compiledFunction->location.column()); } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 1cd2ecffa4..ccc55d869f 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -303,7 +303,6 @@ struct PropertyAttributes void clear() { m_all = 0; } bool isEmpty() const { return !m_all; } - uint flags() const { return m_flags; } uint all() const { return m_all; } bool operator==(PropertyAttributes other) { diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 70849775cb..904c6a5eaf 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -178,7 +178,7 @@ void SharedInternalClassDataPrivate<PropertyKey>::setSize(uint s) data->values.size = s; } -PropertyKey SharedInternalClassDataPrivate<PropertyKey>::at(uint i) +PropertyKey SharedInternalClassDataPrivate<PropertyKey>::at(uint i) const { Q_ASSERT(data && i < size()); return PropertyKey::fromId(data->values.values[i].rawValue()); @@ -265,6 +265,13 @@ namespace Heap { void InternalClass::init(ExecutionEngine *engine) { +// InternalClass is automatically zeroed during allocation: +// prototype = nullptr; +// parent = nullptr; +// size = 0; +// numRedundantTransitions = 0; +// flags = 0; + Base::init(); new (&propertyTable) PropertyHash(); new (&nameMap) SharedInternalClassData<PropertyKey>(engine); @@ -273,13 +280,6 @@ void InternalClass::init(ExecutionEngine *engine) this->engine = engine; vtable = QV4::InternalClass::staticVTable(); -// prototype = nullptr; -// parent = nullptr; -// size = 0; - extensible = true; - isFrozen = false; - isSealed = false; - isUsedAsProto = false; protoId = engine->newProtoId(); // Also internal classes need an internal class pointer. Simply make it point to itself @@ -300,10 +300,8 @@ void InternalClass::init(Heap::InternalClass *other) prototype = other->prototype; parent = other; size = other->size; - extensible = other->extensible; - isSealed = other->isSealed; - isFrozen = other->isFrozen; - isUsedAsProto = other->isUsedAsProto; + numRedundantTransitions = other->numRedundantTransitions; + flags = other->flags; protoId = engine->newProtoId(); internalClass.set(engine, other->internalClass); @@ -365,7 +363,99 @@ static void addDummyEntry(InternalClass *newClass, PropertyHash::Entry e) ++newClass->size; } -Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry) +static PropertyAttributes attributesFromFlags(int flags) +{ + PropertyAttributes attributes; + attributes.m_all = uchar(flags); + return attributes; +} + +static Heap::InternalClass *cleanInternalClass(Heap::InternalClass *orig) +{ + if (++orig->numRedundantTransitions < Heap::InternalClass::MaxRedundantTransitions) + return orig; + + // We will generally add quite a few transitions here. We have 255 redundant ones. + // We can expect at least as many significant ones in addition. + std::vector<InternalClassTransition> transitions; + + Scope scope(orig->engine); + Scoped<QV4::InternalClass> child(scope, orig); + + { + quint8 remainingRedundantTransitions = orig->numRedundantTransitions; + QSet<PropertyKey> properties; + int structureChanges = 0; + + Scoped<QV4::InternalClass> parent(scope, orig->parent); + while (parent && remainingRedundantTransitions > 0) { + Q_ASSERT(child->d() != scope.engine->classes[ExecutionEngine::Class_Empty]); + const auto it = std::find_if( + parent->d()->transitions.begin(), parent->d()->transitions.end(), + [&child](const InternalClassTransition &t) { + return child->d() == t.lookup; + }); + Q_ASSERT(it != parent->d()->transitions.end()); + + if (it->flags & InternalClassTransition::StructureChange) { + // A structural change. Each kind of structural change has to be recorded only once. + if ((structureChanges & it->flags) != it->flags) { + transitions.push_back(*it); + structureChanges |= it->flags; + } else { + --remainingRedundantTransitions; + } + } else if (!properties.contains(it->id)) { + // We only need the final state of the property. + properties.insert(it->id); + + // Property removal creates _two_ redundant transitions. + // We don't have to replay either, but numRedundantTransitions only records one. + if (it->flags != 0) + transitions.push_back(*it); + } else { + --remainingRedundantTransitions; + } + + child = parent->d(); + parent = child->d()->parent; + Q_ASSERT(child->d() != parent->d()); + } + } + + for (auto it = transitions.rbegin(); it != transitions.rend(); ++it) { + switch (it->flags) { + case InternalClassTransition::NotExtensible: + child = child->d()->nonExtensible(); + continue; + case InternalClassTransition::VTableChange: + child = child->d()->changeVTable(it->vtable); + continue; + case InternalClassTransition::PrototypeChange: + child = child->d()->changePrototype(it->prototype); + continue; + case InternalClassTransition::ProtoClass: + child = child->d()->asProtoClass(); + continue; + case InternalClassTransition::Sealed: + child = child->d()->sealed(); + continue; + case InternalClassTransition::Frozen: + child = child->d()->frozen(); + continue; + default: + Q_ASSERT(it->flags != 0); + Q_ASSERT(it->flags < InternalClassTransition::StructureChange); + child = child->addMember(it->id, attributesFromFlags(it->flags)); + continue; + } + } + + return child->d(); +} + +Heap::InternalClass *InternalClass::changeMember( + PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry) { if (!data.isEmpty()) data.resolve(); @@ -381,7 +471,7 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert } if (data == propertyData.at(idx)) - return static_cast<Heap::InternalClass *>(this); + return this; Transition temp = { { identifier }, nullptr, int(data.all()) }; Transition &t = lookupOrInsertTransition(temp); @@ -394,7 +484,8 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert Q_ASSERT(!propertyData.at(idx).isAccessor()); // add a dummy entry for the accessor - entry->setterIndex = newClass->size; + if (entry) + entry->setterIndex = newClass->size; e->setterIndex = newClass->size; addDummyEntry(newClass, *e); } @@ -403,7 +494,8 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert t.lookup = newClass; Q_ASSERT(t.lookup); - return newClass; + + return cleanInternalClass(newClass); } Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto) @@ -413,7 +505,7 @@ Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto) if (proto) proto->setUsedAsProto(); Q_ASSERT(prototype != proto); - Q_ASSERT(!proto || proto->internalClass->isUsedAsProto); + Q_ASSERT(!proto || proto->internalClass->isUsedAsProto()); Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::PrototypeChange }; temp.prototype = proto; @@ -427,8 +519,7 @@ Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto) newClass->prototype = proto; t.lookup = newClass; - - return newClass; + return prototype ? cleanInternalClass(newClass) : newClass; } Heap::InternalClass *InternalClass::changeVTableImpl(const VTable *vt) @@ -449,12 +540,14 @@ Heap::InternalClass *InternalClass::changeVTableImpl(const VTable *vt) t.lookup = newClass; Q_ASSERT(t.lookup); Q_ASSERT(newClass->vtable); - return newClass; + return vtable == QV4::InternalClass::staticVTable() + ? newClass + : cleanInternalClass(newClass); } Heap::InternalClass *InternalClass::nonExtensible() { - if (!extensible) + if (!isExtensible()) return this; Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::NotExtensible}; @@ -463,7 +556,7 @@ Heap::InternalClass *InternalClass::nonExtensible() return t.lookup; Heap::InternalClass *newClass = engine->newClass(this); - newClass->extensible = false; + newClass->flags |= NotExtensible; t.lookup = newClass; Q_ASSERT(t.lookup); @@ -500,7 +593,7 @@ Heap::InternalClass *InternalClass::addMember(PropertyKey identifier, PropertyAt Heap::InternalClass *InternalClass::addMemberImpl(PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry) { - Transition temp = { { identifier }, nullptr, (int)data.flags() }; + Transition temp = { { identifier }, nullptr, int(data.all()) }; Transition &t = lookupOrInsertTransition(temp); if (entry) { @@ -553,21 +646,23 @@ void InternalClass::removeMember(QV4::Object *object, PropertyKey identifier) changeMember(object, identifier, Attr_Invalid); #ifndef QT_NO_DEBUG - // we didn't remove the data slot, just made it inaccessible - Q_ASSERT(object->internalClass()->size == oldClass->size); + // We didn't remove the data slot, just made it inaccessible. + // ... unless we've rebuilt the whole class. Then all the deleted properties are gone. + Q_ASSERT(object->internalClass()->numRedundantTransitions == 0 + || object->internalClass()->size == oldClass->size); #endif } Heap::InternalClass *InternalClass::sealed() { - if (isSealed) + if (isSealed()) return this; Transition temp = { { PropertyKey::invalid() }, nullptr, InternalClassTransition::Sealed }; Transition &t = lookupOrInsertTransition(temp); if (t.lookup) { - Q_ASSERT(t.lookup && t.lookup->isSealed); + Q_ASSERT(t.lookup && t.lookup->isSealed()); return t.lookup; } @@ -575,7 +670,7 @@ Heap::InternalClass *InternalClass::sealed() Scoped<QV4::InternalClass> ic(scope, engine->newClass(this)); Heap::InternalClass *s = ic->d(); - if (!isFrozen) { // freezing also makes all properties non-configurable + if (!isFrozen()) { // freezing also makes all properties non-configurable for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); if (attrs.isEmpty()) @@ -584,7 +679,7 @@ Heap::InternalClass *InternalClass::sealed() s->propertyData.set(i, attrs); } } - s->isSealed = true; + s->flags |= Sealed; t.lookup = s; return s; @@ -592,14 +687,14 @@ Heap::InternalClass *InternalClass::sealed() Heap::InternalClass *InternalClass::frozen() { - if (isFrozen) + if (isFrozen()) return this; Transition temp = { { PropertyKey::invalid() }, nullptr, InternalClassTransition::Frozen }; Transition &t = lookupOrInsertTransition(temp); if (t.lookup) { - Q_ASSERT(t.lookup && t.lookup->isFrozen); + Q_ASSERT(t.lookup && t.lookup->isFrozen()); return t.lookup; } @@ -616,7 +711,7 @@ Heap::InternalClass *InternalClass::frozen() attrs.setConfigurable(false); f->propertyData.set(i, attrs); } - f->isFrozen = true; + f->flags |= Frozen; t.lookup = f; return f; @@ -640,7 +735,7 @@ InternalClass *InternalClass::cryopreserved() bool InternalClass::isImplicitlyFrozen() const { - if (isFrozen) + if (isFrozen()) return true; for (uint i = 0; i < size; ++i) { @@ -656,7 +751,7 @@ bool InternalClass::isImplicitlyFrozen() const Heap::InternalClass *InternalClass::asProtoClass() { - if (isUsedAsProto) + if (isUsedAsProto()) return this; Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::ProtoClass }; @@ -665,7 +760,7 @@ Heap::InternalClass *InternalClass::asProtoClass() return t.lookup; Heap::InternalClass *newClass = engine->newClass(this); - newClass->isUsedAsProto = true; + newClass->flags |= UsedAsProto; t.lookup = newClass; Q_ASSERT(t.lookup); @@ -685,7 +780,7 @@ static void updateProtoUsage(Heap::Object *o, Heap::InternalClass *ic) void InternalClass::updateProtoUsage(Heap::Object *o) { - Q_ASSERT(isUsedAsProto); + Q_ASSERT(isUsedAsProto()); Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_Empty); Q_ASSERT(!ic->prototype); @@ -698,6 +793,9 @@ void InternalClass::markObjects(Heap::Base *b, MarkStack *stack) if (ic->prototype) ic->prototype->mark(stack); + if (ic->parent) + ic->parent->mark(stack); + ic->nameMap.mark(stack); } diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 403702ae55..a5a1471cf1 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -172,7 +172,7 @@ struct SharedInternalClassDataPrivate<PropertyAttributes> { uint size() const { return m_size; } void setSize(uint s) { m_size = s; } - PropertyAttributes at(uint i) { Q_ASSERT(data && i < m_alloc); return data[i]; } + PropertyAttributes at(uint i) const { Q_ASSERT(data && i < m_alloc); return data[i]; } void set(uint i, PropertyAttributes t) { Q_ASSERT(data && i < m_alloc); data[i] = t; } void mark(MarkStack *) {} @@ -197,7 +197,7 @@ struct SharedInternalClassDataPrivate<PropertyKey> { uint size() const; void setSize(uint s); - PropertyKey at(uint i); + PropertyKey at(uint i) const; void set(uint i, PropertyKey t); void mark(MarkStack *s); @@ -290,24 +290,33 @@ struct InternalClassTransition int flags; enum { // range 0-0xff is reserved for attribute changes - NotExtensible = 0x100, - VTableChange = 0x200, - PrototypeChange = 0x201, - ProtoClass = 0x202, - Sealed = 0x203, - Frozen = 0x204 + StructureChange = 0x100, + NotExtensible = StructureChange | (1 << 0), + VTableChange = StructureChange | (1 << 1), + PrototypeChange = StructureChange | (1 << 2), + ProtoClass = StructureChange | (1 << 3), + Sealed = StructureChange | (1 << 4), + Frozen = StructureChange | (1 << 5), }; bool operator==(const InternalClassTransition &other) const { return id == other.id && flags == other.flags; } bool operator<(const InternalClassTransition &other) const - { return id < other.id || (id == other.id && flags < other.flags); } + { return flags < other.flags || (flags == other.flags && id < other.id); } }; namespace Heap { struct InternalClass : Base { + enum Flag { + NotExtensible = 1 << 0, + Sealed = 1 << 1, + Frozen = 1 << 2, + UsedAsProto = 1 << 3, + }; + enum { MaxRedundantTransitions = 255 }; + ExecutionEngine *engine; const VTable *vtable; quintptr protoId; // unique across the engine, gets changed whenever the proto chain changes @@ -323,10 +332,13 @@ struct InternalClass : Base { InternalClassTransition &lookupOrInsertTransition(const InternalClassTransition &t); uint size; - bool extensible; - bool isSealed; - bool isFrozen; - bool isUsedAsProto; + quint8 numRedundantTransitions; + quint8 flags; + + bool isExtensible() const { return !(flags & NotExtensible); } + bool isSealed() const { return flags & Sealed; } + bool isFrozen() const { return flags & Frozen; } + bool isUsedAsProto() const { return flags & UsedAsProto; } void init(ExecutionEngine *engine); void init(InternalClass *other); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index b723141caa..ac90a7fdb9 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -61,17 +61,52 @@ DEFINE_OBJECT_VTABLE(Object); void Object::setInternalClass(Heap::InternalClass *ic) { - d()->internalClass.set(engine(), ic); - if (ic->isUsedAsProto) - ic->updateProtoUsage(d()); Q_ASSERT(ic && ic->vtable); - uint nInline = d()->vtable()->nInlineProperties; - if (ic->size <= nInline) - return; - bool hasMD = d()->memberData != nullptr; - uint requiredSize = ic->size - nInline; - if (!(hasMD && requiredSize) || (hasMD && d()->memberData->values.size < requiredSize)) - d()->memberData.set(ic->engine, MemberData::allocate(ic->engine, requiredSize, d()->memberData)); + Heap::Object *p = d(); + + if (ic->numRedundantTransitions < p->internalClass.get()->numRedundantTransitions) { + // IC was rebuilt. The indices are different now. We need to move everything. + + Scope scope(engine()); + + // We allocate before setting the new IC. Protect it from GC. + Scoped<InternalClass> newIC(scope, ic); + + // Pick the members of the old IC that are still valid in the new IC. + // Order them by index in memberData (or inline data). + Scoped<MemberData> newMembers(scope, MemberData::allocate(scope.engine, ic->size)); + for (uint i = 0; i < ic->size; ++i) + newMembers->set(scope.engine, i, get(ic->nameMap.at(i))); + + p->internalClass.set(scope.engine, ic); + const uint nInline = p->vtable()->nInlineProperties; + + if (ic->size > nInline) + p->memberData.set(scope.engine, MemberData::allocate(ic->engine, ic->size - nInline)); + else + p->memberData.set(scope.engine, nullptr); + + const auto &memberValues = newMembers->d()->values; + for (uint i = 0; i < ic->size; ++i) + setProperty(i, memberValues[i]); + } else { + // The old indices are still the same. No need to move any values. + // We may need to re-allocate, though. + + p->internalClass.set(ic->engine, ic); + const uint nInline = p->vtable()->nInlineProperties; + if (ic->size > nInline) { + const uint requiredSize = ic->size - nInline; + if ((p->memberData ? p->memberData->values.size : 0) < requiredSize) { + p->memberData.set(ic->engine, MemberData::allocate( + ic->engine, requiredSize, p->memberData)); + } + } + } + + if (ic->isUsedAsProto()) + ic->updateProtoUsage(p); + } void Object::getProperty(const InternalClassEntry &entry, Property *p) const @@ -958,7 +993,7 @@ bool Object::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property bool Object::virtualIsExtensible(const Managed *m) { - return m->d()->internalClass->extensible; + return m->d()->internalClass->isExtensible(); } bool Object::virtualPreventExtensions(Managed *m) @@ -982,7 +1017,7 @@ bool Object::virtualSetPrototypeOf(Managed *m, const Object *proto) Heap::Object *protod = proto ? proto->d() : nullptr; if (current == protod) return true; - if (!o->internalClass()->extensible) + if (!o->internalClass()->isExtensible()) return false; Heap::Object *p = protod; while (p) { diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp index 26e1074fe3..1f518966d6 100644 --- a/src/qml/jsruntime/qv4profiling.cpp +++ b/src/qml/jsruntime/qv4profiling.cpp @@ -50,8 +50,8 @@ FunctionLocation FunctionCall::resolveLocation() const { return FunctionLocation(m_function->name()->toQString(), m_function->executableCompilationUnit()->fileName(), - m_function->compiledFunction->location.line, - m_function->compiledFunction->location.column); + m_function->compiledFunction->location.line(), + m_function->compiledFunction->location.column()); } FunctionCallProperties FunctionCall::properties() const diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h index b2a2ec3dea..81f2331666 100644 --- a/src/qml/jsruntime/qv4propertykey_p.h +++ b/src/qml/jsruntime/qv4propertykey_p.h @@ -51,6 +51,7 @@ // #include <private/qv4global_p.h> +#include <QtCore/qhashfunctions.h> QT_BEGIN_NAMESPACE @@ -145,6 +146,10 @@ public: bool operator ==(const PropertyKey &other) const { return val == other.val; } bool operator !=(const PropertyKey &other) const { return val != other.val; } bool operator <(const PropertyKey &other) const { return val < other.val; } + inline friend uint qHash(const PropertyKey &key, uint seed) noexcept + { + return QT_PREPEND_NAMESPACE(qHash)(key.val, seed); + } }; } diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index 194f7b4cf7..d7bd93aa0d 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -353,7 +353,9 @@ public: QQmlSourceLocation sourceLocation() const override final { - return QQmlSourceLocation(m_compilationUnit->fileName(), m_binding->valueLocation.line, m_binding->valueLocation.column); + return QQmlSourceLocation( + m_compilationUnit->fileName(), m_binding->valueLocation.line(), + m_binding->valueLocation.column()); } @@ -532,8 +534,8 @@ QString QQmlBinding::expressionIdentifier() const { if (auto f = function()) { QString url = f->sourceFile(); - uint lineNumber = f->compiledFunction->location.line; - uint columnNumber = f->compiledFunction->location.column; + uint lineNumber = f->compiledFunction->location.line(); + uint columnNumber = f->compiledFunction->location.column(); return url + QString::asprintf(":%u:%u", lineNumber, columnNumber); } diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index df193a0591..6e0956472f 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1436,8 +1436,10 @@ QQmlError QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(const RequiredP } error.setDescription(description); error.setUrl(unsetRequiredProperty.fileUrl); - error.setLine(qmlConvertSourceCoordinate<quint32, int>(unsetRequiredProperty.location.line)); - error.setColumn(qmlConvertSourceCoordinate<quint32, int>(unsetRequiredProperty.location.column)); + error.setLine(qmlConvertSourceCoordinate<quint32, int>( + unsetRequiredProperty.location.line())); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>( + unsetRequiredProperty.location.column())); return error; } diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index 5e6e1187e2..172557b7c2 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -102,8 +102,8 @@ void QQmlCustomParser::clearErrors() void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description) { QQmlError error; - error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line)); - error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column)); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line())); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column())); error.setDescription(description); exceptions << error; diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 826a1a5ab4..852a673ebd 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -193,7 +193,7 @@ int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject, \endcode */ -bool QQmlEnginePrivate::qml_debugging_enabled = false; +std::atomic<bool> QQmlEnginePrivate::qml_debugging_enabled{false}; bool QQmlEnginePrivate::s_designerMode = false; #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) @@ -1812,7 +1812,7 @@ void QQmlData::deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCo const QV4::CompiledData::Binding *binding = compiledObject->bindingTable(); for (quint32 i = 0; i < compiledObject->nBindings; ++i, ++binding) { const QQmlPropertyData *property = propertyData.at(i); - if (property && binding->flags & QV4::CompiledData::Binding::IsDeferredBinding) + if (property && binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding)) deferData->bindings.insert(property->coreIndex(), binding); } diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 263c69e2d8..9160fd8aa2 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -80,6 +80,8 @@ #include <private/qjsengine_p.h> #include <private/qqmldirparser_p.h> +#include <atomic> + QT_BEGIN_NAMESPACE class QQmlContext; @@ -267,7 +269,7 @@ public: static bool designerMode(); static void activateDesignerMode(); - static bool qml_debugging_enabled; + static std::atomic<bool> qml_debugging_enabled; mutable QMutex networkAccessManagerMutex; diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 10c6c41338..e7263d1850 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -46,7 +46,6 @@ #include <QtCore/qfileinfo.h> #include <QtCore/qpluginloader.h> #include <QtCore/qlibraryinfo.h> -#include <QtCore/qreadwritelock.h> #include <QtQml/qqmlextensioninterface.h> #include <QtQml/qqmlextensionplugin.h> #include <private/qqmlextensionplugin_p.h> diff --git a/src/qml/qml/qqmlirloader.cpp b/src/qml/qml/qqmlirloader.cpp index 7fa3d211a6..b6b4372faf 100644 --- a/src/qml/qml/qqmlirloader.cpp +++ b/src/qml/qml/qqmlirloader.cpp @@ -94,10 +94,11 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali object->init(pool, serializedObject->inheritedTypeNameIndex, serializedObject->idNameIndex); object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias; - object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias; - object->isInlineComponent = serializedObject->flags & QV4::CompiledData::Object::IsInlineComponentRoot; - object->flags = serializedObject->flags; - object->id = serializedObject->id; + object->defaultPropertyIsAlias = serializedObject->hasAliasAsDefaultProperty(); + object->isInlineComponent = serializedObject->hasFlag( + QV4::CompiledData::Object::IsInlineComponentRoot); + object->flags = serializedObject->flags(); + object->id = serializedObject->objectId(); object->location = serializedObject->location; object->locationOfIdProperty = serializedObject->locationOfIdProperty; @@ -108,7 +109,7 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali QmlIR::Binding *b = pool->New<QmlIR::Binding>(); *static_cast<QV4::CompiledData::Binding*>(b) = serializedObject->bindingTable()[i]; object->bindings->append(b); - if (b->type == QV4::CompiledData::Binding::Type_Script) { + if (b->type() == QV4::CompiledData::Binding::Type_Script) { functionIndices.append(b->value.compiledScriptIndex); b->value.compiledScriptIndex = functionIndices.count() - 1; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 6aeb567a86..33fbab6e6b 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -280,7 +280,7 @@ void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex, if (binding) { Q_ASSERT(qmlProperty); - Q_ASSERT(binding->flags & QV4::CompiledData::Binding::IsDeferredBinding); + Q_ASSERT(binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding)); QQmlListProperty<void> savedList; qSwap(_currentList, savedList); @@ -342,7 +342,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const int propertyType = property->propType(); if (property->isEnum()) { - if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum) { + if (binding->hasFlag(QV4::CompiledData::Binding::IsResolvedEnum)) { propertyType = QMetaType::Int; } else { // ### This should be resolved earlier at compile time and the binding value should be changed accordingly. @@ -356,18 +356,18 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const auto assertOrNull = [&](bool ok) { - Q_ASSERT(ok || binding->type == QV4::CompiledData::Binding::Type_Null); + Q_ASSERT(ok || binding->type() == QV4::CompiledData::Binding::Type_Null); Q_UNUSED(ok); }; - auto assertType = [&](QV4::CompiledData::Binding::ValueType type) + auto assertType = [&](QV4::CompiledData::Binding::Type type) { - Q_ASSERT(binding->type == type || binding->type == QV4::CompiledData::Binding::Type_Null); + Q_ASSERT(binding->type()== type || binding->type() == QV4::CompiledData::Binding::Type_Null); Q_UNUSED(type); }; if (property->isQObject()) { - if (binding->type == QV4::CompiledData::Binding::Type_Null) { + if (binding->type() == QV4::CompiledData::Binding::Type_Null) { QObject *value = nullptr; const bool ok = property->writeProperty(_qobject, &value, propertyWriteFlags); Q_ASSERT(ok); @@ -378,7 +378,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const switch (propertyType) { case QMetaType::QVariant: { - if (binding->type == QV4::CompiledData::Binding::Type_Number) { + if (binding->type() == QV4::CompiledData::Binding::Type_Number) { double n = compilationUnit->bindingValueAsNumber(binding); if (double(int(n)) == n) { if (property->isVarProperty()) { @@ -396,14 +396,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const property->writeProperty(_qobject, &value, propertyWriteFlags); } } - } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) { + } else if (binding->type() == QV4::CompiledData::Binding::Type_Boolean) { if (property->isVarProperty()) { _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::fromBoolean(binding->valueAsBoolean())); } else { QVariant value(binding->valueAsBoolean()); property->writeProperty(_qobject, &value, propertyWriteFlags); } - } else if (binding->type == QV4::CompiledData::Binding::Type_Null) { + } else if (binding->type() == QV4::CompiledData::Binding::Type_Null) { if (property->isVarProperty()) { _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::nullValue()); } else { @@ -659,18 +659,24 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const break; } else if (property->propType() == qMetaTypeId<QJSValue>()) { QJSValue value; - if (binding->type == QV4::CompiledData::Binding::Type_Boolean) { + switch (binding->type()) { + case QV4::CompiledData::Binding::Type_Boolean: value = QJSValue(binding->valueAsBoolean()); - } else if (binding->type == QV4::CompiledData::Binding::Type_Number) { - double n = compilationUnit->bindingValueAsNumber(binding); - if (double(int(n)) == n) { + break; + case QV4::CompiledData::Binding::Type_Number: { + const double n = compilationUnit->bindingValueAsNumber(binding); + if (double(int(n)) == n) value = QJSValue(int(n)); - } else + else value = QJSValue(n); - } else if (binding->type == QV4::CompiledData::Binding::Type_Null) { + break; + } + case QV4::CompiledData::Binding::Type_Null: value = QJSValue::NullValue; - } else { + break; + default: value = QJSValue(compilationUnit->bindingValueAsString(binding)); + break; } property->writeProperty(_qobject, &value, propertyWriteFlags); break; @@ -717,8 +723,8 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings) if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType() == QMetaType::QString) { QV4::CompiledData::Binding idBinding; idBinding.propertyNameIndex = 0; // Not used - idBinding.flags = 0; - idBinding.type = QV4::CompiledData::Binding::Type_String; + idBinding.clearFlags(); + idBinding.setType(QV4::CompiledData::Binding::Type_String); idBinding.stringIndex = _compiledObject->idNameIndex; idBinding.location = _compiledObject->location; // ### setPropertyValue(idProperty, &idBinding); @@ -772,10 +778,10 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings) } - if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding) + if (binding->hasFlag(QV4::CompiledData::Binding::IsCustomParserBinding)) continue; - if (binding->flags & QV4::CompiledData::Binding::IsDeferredBinding) { + if (binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding)) { if (!applyDeferredBindings) continue; } else { @@ -803,7 +809,8 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings) bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProperty, const QV4::CompiledData::Binding *binding) { - if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { + const QV4::CompiledData::Binding::Type bindingType = binding->type(); + if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) { Q_ASSERT(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty()); QV4::ResolvedTypeReference *tr = resolvedType(binding->propertyNameIndex); Q_ASSERT(tr); @@ -826,11 +833,13 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper if (bindingProperty && bindingProperty->propType() == qMetaTypeId<QQmlScriptString>()) { QQmlScriptString ss(compilationUnit->bindingValueAsScriptString(binding), context->asQQmlContext(), _scopeObject); - ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid; - ss.d.data()->lineNumber = binding->location.line; - ss.d.data()->columnNumber = binding->location.column; - ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String; - ss.d.data()->isNumberLiteral = binding->type == QV4::CompiledData::Binding::Type_Number; + ss.d.data()->bindingId = bindingType == QV4::CompiledData::Binding::Type_Script + ? binding->value.compiledScriptIndex + : (quint32)QQmlBinding::Invalid; + ss.d.data()->lineNumber = binding->location.line(); + ss.d.data()->columnNumber = binding->location.column(); + ss.d.data()->isStringLiteral = bindingType == QV4::CompiledData::Binding::Type_String; + ss.d.data()->isNumberLiteral = bindingType == QV4::CompiledData::Binding::Type_Number; ss.d.data()->numberValue = compilationUnit->bindingValueAsNumber(binding); QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | @@ -842,7 +851,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper } QObject *createdSubObject = nullptr; - if (binding->type == QV4::CompiledData::Binding::Type_Object) { + if (bindingType == QV4::CompiledData::Binding::Type_Object) { createdSubObject = createInstance(binding->value.objectIndex, _bindingTarget); if (!createdSubObject) return false; @@ -851,7 +860,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper if (!bindingProperty) // ### error return true; - if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty) { + const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags(); + if (bindingType == QV4::CompiledData::Binding::Type_GroupProperty) { const QV4::CompiledData::Object *obj = compilationUnit->objectAt(binding->value.objectIndex); if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) { @@ -892,13 +902,15 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper } } - if (_ddata->hasBindingBit(bindingProperty->coreIndex()) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) - && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment) + if (_ddata->hasBindingBit(bindingProperty->coreIndex()) + && !(bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression) + && !(bindingFlags & QV4::CompiledData::Binding::IsOnAssignment) && !_valueTypeProperty) QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex())); - if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) { - if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) { + if (bindingType == QV4::CompiledData::Binding::Type_Script + || binding->isTranslationBinding()) { + if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression) { QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; int signalIndex = _propertyCache->methodIndexToSignalIndex(bindingProperty->coreIndex()); QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine); @@ -954,8 +966,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper return true; } - if (binding->type == QV4::CompiledData::Binding::Type_Object) { - if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) { + if (bindingType == QV4::CompiledData::Binding::Type_Object) { + if (bindingFlags & QV4::CompiledData::Binding::IsOnAssignment) { // ### determine value source and interceptor casts ahead of time. QQmlType type = qmlTypeForObject(createdSubObject); Q_ASSERT(type.isValid()); @@ -1013,7 +1025,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper } // Assigning object to signal property? - if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) { + if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) { if (!bindingProperty->isFunction()) { recordError(binding->valueLocation, tr("Cannot assign an object to signal property %1").arg(bindingProperty->name(_qobject))); return false; @@ -1135,16 +1147,16 @@ void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location, { QQmlError error; error.setUrl(compilationUnit->url()); - error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line)); - error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column)); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line())); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column())); error.setDescription(description); errors << error; } void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const { - if (object->id >= 0) - context->setIdProperty(object->id, instance); + if (object->objectId() >= 0) + context->setIdProperty(object->objectId(), instance); } void QQmlObjectCreator::createQmlContext() @@ -1169,7 +1181,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo QQmlParserStatus *parserStatus = nullptr; bool installPropertyCache = true; - if (obj->flags & QV4::CompiledData::Object::IsComponent) { + if (obj->hasFlag(QV4::CompiledData::Object::IsComponent)) { isComponent = true; QQmlComponent *component = new QQmlComponent(engine, compilationUnit.data(), index, parent); typeName = QStringLiteral("<component>"); @@ -1261,13 +1273,13 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo compilationUnit.data(), obj, typeName, context->url())); Q_UNUSED(typeName); // only relevant for tracing - ddata->lineNumber = obj->location.line; - ddata->columnNumber = obj->location.column; + ddata->lineNumber = obj->location.line(); + ddata->columnNumber = obj->location.column(); ddata->setImplicitDestructible(); // inline components are root objects, but their index is != 0, so we need // an additional check - const bool isInlineComponent = obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot; + const bool isInlineComponent = obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot); if (static_cast<quint32>(index) == /*root object*/0 || ddata->rootObjectInCreation || isInlineComponent) { if (ddata->context) { Q_ASSERT(ddata->context != context); @@ -1300,7 +1312,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo if (isContextObject) context->contextObject = instance; - if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) { + if (customParser && obj->hasFlag(QV4::CompiledData::Object::HasCustomParserBindings)) { customParser->engine = QQmlEnginePrivate::get(engine); customParser->imports = compilationUnit->typeNameCache.data(); @@ -1308,9 +1320,8 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo const QV4::CompiledData::Object *obj = compilationUnit->objectAt(index); const QV4::CompiledData::Binding *binding = obj->bindingTable(); for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) { - if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding) { + if (binding->hasFlag(QV4::CompiledData::Binding::IsCustomParserBinding)) bindings << binding; - } } customParser->applyBindings(instance, compilationUnit.data(), bindings); @@ -1506,7 +1517,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * qSwap(_propertyCache, cache); qSwap(_vmeMetaObject, vmeMetaObject); - if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings) + if (_compiledObject->hasFlag(QV4::CompiledData::Object::HasDeferredBindings)) _ddata->deferData(_compiledObjectIndex, compilationUnit, context); QSet<QString> postHocRequired; @@ -1519,7 +1530,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * QQmlPropertyData *propertyData = _propertyCache->property(_propertyCache->propertyOffset() + propertyIndex); // only compute stringAt if there's a chance for the lookup to succeed auto postHocIt = postHocRequired.isEmpty() ? postHocRequired.end() : postHocRequired.find(stringAt(property->nameIndex)); - if (!property->isRequired && postHocRequired.end() == postHocIt) + if (!property->isRequired() && postHocRequired.end() == postHocIt) continue; if (postHocIt != postHocRequired.end()) postHocRequired.erase(postHocIt); @@ -1556,12 +1567,12 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * for (int aliasIndex = 0; aliasIndex != _compiledObject->aliasCount(); ++aliasIndex) { const QV4::CompiledData::Alias* alias = _compiledObject->aliasesBegin() + aliasIndex; const auto originalAlias = alias; - while (alias->aliasToLocalAlias) + while (alias->isAliasToLocalAlias()) alias = _compiledObject->aliasesBegin() + alias->localAliasIndex; - Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved); + Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved)); if (!context->idValues->wasSet()) continue; - QObject *target = context->idValues[alias->targetObjectId].data(); + QObject *target = context->idValues[alias->targetObjectId()].data(); if (!target) continue; QQmlData *targetDData = QQmlData::get(target, /*create*/false); @@ -1573,7 +1584,11 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * continue; auto it = sharedState->requiredProperties.find(targetProperty); if (it != sharedState->requiredProperties.end()) - it->aliasesToRequired.push_back(AliasToRequiredInfo {compilationUnit->stringAt(originalAlias->nameIndex), compilationUnit->finalUrl()}); + it->aliasesToRequired.push_back( + AliasToRequiredInfo { + compilationUnit->stringAt(originalAlias->nameIndex()), + compilationUnit->finalUrl() + }); } qSwap(_vmeMetaObject, vmeMetaObject); diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index d6a9e73763..db0535c292 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -187,6 +187,23 @@ namespace QQmlPrivate = QQmlPrivate::createSingletonInstance<T>; }; + // from https://en.cppreference.com/w/cpp/language/static: + // If a const non-inline (since C++17) static data member or a constexpr + // static data member (since C++11)(until C++17) is odr-used, a definition + // at namespace scope is still required, but it cannot have an initializer. + // + // If a static data member is declared constexpr, it is implicitly inline + // and does not need to be redeclared at namespace scope. This redeclaration + // without an initializer (formerly required as shown above) is still + // permitted, but is deprecated. + // + // TL;DR: redundant definitions for static constexpr are required in c++11 + // but deprecated in c++17. + template<typename T> + constexpr CreateIntoFunction Constructors<T, true>::createInto; + template<typename T> + constexpr CreateSingletonFunction Constructors<T, true>::createSingletonInstance; + template<typename T> struct Constructors<T, false> { @@ -194,6 +211,12 @@ namespace QQmlPrivate static constexpr CreateSingletonFunction createSingletonInstance = nullptr; }; + // see comment above over the Constructors<T, true> definitions. + template<typename T> + constexpr CreateIntoFunction Constructors<T, false>::createInto; + template<typename T> + constexpr CreateSingletonFunction Constructors<T, false>::createSingletonInstance; + template<typename T, bool IsVoid = std::is_void<T>::value> struct ExtendedType; @@ -205,6 +228,12 @@ namespace QQmlPrivate static constexpr const QMetaObject *staticMetaObject = nullptr; }; + // see comment above over the Constructors<T, true> definitions. + template<typename T> + constexpr const CreateParentFunction ExtendedType<T, true>::createParent; + template<typename T> + constexpr const QMetaObject* ExtendedType<T, true>::staticMetaObject; + // If it's not void, we actually want an error if the ctor or the metaobject is missing. template<typename T> struct ExtendedType<T, false> @@ -213,6 +242,12 @@ namespace QQmlPrivate static constexpr const QMetaObject *staticMetaObject = &T::staticMetaObject; }; + // see comment above over the Constructors<T, true> definitions. + template<typename T> + constexpr const CreateParentFunction ExtendedType<T, false>::createParent; + template<typename T> + constexpr const QMetaObject* ExtendedType<T, false>::staticMetaObject; + template<class From, class To, int N> struct StaticCastSelectorClass { @@ -577,6 +612,10 @@ namespace QQmlPrivate static constexpr bool Value = false; }; + // see comment above over the Constructors<T, true> definitions. + template<typename T, class C> + constexpr bool QmlSingleton<T, C>::Value; + template<class T> struct QmlSingleton<T, QmlVoidT<typename T::QmlIsSingleton>> { diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp index 88d80d88ab..1579fd3336 100644 --- a/src/qml/qml/qqmlpropertycachecreator.cpp +++ b/src/qml/qml/qqmlpropertycachecreator.cpp @@ -110,8 +110,10 @@ QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencing bool QQmlBindingInstantiationContext::resolveInstantiatingProperty() { - if (!instantiatingBinding || instantiatingBinding->type != QV4::CompiledData::Binding::Type_GroupProperty) + if (!instantiatingBinding + || instantiatingBinding->type() != QV4::CompiledData::Binding::Type_GroupProperty) { return true; + } Q_ASSERT(referencingObjectIndex >= 0); Q_ASSERT(referencingObjectPropertyCache); @@ -144,6 +146,11 @@ void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(QQmlEnginePr if (propertyCaches->at(groupPropertyObjectIndex)) continue; + if (!pendingBinding.referencingObjectPropertyCache) { + pendingBinding.referencingObjectPropertyCache + = propertyCaches->at(pendingBinding.referencingObjectIndex); + } + if (!pendingBinding.resolveInstantiatingProperty()) continue; diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h index 3fd6c8b4da..363e4d17fe 100644 --- a/src/qml/qml/qqmlpropertycachecreator_p.h +++ b/src/qml/qml/qqmlpropertycachecreator_p.h @@ -67,8 +67,8 @@ inline QQmlError qQmlCompileError(const QV4::CompiledData::Location &location, const QString &description) { QQmlError error; - error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line)); - error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column)); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line())); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column())); error.setDescription(description); return error; } @@ -196,7 +196,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects() // create meta objects for inline components before compiling actual root component for (auto nodeIt = nodesSorted.rbegin(); nodeIt != nodesSorted.rend(); ++nodeIt) { - const auto &ic = allICs[nodeIt->index]; + const auto &ic = allICs[nodeIt->index()]; QV4::ResolvedTypeReference *typeRef = objectContainer->resolvedType(ic.nameIndex); Q_ASSERT(propertyCaches->at(ic.objectIndex) == nullptr); Q_ASSERT(typeRef->typePropertyCache.isNull()); // not set yet @@ -226,7 +226,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur const CompiledObject *obj = objectContainer->objectAt(objectIndex); bool needVMEMetaObject = isVMERequired == VMEMetaObjectIsRequired::Always || obj->propertyCount() != 0 || obj->aliasCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0 || obj->enumCount() != 0 - || (((obj->flags & QV4::CompiledData::Object::IsComponent) + || ((obj->hasFlag(QV4::CompiledData::Object::IsComponent) || (objectIndex == 0 && isAddressable(objectContainer->url()))) && !objectContainer->resolvedType(obj->inheritedTypeNameIndex)->isFullyDynamicType); @@ -234,7 +234,8 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur auto binding = obj->bindingsBegin(); auto end = obj->bindingsEnd(); for ( ; binding != end; ++binding) { - if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) { + if (binding->type() == QV4::CompiledData::Binding::Type_Object + && (binding->flags() & QV4::CompiledData::Binding::IsOnAssignment)) { // If the on assignment is inside a group property, we need to distinguish between QObject based // group properties and value type group properties. For the former the base type is derived from // the property that references us, for the latter we only need a meta-object on the referencing object @@ -276,24 +277,24 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur } } - if (QQmlPropertyCache *thisCache = propertyCaches->at(objectIndex)) { - auto binding = obj->bindingsBegin(); - auto end = obj->bindingsEnd(); - for ( ; binding != end; ++binding) - if (binding->type >= QV4::CompiledData::Binding::Type_Object) { - QQmlBindingInstantiationContext context(objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache); - - // Binding to group property where we failed to look up the type of the - // property? Possibly a group property that is an alias that's not resolved yet. - // Let's attempt to resolve it after we're done with the aliases and fill in the - // propertyCaches entry then. - if (!context.resolveInstantiatingProperty()) - pendingGroupPropertyBindings->append(context); - - QQmlError error = buildMetaObjectRecursively(binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe); - if (error.isValid()) - return error; - } + QQmlPropertyCache *thisCache = propertyCaches->at(objectIndex); + auto binding = obj->bindingsBegin(); + auto end = obj->bindingsEnd(); + for ( ; binding != end; ++binding) { + if (binding->type() >= QV4::CompiledData::Binding::Type_Object) { + QQmlBindingInstantiationContext context(objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache); + + // Binding to group property where we failed to look up the type of the + // property? Possibly a group property that is an alias that's not resolved yet. + // Let's attempt to resolve it after we're done with the aliases and fill in the + // propertyCaches entry then. + if (!thisCache || !context.resolveInstantiatingProperty()) + pendingGroupPropertyBindings->append(context); + + QQmlError error = buildMetaObjectRecursively(binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe); + if (error.isValid()) + return error; + } } QQmlError noError; @@ -390,7 +391,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int auto aend = obj->aliasesEnd(); for ( ; a != aend; ++a) { bool notInRevision = false; - QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), ¬InRevision); + QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex()), ¬InRevision); if (d && d->isFinal()) return qQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property")); } @@ -438,7 +439,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int for ( ; a != aend; ++a) { auto flags = QQmlPropertyData::defaultSignalFlags(); - QString changedSigName = stringAt(a->nameIndex) + QLatin1String("Changed"); + QString changedSigName = stringAt(a->nameIndex()) + QLatin1String("Changed"); seenSignals.insert(changedSigName); cache->appendSignal(changedSigName, flags, effectiveMethodIndex++); @@ -556,12 +557,13 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int if (type == QV4::CompiledData::BuiltinType::Variant) propertyFlags.type = QQmlPropertyData::Flags::QVariantType; } else { - Q_ASSERT(!p->isBuiltinType); + Q_ASSERT(!p->isBuiltinType()); QQmlType qmltype; bool selfReference = false; - if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex), &qmltype, nullptr, nullptr, nullptr, - nullptr, QQmlType::AnyRegistrationType, &selfReference)) { + if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex()), &qmltype, + nullptr, nullptr, nullptr, nullptr, + QQmlType::AnyRegistrationType, &selfReference)) { return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type")); } @@ -592,13 +594,13 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int typeIds = compilationUnit->typeIdsForComponent(); } - if (p->isList) { + if (p->isList()) { propertyType = typeIds.listId; } else { propertyType = typeIds.id; } } else { - if (p->isList) { + if (p->isList()) { propertyType = qmltype.qListTypeId(); } else { propertyType = qmltype.typeId(); @@ -606,18 +608,17 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int } } - if (p->isList) + if (p->isList()) propertyFlags.type = QQmlPropertyData::Flags::QListType; else propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType; } - if (!p->isReadOnly && !p->isList) + if (!p->isReadOnly() && !p->isList()) propertyFlags.setIsWritable(true); - QString propertyName = stringAt(p->nameIndex); - if (!obj->defaultPropertyIsAlias && propertyIdx == obj->indexOfDefaultPropertyOrAlias) + if (!obj->hasAliasAsDefaultProperty() && propertyIdx == obj->indexOfDefaultPropertyOrAlias) cache->_defaultPropertyName = propertyName; cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, propertyType, propertTypeMinorVersion, effectiveSignalIndex); @@ -633,13 +634,14 @@ template <typename ObjectContainer> inline int QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(const QV4::CompiledData::ParameterType ¶m, QString *customTypeName) { - if (param.indexIsBuiltinType) { + if (param.indexIsBuiltinType()) { // built-in type - return metaTypeForPropertyType(static_cast<QV4::CompiledData::BuiltinType>(int(param.typeNameIndexOrBuiltinType))); + return metaTypeForPropertyType( + static_cast<QV4::CompiledData::BuiltinType>(param.typeNameIndexOrBuiltinType())); } // lazily resolved type - const QString typeName = stringAt(param.typeNameIndexOrBuiltinType); + const QString typeName = stringAt(param.typeNameIndexOrBuiltinType()); if (customTypeName) *customTypeName = typeName; QQmlType qmltype; @@ -702,7 +704,7 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertie // from a binding. for (int i = 1; i < objectContainer->objectCount(); ++i) { const CompiledObject &component = *objectContainer->objectAt(i); - if (!(component.flags & QV4::CompiledData::Object::IsComponent)) + if (!component.hasFlag(QV4::CompiledData::Object::IsComponent)) continue; const auto rootBinding = component.bindingsBegin(); @@ -725,12 +727,12 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertie auto alias = object.aliasesBegin(); auto end = object.aliasesEnd(); for ( ; alias != end; ++alias) { - Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved); + Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved)); - const int targetObjectIndex = objectForId(component, alias->targetObjectId); + const int targetObjectIndex = objectForId(component, alias->targetObjectId()); Q_ASSERT(targetObjectIndex >= 0); - if (alias->aliasToLocalAlias) + if (alias->isAliasToLocalAlias()) continue; if (alias->encodedMetaPropertyIndex == -1) @@ -772,18 +774,21 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAl objectsWithAliases->append(objectIndex); // Stop at Component boundary - if (object.flags & QV4::CompiledData::Object::IsComponent && objectIndex != /*root object*/0) + if (object.hasFlag(QV4::CompiledData::Object::IsComponent) && objectIndex != /*root object*/0) return; auto binding = object.bindingsBegin(); auto end = object.bindingsEnd(); for (; binding != end; ++binding) { - if (binding->type != QV4::CompiledData::Binding::Type_Object - && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty - && binding->type != QV4::CompiledData::Binding::Type_GroupProperty) - continue; - - collectObjectsWithAliasesRecursively(binding->value.objectIndex, objectsWithAliases); + switch (binding->type()) { + case QV4::CompiledData::Binding::Type_Object: + case QV4::CompiledData::Binding::Type_AttachedProperty: + case QV4::CompiledData::Binding::Type_GroupProperty: + collectObjectsWithAliasesRecursively(binding->value.objectIndex, objectsWithAliases); + break; + default: + break; + } } } @@ -797,12 +802,12 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor propertyFlags->setIsAlias(true); - if (alias.aliasToLocalAlias) { + if (alias.isAliasToLocalAlias()) { const QV4::CompiledData::Alias *lastAlias = &alias; QVarLengthArray<const QV4::CompiledData::Alias *, 4> seenAliases({lastAlias}); do { - const int targetObjectIndex = objectForId(component, lastAlias->targetObjectId); + const int targetObjectIndex = objectForId(component, lastAlias->targetObjectId()); Q_ASSERT(targetObjectIndex >= 0); const CompiledObject *targetObject = objectContainer->objectAt(targetObjectIndex); Q_ASSERT(targetObject); @@ -819,17 +824,17 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor seenAliases.append(targetAlias); lastAlias = targetAlias; - } while (lastAlias->aliasToLocalAlias); + } while (lastAlias->isAliasToLocalAlias()); return propertyDataForAlias(component, *lastAlias, type, minorVersion, propertyFlags, enginePriv); } - const int targetObjectIndex = objectForId(component, alias.targetObjectId); + const int targetObjectIndex = objectForId(component, alias.targetObjectId()); Q_ASSERT(targetObjectIndex >= 0); const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex); if (alias.encodedMetaPropertyIndex == -1) { - Q_ASSERT(alias.flags & QV4::CompiledData::Alias::AliasPointsToPointerObject); + Q_ASSERT(alias.hasFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject)); auto *typeRef = objectContainer->resolvedType(targetObject.inheritedTypeNameIndex); if (!typeRef) { // Can be caused by the alias target not being a valid id or property. E.g.: @@ -901,7 +906,8 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor } } - propertyFlags->setIsWritable(!(alias.flags & QV4::CompiledData::Alias::IsReadOnly) && writable); + propertyFlags->setIsWritable(!(alias.hasFlag(QV4::CompiledData::Alias::IsReadOnly)) + && writable); propertyFlags->setIsResettable(resettable); return QQmlError(); } @@ -924,7 +930,7 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesTo auto alias = object.aliasesBegin(); auto end = object.aliasesEnd(); for ( ; alias != end; ++alias, ++aliasIndex) { - Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved); + Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved)); int type = 0; int minorVersion = 0; @@ -933,9 +939,9 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesTo if (error.isValid()) return error; - const QString propertyName = objectContainer->stringAt(alias->nameIndex); + const QString propertyName = objectContainer->stringAt(alias->nameIndex()); - if (object.defaultPropertyIsAlias && aliasIndex == object.indexOfDefaultPropertyOrAlias) + if (object.hasAliasAsDefaultProperty() && aliasIndex == object.indexOfDefaultPropertyOrAlias) propertyCache->_defaultPropertyName = propertyName; propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, @@ -951,7 +957,7 @@ inline int QQmlPropertyCacheAliasCreator<ObjectContainer>::objectForId(const Com for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) { const int candidateIndex = component.namedObjectsInComponentTable()[i]; const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex); - if (candidate.id == id) + if (candidate.objectId() == id) return candidateIndex; } return -1; diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp index 3a1f33113f..ae8e6e3982 100644 --- a/src/qml/qml/qqmlpropertyvalidator.cpp +++ b/src/qml/qml/qqmlpropertyvalidator.cpp @@ -104,10 +104,11 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject( validateObject(it->objectIndex, /* instantiatingBinding*/ nullptr); } - if (obj->flags & QV4::CompiledData::Object::IsComponent && !(obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot)) { + if (obj->hasFlag(QV4::CompiledData::Object::IsComponent) + && !obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot)) { Q_ASSERT(obj->nBindings == 1); const QV4::CompiledData::Binding *componentBinding = obj->bindingTable(); - Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object); + Q_ASSERT(componentBinding->type() == QV4::CompiledData::Binding::Type_Object); return validateObject(componentBinding->value.objectIndex, componentBinding); } @@ -131,7 +132,7 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject( if (!binding->isGroupProperty()) continue; - if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) + if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) continue; if (populatingValueTypeGroupProperty) { @@ -160,9 +161,11 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject( binding = obj->bindingTable(); for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) { QString name = stringAt(binding->propertyNameIndex); + const QV4::CompiledData::Binding::Type bindingType = binding->type(); + const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags(); if (customParser) { - if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { + if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) { if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) { customBindings << binding; continue; @@ -175,13 +178,14 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject( } bool bindingToDefaultProperty = false; - bool isGroupProperty = instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty; + bool isGroupProperty = instantiatingBinding + && instantiatingBinding->type() == QV4::CompiledData::Binding::Type_GroupProperty; bool notInRevision = false; QQmlPropertyData *pd = nullptr; if (!name.isEmpty()) { - if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression - || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) { + if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression + || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) { pd = propertyResolver.signal(name, ¬InRevision); } else { pd = propertyResolver.property(name, ¬InRevision, @@ -218,11 +222,11 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject( return recordError(binding->location, tr("Invalid attached object assignment")); } - if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) { + if (binding->type() >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) { const bool populatingValueTypeGroupProperty = pd && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType()) - && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment); + && !binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment); const QVector<QQmlError> subObjectValidatorErrors = validateObject(binding->value.objectIndex, binding, populatingValueTypeGroupProperty); @@ -231,11 +235,12 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject( } // Signal handlers were resolved and checked earlier in the signal handler conversion pass. - if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression - || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) + if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerExpression) + || binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject)) { continue; + } - if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { + if (binding->type() == QV4::CompiledData::Binding::Type_AttachedProperty) { if (instantiatingBinding && (instantiatingBinding->isAttachedProperty() || instantiatingBinding->isGroupProperty())) { return recordError(binding->location, tr("Attached properties cannot be used here")); } @@ -249,15 +254,15 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject( if (!pd->isWritable() && !pd->isQList() && !binding->isGroupProperty() - && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration) + && !(bindingFlags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration) ) { - if (assigningToGroupProperty && binding->type < QV4::CompiledData::Binding::Type_Object) + if (assigningToGroupProperty && bindingType < QV4::CompiledData::Binding::Type_Object) return recordError(binding->valueLocation, tr("Cannot assign a value directly to a grouped property")); return recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name)); } - if (!pd->isQList() && (binding->flags & QV4::CompiledData::Binding::IsListItem)) { + if (!pd->isQList() && (bindingFlags & QV4::CompiledData::Binding::IsListItem)) { QString error; if (pd->propType() == qMetaTypeId<QQmlScriptString>()) error = tr( "Cannot assign multiple values to a script property"); @@ -268,7 +273,7 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject( if (!bindingToDefaultProperty && !binding->isGroupProperty() - && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment) + && !(bindingFlags & QV4::CompiledData::Binding::IsOnAssignment) && assigningToGroupProperty) { QV4::CompiledData::Location loc = binding->valueLocation; if (loc < (*assignedGroupProperty)->valueLocation) @@ -279,11 +284,11 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject( return recordError(loc, tr("Cannot assign a value directly to a grouped property")); } - if (binding->type < QV4::CompiledData::Binding::Type_Script) { + if (bindingType < QV4::CompiledData::Binding::Type_Script) { QQmlError bindingError = validateLiteralBinding(propertyCache, pd, binding); if (bindingError.isValid()) return recordError(bindingError); - } else if (binding->type == QV4::CompiledData::Binding::Type_Object) { + } else if (bindingType == QV4::CompiledData::Binding::Type_Object) { QQmlError bindingError = validateObjectBinding(pd, name, binding); if (bindingError.isValid()) return recordError(bindingError); @@ -366,7 +371,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope QQmlError noError; if (property->isEnum()) { - if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum) + if (binding->hasFlag(QV4::CompiledData::Binding::IsResolvedEnum)) return noError; QString value = compilationUnit->bindingValueAsString(binding); @@ -384,11 +389,13 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope } auto warnOrError = [&](const QString &error) { - if (binding->type == QV4::CompiledData::Binding::Type_Null) { + if (binding->type() == QV4::CompiledData::Binding::Type_Null) { QQmlError warning; warning.setUrl(compilationUnit->url()); - warning.setLine(qmlConvertSourceCoordinate<quint32, int>(binding->valueLocation.line)); - warning.setColumn(qmlConvertSourceCoordinate<quint32, int>(binding->valueLocation.column)); + warning.setLine(qmlConvertSourceCoordinate<quint32, int>( + binding->valueLocation.line())); + warning.setColumn(qmlConvertSourceCoordinate<quint32, int>( + binding->valueLocation.column())); warning.setDescription(error + tr(" - Assigning null to incompatible properties in QML " "is deprecated. This will become a compile error in " "future versions of Qt.")); @@ -398,6 +405,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope return qQmlCompileError(binding->valueLocation, error); }; + const QV4::CompiledData::Binding::Type bindingType = binding->type(); switch (property->propType()) { case QMetaType::QVariant: break; @@ -414,19 +422,17 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope } break; case QMetaType::QByteArray: { - if (binding->type != QV4::CompiledData::Binding::Type_String) { + if (bindingType != QV4::CompiledData::Binding::Type_String) return warnOrError(tr("Invalid property assignment: byte array expected")); - } } break; case QMetaType::QUrl: { - if (binding->type != QV4::CompiledData::Binding::Type_String) { + if (bindingType != QV4::CompiledData::Binding::Type_String) return warnOrError(tr("Invalid property assignment: url expected")); - } } break; case QMetaType::UInt: { - if (binding->type == QV4::CompiledData::Binding::Type_Number) { + if (bindingType == QV4::CompiledData::Binding::Type_Number) { double d = compilationUnit->bindingValueAsNumber(binding); if (double(uint(d)) == d) return noError; @@ -435,7 +441,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope } break; case QMetaType::Int: { - if (binding->type == QV4::CompiledData::Binding::Type_Number) { + if (bindingType == QV4::CompiledData::Binding::Type_Number) { double d = compilationUnit->bindingValueAsNumber(binding); if (double(int(d)) == d) return noError; @@ -444,13 +450,13 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope } break; case QMetaType::Float: { - if (binding->type != QV4::CompiledData::Binding::Type_Number) { + if (bindingType != QV4::CompiledData::Binding::Type_Number) { return warnOrError(tr("Invalid property assignment: number expected")); } } break; case QMetaType::Double: { - if (binding->type != QV4::CompiledData::Binding::Type_Number) { + if (bindingType != QV4::CompiledData::Binding::Type_Number) { return warnOrError(tr("Invalid property assignment: number expected")); } } @@ -538,7 +544,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope } break; case QMetaType::Bool: { - if (binding->type != QV4::CompiledData::Binding::Type_Boolean) { + if (bindingType != QV4::CompiledData::Binding::Type_Boolean) { return warnOrError(tr("Invalid property assignment: boolean expected")); } } @@ -594,12 +600,12 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope default: { // generate single literal value assignment to a list property if required if (property->propType() == qMetaTypeId<QList<qreal> >()) { - if (binding->type != QV4::CompiledData::Binding::Type_Number) { + if (bindingType != QV4::CompiledData::Binding::Type_Number) { return warnOrError(tr("Invalid property assignment: number or array of numbers expected")); } break; } else if (property->propType() == qMetaTypeId<QList<int> >()) { - bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number); + bool ok = (bindingType == QV4::CompiledData::Binding::Type_Number); if (ok) { double n = compilationUnit->bindingValueAsNumber(binding); if (double(int(n)) != n) @@ -609,12 +615,12 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope return warnOrError(tr("Invalid property assignment: int or array of ints expected")); break; } else if (property->propType() == qMetaTypeId<QList<bool> >()) { - if (binding->type != QV4::CompiledData::Binding::Type_Boolean) { + if (bindingType != QV4::CompiledData::Binding::Type_Boolean) { return warnOrError(tr("Invalid property assignment: bool or array of bools expected")); } break; } else if (property->propType() == qMetaTypeId<QList<QUrl> >()) { - if (binding->type != QV4::CompiledData::Binding::Type_String) { + if (bindingType != QV4::CompiledData::Binding::Type_String) { return warnOrError(tr("Invalid property assignment: url or array of urls expected")); } break; @@ -628,7 +634,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) { break; } else if (property->isQObject() - && binding->type == QV4::CompiledData::Binding::Type_Null) { + && bindingType == QV4::CompiledData::Binding::Type_Null) { break; } @@ -690,8 +696,8 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert { QQmlError noError; - if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) { - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object); + if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) { + Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Object); bool isValueSource = false; bool isPropertyInterceptor = false; @@ -740,7 +746,8 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert } } return noError; - } else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) { + } else if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject) + && property->isFunction()) { return noError; } else if (isPrimitiveType(propType)) { auto typeName = QString::fromUtf8(QMetaType::typeName(propType)); diff --git a/src/qml/qml/qqmlscriptblob.cpp b/src/qml/qml/qqmlscriptblob.cpp index dac21f7ee7..18ea5db4c6 100644 --- a/src/qml/qml/qqmlscriptblob.cpp +++ b/src/qml/qml/qqmlscriptblob.cpp @@ -168,8 +168,8 @@ void QQmlScriptBlob::done() QList<QQmlError> errors = script.script->errors(); QQmlError error; error.setUrl(url()); - error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line)); - error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column)); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line())); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column())); error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString())); errors.prepend(error); setError(errors); @@ -237,8 +237,8 @@ void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::Exe Q_ASSERT(errors.size()); QQmlError error(errors.takeFirst()); error.setUrl(m_importCache.baseUrl()); - error.setLine(import->location.line); - error.setColumn(import->location.column); + error.setLine(import->location.line()); + error.setColumn(import->location.column()); errors.prepend(error); // put it back on the list after filling out information. setError(errors); return; diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp index f1a6b3bff2..c3c80a2ac5 100644 --- a/src/qml/qml/qqmltypecompiler.cpp +++ b/src/qml/qml/qqmltypecompiler.cpp @@ -174,8 +174,8 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile() void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description) { QQmlError error; - error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line)); - error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column)); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line())); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column())); error.setDescription(description); error.setUrl(url()); errors << error; @@ -335,7 +335,8 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { QString propertyName = stringAt(binding->propertyNameIndex); // Attached property? - if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { + const QV4::CompiledData::Binding::Type bindingType = binding->type(); + if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) { const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex); auto *typeRef = resolvedType(binding->propertyNameIndex); QQmlType type = typeRef ? typeRef->type : QQmlType(); @@ -438,13 +439,13 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio } // Binding object to signal means connect the signal to the object's default method. - if (binding->type == QV4::CompiledData::Binding::Type_Object) { - binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerObject; + if (bindingType == QV4::CompiledData::Binding::Type_Object) { + binding->setFlag(QV4::CompiledData::Binding::IsSignalHandlerObject); continue; } - if (binding->type != QV4::CompiledData::Binding::Type_Script) { - if (binding->type < QV4::CompiledData::Binding::Type_Script) { + if (bindingType != QV4::CompiledData::Binding::Type_Script) { + if (bindingType < QV4::CompiledData::Binding::Type_Script) { COMPILE_EXCEPTION(binding, tr("Cannot assign a value to a signal (expecting a script to be run)")); } else { COMPILE_EXCEPTION(binding, tr("Incorrectly specified signal assignment")); @@ -489,7 +490,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio } foe->node = functionDeclaration; binding->propertyNameIndex = compiler->registerString(propertyName); - binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerExpression; + binding->setFlag(QV4::CompiledData::Binding::IsSignalHandlerExpression); } return true; } @@ -513,11 +514,13 @@ bool QQmlEnumTypeResolver::resolveEnumBindings() QQmlPropertyResolver resolver(propertyCache); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { - if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression - || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) + const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags(); + if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression + || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) { continue; + } - if (binding->type != QV4::CompiledData::Binding::Type_Script) + if (binding->type() != QV4::CompiledData::Binding::Type_Script) continue; const QString propertyName = stringAt(binding->propertyNameIndex); @@ -548,10 +551,10 @@ bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QS if (enumName.length() > 0 && enumName[0].isLower() && !isQtObject) { COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName.toString())); } - binding->type = QV4::CompiledData::Binding::Type_Number; + binding->setType(QV4::CompiledData::Binding::Type_Number); binding->value.constantValueIndex = compiler->registerConstant(QV4::Encode((double)enumValue)); // binding->setNumberValueInternal((double)enumValue); - binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum; + binding->setFlag(QV4::CompiledData::Binding::IsResolvedEnum); return true; } @@ -561,10 +564,13 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, if (!prop->isEnum() && !isIntProp) return true; - if (!prop->isWritable() && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)) - COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property").arg(stringAt(binding->propertyNameIndex))); + if (!prop->isWritable() + && !(binding->hasFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))) { + COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property") + .arg(stringAt(binding->propertyNameIndex))); + } - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script); + Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script); const QString string = compiler->bindingAsString(obj, binding->value.compiledScriptIndex); if (!string.constData()->isUpper()) return true; @@ -694,15 +700,21 @@ void QQmlCustomParserScriptIndexer::scanObjectRecursively(int objectIndex, bool if (!annotateScriptBindings) annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { - if (binding->type >= QV4::CompiledData::Binding::Type_Object) { + switch (binding->type()) { + case QV4::CompiledData::Binding::Type_Script: + if (annotateScriptBindings) { + binding->stringIndex = compiler->registerString( + compiler->bindingAsString(obj, binding->value.compiledScriptIndex)); + } + break; + case QV4::CompiledData::Binding::Type_Object: + case QV4::CompiledData::Binding::Type_AttachedProperty: + case QV4::CompiledData::Binding::Type_GroupProperty: scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings); - continue; - } else if (binding->type != QV4::CompiledData::Binding::Type_Script) - continue; - if (!annotateScriptBindings) - continue; - const QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex); - binding->stringIndex = compiler->registerString(script); + break; + default: + break; + } } } @@ -731,7 +743,7 @@ void QQmlAliasAnnotator::annotateBindingsToAliases() bool notInRevision = false; QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), ¬InRevision) : defaultProperty; if (pd && pd->isAlias()) - binding->flags |= QV4::CompiledData::Binding::IsBindingToAlias; + binding->setFlag(QV4::CompiledData::Binding::IsBindingToAlias); } } } @@ -758,7 +770,7 @@ void QQmlScriptStringScanner::scan() QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { - if (binding->type != QV4::CompiledData::Binding::Type_Script) + if (binding->type() != QV4::CompiledData::Binding::Type_Script) continue; bool notInRevision = false; QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), ¬InRevision) : defaultProperty; @@ -804,9 +816,9 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { - if (binding->type != QV4::CompiledData::Binding::Type_Object) + if (binding->type() != QV4::CompiledData::Binding::Type_Object) continue; - if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) + if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject)) continue; const QmlIR::Object *targetObject = qmlObjects->at(binding->value.objectIndex); @@ -871,7 +883,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>(); *syntheticBinding = *binding; - syntheticBinding->type = QV4::CompiledData::Binding::Type_Object; + syntheticBinding->setType(QV4::CompiledData::Binding::Type_Object); QString error = syntheticComponent->appendBinding(syntheticBinding, /*isListBinding*/false); Q_ASSERT(error.isEmpty()); Q_UNUSED(error); @@ -932,7 +944,7 @@ bool QQmlComponentAndAliasResolver::resolve() COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id")); } - if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object) + if (rootBinding->next || rootBinding->type() != QV4::CompiledData::Binding::Type_Object) COMPILE_EXCEPTION(obj, tr("Invalid component body specification")); // For the root object, we are going to collect ids/aliases and resolve them for as a separate @@ -1000,13 +1012,16 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex) return true; for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { - if (binding->type != QV4::CompiledData::Binding::Type_Object - && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty - && binding->type != QV4::CompiledData::Binding::Type_GroupProperty) - continue; - - if (!collectIdsAndAliases(binding->value.objectIndex)) - return false; + switch (binding->type()) { + case QV4::CompiledData::Binding::Type_Object: + case QV4::CompiledData::Binding::Type_AttachedProperty: + case QV4::CompiledData::Binding::Type_GroupProperty: + if (!collectIdsAndAliases(binding->value.objectIndex)) + return false; + break; + default: + break; + } } return true; @@ -1054,7 +1069,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex) if (!atLeastOneAliasResolved && !_objectsWithAliases.isEmpty()) { const QmlIR::Object *obj = qmlObjects->at(_objectsWithAliases.first()); for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) { - if (!(alias->flags & QV4::CompiledData::Alias::Resolved)) { + if (!alias->hasFlag(QV4::CompiledData::Alias::Resolved)) { recordError(alias->location, tr("Circular alias reference detected")); return false; } @@ -1076,7 +1091,7 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, bool seenUnresolvedAlias = false; for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next) { - if (alias->flags & QV4::CompiledData::Alias::Resolved) + if (alias->hasFlag(QV4::CompiledData::Alias::Resolved)) continue; seenUnresolvedAlias = true; @@ -1092,8 +1107,8 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex); Q_ASSERT(targetObject->id >= 0); - alias->targetObjectId = targetObject->id; - alias->aliasToLocalAlias = false; + alias->setTargetObjectId(targetObject->id); + alias->setIsAliasToLocalAlias(false); const QString aliasPropertyValue = stringAt(alias->propertyNameIndex); @@ -1110,7 +1125,7 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, QQmlPropertyIndex propIdx; if (property.isEmpty()) { - alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject; + alias->setFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject); } else { QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex); if (!targetCache) { @@ -1129,7 +1144,7 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, bool aliasPointsToOtherAlias = false; int localAliasIndex = 0; for (auto targetAlias = targetObject->aliasesBegin(), end = targetObject->aliasesEnd(); targetAlias != end; ++targetAlias, ++localAliasIndex) { - if (stringAt(targetAlias->nameIndex) == property) { + if (stringAt(targetAlias->nameIndex()) == property) { aliasPointsToOtherAlias = true; break; } @@ -1137,8 +1152,8 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, if (aliasPointsToOtherAlias) { if (targetObjectIndex == objectIndex) { alias->localAliasIndex = localAliasIndex; - alias->aliasToLocalAlias = true; - alias->flags |= QV4::CompiledData::Alias::Resolved; + alias->setIsAliasToLocalAlias(true); + alias->setFlag(QV4::CompiledData::Alias::Resolved); ++numResolvedAliases; continue; } @@ -1200,12 +1215,12 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, } } else { if (targetProperty->isQObject()) - alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject; + alias->setFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject); } } alias->encodedMetaPropertyIndex = propIdx.toEncoded(); - alias->flags |= QV4::CompiledData::Alias::Resolved; + alias->setFlag(QV4::CompiledData::Alias::Resolved); numResolvedAliases++; } @@ -1241,7 +1256,7 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex) if (obj->flags & QV4::CompiledData::Object::IsComponent && !obj->isInlineComponent) { Q_ASSERT(obj->bindingCount() == 1); const QV4::CompiledData::Binding *componentBinding = obj->firstBinding(); - Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object); + Q_ASSERT(componentBinding->type() == QV4::CompiledData::Binding::Type_Object); return scanObject(componentBinding->value.objectIndex); } @@ -1279,16 +1294,16 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex) QString name = stringAt(binding->propertyNameIndex); if (customParser) { - if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { + if (binding->type() == QV4::CompiledData::Binding::Type_AttachedProperty) { if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) { - binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding; + binding->setFlag(QV4::CompiledData::Binding::IsCustomParserBinding); obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings; continue; } } else if (QmlIR::IRBuilder::isSignalPropertyName(name) && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) { obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings; - binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding; + binding->setFlag(QV4::CompiledData::Binding::IsCustomParserBinding); continue; } } @@ -1307,7 +1322,8 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex) bool seenSubObjectWithId = false; - if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) { + if (binding->type() >= QV4::CompiledData::Binding::Type_Object + && (pd || binding->isAttachedProperty())) { qSwap(_seenObjectWithId, seenSubObjectWithId); const bool subObjectValid = scanObject(binding->value.objectIndex); qSwap(_seenObjectWithId, seenSubObjectWithId); @@ -1316,21 +1332,24 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex) _seenObjectWithId |= seenSubObjectWithId; } - if (!seenSubObjectWithId && binding->type != QV4::CompiledData::Binding::Type_GroupProperty + if (!seenSubObjectWithId + && binding->type() != QV4::CompiledData::Binding::Type_GroupProperty && !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) { - binding->flags |= QV4::CompiledData::Binding::IsDeferredBinding; + binding->setFlag(QV4::CompiledData::Binding::IsDeferredBinding); obj->flags |= QV4::CompiledData::Object::HasDeferredBindings; } - if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression - || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) + const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags(); + if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression + || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) { continue; + } if (!pd) { if (customParser) { obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings; - binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding; + binding->setFlag(QV4::CompiledData::Binding::IsCustomParserBinding); } } } diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp index ebd139b6a9..c7bfcc55b1 100644 --- a/src/qml/qml/qqmltypedata.cpp +++ b/src/qml/qml/qqmltypedata.cpp @@ -203,8 +203,8 @@ bool QQmlTypeData::tryLoadFromDiskCache() Q_ASSERT(errors.size()); QQmlError error(errors.takeFirst()); error.setUrl(m_importCache.baseUrl()); - error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line)); - error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column)); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line())); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column())); errors.prepend(error); // put it back on the list after filling out information. setError(errors); return false; @@ -324,8 +324,8 @@ void QQmlTypeData::done() QList<QQmlError> errors = script.script->errors(); QQmlError error; error.setUrl(url()); - error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line)); - error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column)); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line())); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column())); error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString())); errors.prepend(error); setError(errors); @@ -348,8 +348,8 @@ void QQmlTypeData::done() QList<QQmlError> errors = type.typeData ? type.typeData->errors() : QList<QQmlError>{}; QQmlError error; error.setUrl(url()); - error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line)); - error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column)); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line())); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column())); error.setDescription(QQmlTypeLoader::tr("Type %1 has no inline component type called %2").arg(typeName.leftRef(lastDot), type.type.pendingResolutionName())); errors.prepend(error); setError(errors); @@ -364,8 +364,8 @@ void QQmlTypeData::done() QList<QQmlError> errors = type.typeData->errors(); QQmlError error; error.setUrl(url()); - error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line)); - error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column)); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line())); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column())); error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName)); errors.prepend(error); setError(errors); @@ -383,8 +383,8 @@ void QQmlTypeData::done() QList<QQmlError> errors = type.typeData->errors(); QQmlError error; error.setUrl(url()); - error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line)); - error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column)); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line())); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column())); error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName)); errors.prepend(error); setError(errors); @@ -696,8 +696,8 @@ void QQmlTypeData::continueLoadFromIR() Q_ASSERT(errors.size()); QQmlError error(errors.takeFirst()); error.setUrl(m_importCache.baseUrl()); - error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line)); - error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column)); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line())); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column())); errors.prepend(error); // put it back on the list after filling out information. setError(errors); return; @@ -723,8 +723,10 @@ void QQmlTypeData::allDependenciesDone() QQmlError error; error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(import->uri)); error.setUrl(m_importCache.baseUrl()); - error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line)); - error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column)); + error.setLine(qmlConvertSourceCoordinate<quint32, int>( + import->location.line())); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>( + import->location.column())); errors.prepend(error); } } @@ -858,8 +860,8 @@ void QQmlTypeData::resolveTypes() bool *selfReferenceDetection = unresolvedRef->needsCreation ? nullptr : &ref.selfReference; - if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line, - unresolvedRef->location.column, reportErrors, + if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line(), + unresolvedRef->location.column(), reportErrors, QQmlType::AnyRegistrationType, selfReferenceDetection) && reportErrors) return; @@ -881,8 +883,7 @@ void QQmlTypeData::resolveTypes() ref.majorVersion = majorVersion; ref.minorVersion = minorVersion; - ref.location.line = unresolvedRef->location.line; - ref.location.column = unresolvedRef->location.column; + ref.location = unresolvedRef->location; ref.needsCreation = unresolvedRef->needsCreation; m_resolvedTypes.insert(unresolvedRef.key(), ref); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 1d66e756fa..01aba47a9a 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -697,8 +697,8 @@ void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob) Q_ASSERT(errors.size()); QQmlError error(errors.takeFirst()); error.setUrl(m_importCache.baseUrl()); - error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line)); - error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column)); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line())); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column())); errors.prepend(error); // put it back on the list after filling out information. setError(errors); } diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index aa9f4bc1bd..1e0e4e419f 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -231,17 +231,14 @@ void QQmlVMEMetaObjectEndpoint::tryConnect() const QV4::CompiledData::Alias *aliasData = &metaObject->compiledObject->aliasTable()[aliasId]; if (!aliasData->isObjectAlias()) { QQmlContextData *ctxt = metaObject->ctxt; - QObject *target = ctxt->idValues[aliasData->targetObjectId].data(); + QObject *target = ctxt->idValues[aliasData->targetObjectId()].data(); if (!target) return; - QQmlData *targetDData = QQmlData::get(target, /*create*/false); - if (!targetDData) - return; QQmlPropertyIndex encodedIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex); int coreIndex = encodedIndex.coreIndex(); int valueTypeIndex = encodedIndex.valueTypeIndex(); - const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex); + const QQmlPropertyData *pd = QQmlData::ensurePropertyCache(qmlEngine(target), target)->property(coreIndex); if (pd && valueTypeIndex != -1 && !QQmlValueTypeFactory::valueType(pd->propType())) { // deep alias QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(metaObject->compilationUnit->engine->qmlEngine()); @@ -758,7 +755,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * } break; case QV4::CompiledData::BuiltinType::InvalidBuiltin: - if (property.isList) { + if (property.isList()) { // when reading from the list, we need to find the correct MetaObject, // namely this. However, obejct->metaObject might point to any MetaObject // down the inheritance hierarchy, so we need to store how far we have @@ -866,7 +863,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * writeProperty(id, *reinterpret_cast<QVariant *>(a[0])); break; case QV4::CompiledData::BuiltinType::InvalidBuiltin: - if (property.isList) { + if (property.isList()) { // Writing such a property is not supported. Content is added through the list property // methods. } else { @@ -888,18 +885,20 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * if (id < aliasCount) { const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[id]; - if ((aliasData->flags & QV4::CompiledData::Alias::AliasPointsToPointerObject) && c == QMetaObject::ReadProperty) - *reinterpret_cast<void **>(a[0]) = nullptr; + if (aliasData->hasFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject) + && c == QMetaObject::ReadProperty){ + *reinterpret_cast<void **>(a[0]) = nullptr; + } if (!ctxt) return -1; - while (aliasData->aliasToLocalAlias) + while (aliasData->isAliasToLocalAlias()) aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex]; QQmlContext *context = ctxt->asQQmlContext(); QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context); - QObject *target = ctxtPriv->data->idValues[aliasData->targetObjectId].data(); + QObject *target = ctxtPriv->data->idValues[aliasData->targetObjectId()].data(); if (!target) return -1; @@ -1260,9 +1259,9 @@ bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, const int aliasId = index - propOffset() - compiledObject->nProperties; const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId]; - while (aliasData->aliasToLocalAlias) + while (aliasData->isAliasToLocalAlias()) aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex]; - *target = ctxt->idValues[aliasData->targetObjectId].data(); + *target = ctxt->idValues[aliasData->targetObjectId()].data(); if (!*target) return false; @@ -1290,7 +1289,7 @@ void QQmlVMEMetaObject::connectAlias(int aliasId) } endpoint->metaObject = this; - endpoint->connect(&ctxt->idValues[aliasData->targetObjectId].bindings); + endpoint->connect(&ctxt->idValues[aliasData->targetObjectId()].bindings); endpoint->tryConnect(); } diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 29ed62cd39..4a4e6ce12c 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -247,17 +247,20 @@ void QQmlConnectionsParser::verifyBindings(const QQmlRefPointer<QV4::ExecutableC return; } - if (binding->type >= QV4::CompiledData::Binding::Type_Object) { + if (binding->type() == QV4::CompiledData::Binding::Type_Script) + continue; + + if (binding->type() >= QV4::CompiledData::Binding::Type_Object) { const QV4::CompiledData::Object *target = compilationUnit->objectAt(binding->value.objectIndex); if (!compilationUnit->stringAt(target->inheritedTypeNameIndex).isEmpty()) error(binding, QQmlConnections::tr("Connections: nested objects not allowed")); else error(binding, QQmlConnections::tr("Connections: syntax error")); return; - } if (binding->type != QV4::CompiledData::Binding::Type_Script) { - error(binding, QQmlConnections::tr("Connections: script expected")); - return; } + + error(binding, QQmlConnections::tr("Connections: script expected")); + return; } } @@ -352,7 +355,7 @@ void QQmlConnections::connectSignalsToBindings() QQmlContextData *ctxtdata = ddata ? ddata->outerContext : nullptr; for (const QV4::CompiledData::Binding *binding : qAsConst(d->bindings)) { - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script); + Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script); QString propName = d->compilationUnit->stringAt(binding->propertyNameIndex); QQmlProperty prop(target, propName); diff --git a/src/qmlmodels/qqmllistcompositor_p.h b/src/qmlmodels/qqmllistcompositor_p.h index 6639726850..ccd565a5bd 100644 --- a/src/qmlmodels/qqmllistcompositor_p.h +++ b/src/qmlmodels/qqmllistcompositor_p.h @@ -311,6 +311,10 @@ Q_DECLARE_TYPEINFO(QQmlListCompositor::Insert, Q_PRIMITIVE_TYPE); inline QQmlListCompositor::iterator::iterator() {} +QT_WARNING_PUSH +// GCC isn't wrong, as groupCount is public in iterator, but we tried Q_ASSUME(), +// right in front of the loops, and it didn't help, so we disable the warning: +QT_WARNING_DISABLE_GCC("-Warray-bounds") inline QQmlListCompositor::iterator::iterator( Range *range, int offset, Group group, int groupCount) : range(range) @@ -338,6 +342,7 @@ inline void QQmlListCompositor::iterator::decrementIndexes(int difference, uint index[i] -= difference; } } +QT_WARNING_POP // -Warray-bounds inline QQmlListCompositor::insert_iterator::insert_iterator( Range *range, int offset, Group group, int groupCount) diff --git a/src/qmlmodels/qqmllistmodel.cpp b/src/qmlmodels/qqmllistmodel.cpp index f97bcb4f8d..c181cf15c7 100644 --- a/src/qmlmodels/qqmllistmodel.cpp +++ b/src/qmlmodels/qqmllistmodel.cpp @@ -2719,7 +2719,7 @@ void QQmlListModel::sync() bool QQmlListModelParser::verifyProperty(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding) { - if (binding->type >= QV4::CompiledData::Binding::Type_Object) { + if (binding->type() >= QV4::CompiledData::Binding::Type_Object) { const quint32 targetObjectIndex = binding->value.objectIndex; const QV4::CompiledData::Object *target = compilationUnit->objectAt(targetObjectIndex); QString objName = compilationUnit->stringAt(target->inheritedTypeNameIndex); @@ -2747,7 +2747,7 @@ bool QQmlListModelParser::verifyProperty(const QQmlRefPointer<QV4::ExecutableCom if (!verifyProperty(compilationUnit, binding)) return false; } - } else if (binding->type == QV4::CompiledData::Binding::Type_Script) { + } else if (binding->type() == QV4::CompiledData::Binding::Type_Script) { QString scriptStr = compilationUnit->bindingValueAsScriptString(binding); if (!binding->isFunctionExpression() && !definesEmptyList(scriptStr)) { QByteArray script = scriptStr.toUtf8(); @@ -2770,7 +2770,8 @@ bool QQmlListModelParser::applyProperty( const QString elementName = compilationUnit->stringAt(binding->propertyNameIndex); bool roleSet = false; - if (binding->type >= QV4::CompiledData::Binding::Type_Object) { + const QV4::CompiledData::Binding::Type bindingType = binding->type(); + if (bindingType >= QV4::CompiledData::Binding::Type_Object) { const quint32 targetObjectIndex = binding->value.objectIndex; const QV4::CompiledData::Object *target = compilationUnit->objectAt(targetObjectIndex); @@ -2803,13 +2804,13 @@ bool QQmlListModelParser::applyProperty( value = QVariant::fromValue<const QV4::CompiledData::Binding*>(binding); } else if (binding->evaluatesToString()) { value = compilationUnit->bindingValueAsString(binding); - } else if (binding->type == QV4::CompiledData::Binding::Type_Number) { + } else if (bindingType == QV4::CompiledData::Binding::Type_Number) { value = compilationUnit->bindingValueAsNumber(binding); - } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) { + } else if (bindingType == QV4::CompiledData::Binding::Type_Boolean) { value = binding->valueAsBoolean(); - } else if (binding->type == QV4::CompiledData::Binding::Type_Null) { + } else if (bindingType == QV4::CompiledData::Binding::Type_Null) { value = QVariant::fromValue(nullptr); - } else if (binding->type == QV4::CompiledData::Binding::Type_Script) { + } else if (bindingType == QV4::CompiledData::Binding::Type_Script) { QString scriptStr = compilationUnit->bindingValueAsScriptString(binding); if (definesEmptyList(scriptStr)) { const ListLayout::Role &role = model->getOrCreateListRole(elementName); @@ -2872,7 +2873,7 @@ void QQmlListModelParser::applyBindings(QObject *obj, const QQmlRefPointer<QV4:: bool setRoles = false; for (const QV4::CompiledData::Binding *binding : bindings) { - if (binding->type != QV4::CompiledData::Binding::Type_Object) + if (binding->type() != QV4::CompiledData::Binding::Type_Object) continue; setRoles |= applyProperty(compilationUnit, binding, rv->m_listModel, /*outter element index*/-1); } diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp index fa794c1ad2..c0cf3e469c 100644 --- a/src/qmltest/quicktest.cpp +++ b/src/qmltest/quicktest.cpp @@ -309,7 +309,7 @@ private: if (!object) // Start at root of compilation unit if not enumerating a specific child object = compilationUnit->objectAt(0); - if (object->flags & Object::IsInlineComponentRoot) + if (object->hasFlag(Object::IsInlineComponentRoot)) return result; if (const auto superTypeUnit = compilationUnit->resolvedTypes.value( @@ -325,13 +325,13 @@ private: // Look for override of name in this type for (auto binding = object->bindingsBegin(); binding != object->bindingsEnd(); ++binding) { if (compilationUnit->stringAt(binding->propertyNameIndex) == QLatin1String("name")) { - if (binding->type == QV4::CompiledData::Binding::Type_String) { + if (binding->type() == QV4::CompiledData::Binding::Type_String) { result.testCaseName = compilationUnit->stringAt(binding->stringIndex); } else { QQmlError error; error.setUrl(compilationUnit->url()); - error.setLine(binding->location.line); - error.setColumn(binding->location.column); + error.setLine(binding->location.line()); + error.setColumn(binding->location.column()); error.setDescription(QStringLiteral("the 'name' property of a TestCase must be a literal string")); result.errors << error; } @@ -355,7 +355,7 @@ private: } for (auto binding = object->bindingsBegin(); binding != object->bindingsEnd(); ++binding) { - if (binding->type == QV4::CompiledData::Binding::Type_Object) { + if (binding->type() == QV4::CompiledData::Binding::Type_Object) { const Object *child = compilationUnit->objectAt(binding->value.objectIndex); result << enumerateTestCases(compilationUnit, child); } diff --git a/src/qmltest/quicktestresult.cpp b/src/qmltest/quicktestresult.cpp index f3a6fea193..6a9dc335ff 100644 --- a/src/qmltest/quicktestresult.cpp +++ b/src/qmltest/quicktestresult.cpp @@ -773,7 +773,8 @@ QObject *QuickTestResult::grabImage(QQuickItem *item) if (item && item->window()) { QQuickWindow *window = item->window(); QImage grabbed = window->grabWindow(); - QRectF rf(item->x(), item->y(), item->width(), item->height()); + const auto dpi = grabbed.devicePixelRatio(); + QRectF rf(item->x() * dpi, item->y() * dpi, item->width() * dpi, item->height() * dpi); rf = rf.intersected(QRectF(0, 0, grabbed.width(), grabbed.height())); QObject *o = new QuickTestImageObject(grabbed.copy(rf.toAlignedRect())); QQmlEngine::setContextForObject(o, qmlContext(this)); diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp index 908c616d74..67700e04fa 100644 --- a/src/quick/handlers/qquickpointerhandler.cpp +++ b/src/quick/handlers/qquickpointerhandler.cpp @@ -421,6 +421,8 @@ bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObjec This handler can take the exclusive grab from another handler of the same class. \value PointerHandler.CanTakeOverFromHandlersOfDifferentType This handler can take the exclusive grab from any kind of handler. + \value PointerHandler.CanTakeOverFromItems + This handler can take the exclusive grab from any type of Item. \value PointerHandler.CanTakeOverFromAnything This handler can take the exclusive grab from any type of Item or Handler. \value PointerHandler.ApprovesTakeOverByHandlersOfSameType diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index a9f5aec7a3..ea357d819d 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -326,7 +326,7 @@ void QQuickFlickablePrivate::AxisData::updateVelocity() } } -void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) +void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeom) { Q_Q(QQuickFlickable); if (item == contentItem) { @@ -335,8 +335,14 @@ void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometr orient |= Qt::Horizontal; if (change.yChange()) orient |= Qt::Vertical; - if (orient) + if (orient) { q->viewportMoved(orient); + const QPointF deltaMoved = item->position() - oldGeom.topLeft(); + if (hData.contentPositionChangedExternallyDuringDrag) + hData.pressPos += deltaMoved.x(); + if (vData.contentPositionChangedExternallyDuringDrag) + vData.pressPos += deltaMoved.y(); + } if (orient & Qt::Horizontal) emit q->contentXChanged(); if (orient & Qt::Vertical) @@ -796,8 +802,11 @@ void QQuickFlickable::setContentX(qreal pos) d->hData.vTime = d->timeline.time(); if (isMoving() || isFlicking()) movementEnding(true, false); - if (!qFuzzyCompare(-pos, d->hData.move.value())) + if (!qFuzzyCompare(-pos, d->hData.move.value())) { + d->hData.contentPositionChangedExternallyDuringDrag = d->hData.dragging; d->hData.move.setValue(-pos); + d->hData.contentPositionChangedExternallyDuringDrag = false; + } } qreal QQuickFlickable::contentY() const @@ -814,8 +823,11 @@ void QQuickFlickable::setContentY(qreal pos) d->vData.vTime = d->timeline.time(); if (isMoving() || isFlicking()) movementEnding(false, true); - if (!qFuzzyCompare(-pos, d->vData.move.value())) + if (!qFuzzyCompare(-pos, d->vData.move.value())) { + d->vData.contentPositionChangedExternallyDuringDrag = d->vData.dragging; d->vData.move.setValue(-pos); + d->vData.contentPositionChangedExternallyDuringDrag = false; + } } /*! @@ -2108,9 +2120,11 @@ void QQuickFlickable::setContentWidth(qreal w) d->contentItem->setWidth(w); d->hData.markExtentsDirty(); // Make sure that we're entirely in view. - if (!d->pressed && !d->hData.moving && !d->vData.moving) { + if ((!d->pressed && !d->hData.moving && !d->vData.moving) || d->hData.dragging) { + d->hData.contentPositionChangedExternallyDuringDrag = d->hData.dragging; d->fixupMode = QQuickFlickablePrivate::Immediate; d->fixupX(); + d->hData.contentPositionChangedExternallyDuringDrag = false; } else if (!d->pressed && d->hData.fixingUp) { d->fixupMode = QQuickFlickablePrivate::ExtentChanged; d->fixupX(); @@ -2137,9 +2151,11 @@ void QQuickFlickable::setContentHeight(qreal h) d->contentItem->setHeight(h); d->vData.markExtentsDirty(); // Make sure that we're entirely in view. - if (!d->pressed && !d->hData.moving && !d->vData.moving) { + if ((!d->pressed && !d->hData.moving && !d->vData.moving) || d->vData.dragging) { + d->vData.contentPositionChangedExternallyDuringDrag = d->vData.dragging; d->fixupMode = QQuickFlickablePrivate::Immediate; d->fixupY(); + d->vData.contentPositionChangedExternallyDuringDrag = false; } else if (!d->pressed && d->vData.fixingUp) { d->fixupMode = QQuickFlickablePrivate::ExtentChanged; d->fixupY(); @@ -2766,6 +2782,12 @@ void QQuickFlickable::movementStarting() if (!wasMoving && (d->hData.moving || d->vData.moving)) { emit movingChanged(); emit movementStarted(); +#if QT_CONFIG(accessibility) + if (QAccessible::isActive()) { + QAccessibleEvent ev(this, QAccessible::ScrollingStart); + QAccessible::updateAccessibility(&ev); + } +#endif } } @@ -2810,6 +2832,12 @@ void QQuickFlickable::movementEnding(bool hMovementEnding, bool vMovementEnding) if (wasMoving && !isMoving()) { emit movingChanged(); emit movementEnded(); +#if QT_CONFIG(accessibility) + if (QAccessible::isActive()) { + QAccessibleEvent ev(this, QAccessible::ScrollingEnd); + QAccessible::updateAccessibility(&ev); + } +#endif } if (hMovementEnding) { diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h index 6163613493..d5d838eaea 100644 --- a/src/quick/items/qquickflickable_p_p.h +++ b/src/quick/items/qquickflickable_p_p.h @@ -109,6 +109,7 @@ public: , fixingUp(false), inOvershoot(false), inRebound(false), moving(false), flicking(false) , dragging(false), extentsChanged(false) , explicitValue(false), minExtentDirty(true), maxExtentDirty(true) + , contentPositionChangedExternallyDuringDrag(false) , unused(0) {} @@ -169,7 +170,8 @@ public: bool explicitValue : 1; mutable bool minExtentDirty : 1; mutable bool maxExtentDirty : 1; - uint unused : 19; + bool contentPositionChangedExternallyDuringDrag : 1; + uint unused : 18; }; bool flickX(qreal velocity); diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp index 867a36a362..3e2e4fc1cf 100644 --- a/src/quick/items/qquickmousearea.cpp +++ b/src/quick/items/qquickmousearea.cpp @@ -806,7 +806,8 @@ void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event) QQuickWindow *w = window(); if (w && w->mouseGrabberItem() == this) ungrabMouse(); - setKeepMouseGrab(false); + if (!d->preventStealing) + setKeepMouseGrab(false); } } d->doubleClick = false; diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp index 7573b41f67..4d420969cf 100644 --- a/src/quick/items/qquickmultipointtoucharea.cpp +++ b/src/quick/items/qquickmultipointtoucharea.cpp @@ -569,7 +569,7 @@ void QQuickMultiPointTouchArea::grabGesture() setKeepTouchGrab(true); } -void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) +void QQuickMultiPointTouchArea::updateTouchData(QEvent *event, RemapEventPoints remap) { bool ended = false; bool moved = false; @@ -578,12 +578,14 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) clearTouchLists(); QList<QTouchEvent::TouchPoint> touchPoints; QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window()); + bool touchPointsFromEvent = false; switch (event->type()) { case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: touchPoints = static_cast<QTouchEvent*>(event)->touchPoints(); + touchPointsFromEvent = true; break; case QEvent::MouseButtonPress: _mouseQpaTouchPoint = QTouchEvent::TouchPoint(windowPriv->touchMouseId); @@ -614,6 +616,8 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) qWarning("updateTouchData: unhandled event type %d", event->type()); break; } + if (!touchPointsFromEvent) + remap = RemapEventPoints::No; int numTouchPoints = touchPoints.count(); //always remove released touches, and make sure we handle all releases before adds. @@ -624,7 +628,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id)); if (!dtp) continue; - updateTouchPoint(dtp, &p); + updateTouchPoint(dtp, &p, RemapEventPoints::No); dtp->setPressed(false); _releasedTouchPoints.append(dtp); _touchPoints.remove(id); @@ -639,19 +643,19 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) //handled above } else if (!_touchPoints.contains(id)) { //could be pressed, moved, or stationary // (we may have just obtained enough points to start tracking them -- in that case moved or stationary count as newly pressed) - addTouchPoint(&p); + addTouchPoint(&p, remap); started = true; } else if ((touchPointState & Qt::TouchPointMoved) || p.d->stationaryWithModifiedProperty) { // React to a stationary point with a property change (velocity, pressure) as if the point moved. (QTBUG-77142) QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id)); Q_ASSERT(dtp); _movedTouchPoints.append(dtp); - updateTouchPoint(dtp,&p); + updateTouchPoint(dtp, &p, remap); moved = true; } else { QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id)); Q_ASSERT(dtp); - updateTouchPoint(dtp,&p); + updateTouchPoint(dtp, &p, remap); } } @@ -707,7 +711,7 @@ void QQuickMultiPointTouchArea::clearTouchLists() _movedTouchPoints.clear(); } -void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p) +void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p, RemapEventPoints remap) { QQuickTouchPoint *dtp = nullptr; for (QQuickTouchPoint* tp : qAsConst(_touchPrototypes)) { @@ -721,7 +725,7 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p) if (dtp == nullptr) dtp = new QQuickTouchPoint(false); dtp->setPointId(p->id()); - updateTouchPoint(dtp,p); + updateTouchPoint(dtp, p, remap); dtp->setPressed(true); _touchPoints.insert(p->id(),dtp); _pressedTouchPoints.append(dtp); @@ -782,12 +786,12 @@ void QQuickMultiPointTouchArea::addTouchPrototype(QQuickTouchPoint *prototype) _touchPrototypes.insert(id, prototype); } -void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp, const QTouchEvent::TouchPoint *p) +void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp, const QTouchEvent::TouchPoint *p, RemapEventPoints remap) { //TODO: if !qmlDefined, could bypass setters. // also, should only emit signals after all values have been set dtp->setUniqueId(p->uniqueId()); - dtp->setPosition(p->pos()); + dtp->setPosition(remap == RemapEventPoints::ToLocal ? mapFromScene(p->scenePos()) : p->pos()); dtp->setEllipseDiameters(p->ellipseDiameters()); dtp->setPressure(p->pressure()); dtp->setRotation(p->rotation()); @@ -975,12 +979,12 @@ bool QQuickMultiPointTouchArea::childMouseEventFilter(QQuickItem *receiver, QEve } if (!shouldFilter(event)) return false; - updateTouchData(event); + updateTouchData(event, RemapEventPoints::ToLocal); return _stealMouse; case QEvent::TouchEnd: { if (!shouldFilter(event)) return false; - updateTouchData(event); + updateTouchData(event, RemapEventPoints::ToLocal); ungrab(true); } break; diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h index e34a3faad6..85c1e2258e 100644 --- a/src/quick/items/qquickmultipointtoucharea_p.h +++ b/src/quick/items/qquickmultipointtoucharea_p.h @@ -267,14 +267,15 @@ protected: void mouseUngrabEvent() override; void touchUngrabEvent() override; + enum class RemapEventPoints { No, ToLocal }; void addTouchPrototype(QQuickTouchPoint* prototype); - void addTouchPoint(const QTouchEvent::TouchPoint *p); + void addTouchPoint(const QTouchEvent::TouchPoint *p, RemapEventPoints remap); void addTouchPoint(const QMouseEvent *e); void clearTouchLists(); - void updateTouchPoint(QQuickTouchPoint*, const QTouchEvent::TouchPoint*); + void updateTouchPoint(QQuickTouchPoint*, const QTouchEvent::TouchPoint*, RemapEventPoints remap); void updateTouchPoint(QQuickTouchPoint *dtp, const QMouseEvent *e); - void updateTouchData(QEvent*); + void updateTouchData(QEvent*, RemapEventPoints remap = RemapEventPoints::No); bool sendMouseEvent(QMouseEvent *event); bool shouldFilter(QEvent *event); diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index c135a7f272..d8fd2017e3 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -2409,21 +2409,23 @@ void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo goto geomChangeDone; if (!(widthChanged || widthMaximum) && !d->isLineLaidOutConnected()) { // only height has changed - if (newGeometry.height() > oldGeometry.height()) { - if (!d->heightExceeded && !qFuzzyIsNull(oldGeometry.height())) { - // Height is adequate and growing, and it wasn't 0 previously. - goto geomChangeDone; - } - if (d->lineCount == d->maximumLineCount()) // Reached maximum line and height is growing. - goto geomChangeDone; - } else if (newGeometry.height() < oldGeometry.height()) { - if (d->lineCount < 2 && !verticalScale && newGeometry.height() > 0) // A single line won't be truncated until the text is 0 height. - goto geomChangeDone; - - if (!verticalScale // no scaling, no eliding, and either unwrapped, or no maximum line count. - && d->elideMode != QQuickText::ElideRight - && !(d->maximumLineCountValid && d->widthExceeded)) { - goto geomChangeDone; + if (!verticalPositionChanged) { + if (newGeometry.height() > oldGeometry.height()) { + if (!d->heightExceeded && !qFuzzyIsNull(oldGeometry.height())) { + // Height is adequate and growing, and it wasn't 0 previously. + goto geomChangeDone; + } + if (d->lineCount == d->maximumLineCount()) // Reached maximum line and height is growing. + goto geomChangeDone; + } else if (newGeometry.height() < oldGeometry.height()) { + if (d->lineCount < 2 && !verticalScale && newGeometry.height() > 0) // A single line won't be truncated until the text is 0 height. + goto geomChangeDone; + + if (!verticalScale // no scaling, no eliding, and either unwrapped, or no maximum line count. + && d->elideMode != QQuickText::ElideRight + && !(d->maximumLineCountValid && d->widthExceeded)) { + goto geomChangeDone; + } } } } else if (!heightChanged && widthMaximum) { diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h index 0fffc1fb9a..698f9649dd 100644 --- a/src/quick/items/qquicktext_p.h +++ b/src/quick/items/qquicktext_p.h @@ -326,6 +326,8 @@ private: Q_DECLARE_PRIVATE(QQuickText) }; +Q_DECLARE_MIXED_ENUM_OPERATORS_SYMMETRIC(int, QQuickText::HAlignment, QQuickText::VAlignment) + class QTextLine; class QQuickTextLine : public QObject { diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h index 227d8cbf51..88ba2f9d0d 100644 --- a/src/quick/items/qquicktextedit_p.h +++ b/src/quick/items/qquicktextedit_p.h @@ -422,6 +422,8 @@ private: Q_DECLARE_PRIVATE(QQuickTextEdit) }; +Q_DECLARE_MIXED_ENUM_OPERATORS_SYMMETRIC(int, QQuickTextEdit::HAlignment, QQuickTextEdit::VAlignment) + QT_END_NAMESPACE QML_DECLARE_TYPE(QQuickTextEdit) diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index c3d013f166..9db18d1683 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -518,8 +518,16 @@ void QQuickTextInput::setSelectedTextColor(const QColor &color) } /*! - \qmlproperty enumeration QtQuick::TextInput::horizontalAlignment \qmlproperty enumeration QtQuick::TextInput::effectiveHorizontalAlignment + \readonly + + When using the attached property LayoutMirroring::enabled to mirror application + layouts, the horizontal alignment of text will also be mirrored. However, the property + \l horizontalAlignment will remain unchanged. To query the effective horizontal alignment + of TextInput, use the read-only property \c effectiveHorizontalAlignment. +*/ +/*! + \qmlproperty enumeration QtQuick::TextInput::horizontalAlignment \qmlproperty enumeration QtQuick::TextInput::verticalAlignment Sets the horizontal alignment of the text within the TextInput item's @@ -542,7 +550,7 @@ void QQuickTextInput::setSelectedTextColor(const QColor &color) When using the attached property LayoutMirroring::enabled to mirror application layouts, the horizontal alignment of text will also be mirrored. However, the property \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment - of TextInput, use the read-only property \c effectiveHorizontalAlignment. + of TextInput, use the read-only property \l effectiveHorizontalAlignment. */ QQuickTextInput::HAlignment QQuickTextInput::hAlign() const { @@ -862,6 +870,7 @@ void QQuickTextInput::setCursorPosition(int cp) /*! \qmlproperty rectangle QtQuick::TextInput::cursorRectangle + \readonly The rectangle where the standard text cursor is rendered within the text input. Read only. @@ -903,6 +912,7 @@ QRectF QQuickTextInput::cursorRectangle() const This property is read-only. To change the selection, use select(start,end), selectAll(), or selectWord(). + \readonly \sa selectionEnd, cursorPosition, selectedText */ int QQuickTextInput::selectionStart() const @@ -918,6 +928,7 @@ int QQuickTextInput::selectionStart() const This property is read-only. To change the selection, use select(start,end), selectAll(), or selectWord(). + \readonly \sa selectionStart, cursorPosition, selectedText */ int QQuickTextInput::selectionEnd() const @@ -948,6 +959,7 @@ void QQuickTextInput::select(int start, int end) /*! \qmlproperty string QtQuick::TextInput::selectedText + \readonly This read-only property provides the text currently selected in the text input. @@ -2473,6 +2485,7 @@ void QQuickTextInput::setPersistentSelection(bool on) /*! \qmlproperty bool QtQuick::TextInput::canPaste + \readonly Returns true if the TextInput is writable and the content of the clipboard is suitable for pasting into the TextInput. @@ -2494,6 +2507,7 @@ bool QQuickTextInput::canPaste() const /*! \qmlproperty bool QtQuick::TextInput::canUndo + \readonly Returns true if the TextInput is writable and there are previous operations that can be undone. @@ -2507,6 +2521,7 @@ bool QQuickTextInput::canUndo() const /*! \qmlproperty bool QtQuick::TextInput::canRedo + \readonly Returns true if the TextInput is writable and there are \l {undo}{undone} operations that can be redone. @@ -2520,6 +2535,7 @@ bool QQuickTextInput::canRedo() const /*! \qmlproperty real QtQuick::TextInput::contentWidth + \readonly Returns the width of the text, including the width past the width which is covered due to insufficient wrapping if \l wrapMode is set. @@ -2533,6 +2549,7 @@ qreal QQuickTextInput::contentWidth() const /*! \qmlproperty real QtQuick::TextInput::contentHeight + \readonly Returns the height of the text, including the height past the height that is covered if the text does not fit within the set height. @@ -2696,7 +2713,7 @@ void QQuickTextInput::focusOutEvent(QFocusEvent *event) /*! \qmlproperty bool QtQuick::TextInput::inputMethodComposing - + \readonly This property holds whether the TextInput has partial text input from an input method. diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 5e3f48584d..50b7a333c7 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -2209,6 +2209,8 @@ bool QQuickWindowPrivate::deliverSinglePointEventUntilAccepted(QQuickPointerEven itemPrivate->handlePointerEvent(event); if (point->isAccepted()) return true; + if (!item->window()) + continue; QPointF g = item->window()->mapToGlobal(point->scenePosition().toPoint()); #if QT_CONFIG(wheelevent) // Let the Item have a chance to handle it diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 79d3fca500..8f24617b24 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -1068,11 +1068,10 @@ static void qsg_wipeBuffer(Buffer *buffer, QOpenGLFunctions *funcs) free(buffer->data); } -static void qsg_wipeBatch(Batch *batch, QOpenGLFunctions *funcs, bool separateIndexBuffer) +static void qsg_wipeBatch(Batch *batch, QOpenGLFunctions *funcs) { qsg_wipeBuffer(&batch->vbo, funcs); - if (separateIndexBuffer) - qsg_wipeBuffer(&batch->ibo, funcs); + qsg_wipeBuffer(&batch->ibo, funcs); delete batch->ubuf; batch->stencilClipState.reset(); delete batch; @@ -1082,13 +1081,12 @@ Renderer::~Renderer() { if (m_rhi || QOpenGLContext::currentContext()) { // Clean up batches and buffers - const bool separateIndexBuffer = m_context->separateIndexBuffer(); for (int i = 0; i < m_opaqueBatches.size(); ++i) - qsg_wipeBatch(m_opaqueBatches.at(i), this, separateIndexBuffer); + qsg_wipeBatch(m_opaqueBatches.at(i), this); for (int i = 0; i < m_alphaBatches.size(); ++i) - qsg_wipeBatch(m_alphaBatches.at(i), this, separateIndexBuffer); + qsg_wipeBatch(m_alphaBatches.at(i), this); for (int i = 0; i < m_batchPool.size(); ++i) - qsg_wipeBatch(m_batchPool.at(i), this, separateIndexBuffer); + qsg_wipeBatch(m_batchPool.at(i), this); } for (Node *n : qAsConst(m_nodes)) @@ -1162,8 +1160,7 @@ void Renderer::map(Buffer *buffer, int byteSize, bool isIndexBuf) if (!m_context->hasBrokenIndexBufferObjects() && m_visualizer->mode() == Visualizer::VisualizeNothing) { // Common case, use a shared memory pool for uploading vertex data to avoid // excessive reevaluation - QDataBuffer<char> &pool = m_context->separateIndexBuffer() && isIndexBuf - ? m_indexUploadPool : m_vertexUploadPool; + QDataBuffer<char> &pool = isIndexBuf ? m_indexUploadPool : m_vertexUploadPool; if (byteSize > pool.size()) pool.resize(byteSize); buffer->data = pool.data(); @@ -2215,15 +2212,6 @@ void Renderer::uploadBatch(Batch *b) */ int bufferSize = b->vertexCount * g->sizeOfVertex(); int ibufferSize = 0; - // At this point, we need to check if the vertices byte size is 4 byte aligned or not. - // If an unaligned value is used in a shared buffer with indices, it causes problems with - // glDrawElements. We need to do a 4 byte alignment so that it can work with both - // QSGGeometry::UnsignedShortType and QSGGeometry::UnsignedIntType - int paddingBytes = 0; - if (!m_context->separateIndexBuffer()) { - paddingBytes = aligned(bufferSize, 4) - bufferSize; - bufferSize += paddingBytes; - } if (b->merged) { ibufferSize = b->indexCount * mergedIndexElemSize(); if (m_useDepthBuffer) @@ -2232,11 +2220,7 @@ void Renderer::uploadBatch(Batch *b) ibufferSize = unmergedIndexSize; } - const bool separateIndexBuffer = m_context->separateIndexBuffer(); - if (separateIndexBuffer) - map(&b->ibo, ibufferSize, true); - else - bufferSize += ibufferSize; + map(&b->ibo, ibufferSize, true); map(&b->vbo, bufferSize); if (Q_UNLIKELY(debug_upload())) qDebug() << " - batch" << b << " first:" << b->first << " root:" @@ -2246,9 +2230,7 @@ void Renderer::uploadBatch(Batch *b) if (b->merged) { char *vertexData = b->vbo.data; char *zData = vertexData + b->vertexCount * g->sizeOfVertex(); - char *indexData = separateIndexBuffer - ? b->ibo.data - : zData + (int(m_useDepthBuffer) * b->vertexCount * sizeof(float)) + paddingBytes; + char *indexData = b->ibo.data; quint16 iOffset16 = 0; quint32 iOffset32 = 0; @@ -2260,8 +2242,8 @@ void Renderer::uploadBatch(Batch *b) const uint verticesInSetLimit = m_uint32IndexForRhi ? 0xfffffffe : 0xfffe; int indicesInSet = 0; b->drawSets.reset(); - int drawSetIndices = separateIndexBuffer ? 0 : indexData - vertexData; - const char *indexBase = separateIndexBuffer ? b->ibo.data : b->vbo.data; + int drawSetIndices = 0; + const char *indexBase = b->ibo.data; b->drawSets << DrawSet(0, zData - vertexData, drawSetIndices); while (e) { verticesInSet += e->node->geometry()->vertexCount(); @@ -2295,8 +2277,7 @@ void Renderer::uploadBatch(Batch *b) } } else { char *vboData = b->vbo.data; - char *iboData = separateIndexBuffer ? b->ibo.data - : vboData + b->vertexCount * g->sizeOfVertex() + paddingBytes; + char *iboData = b->ibo.data; Element *e = b->first; while (e) { QSGGeometry *g = e->node->geometry(); @@ -2364,9 +2345,7 @@ void Renderer::uploadBatch(Batch *b) if (!b->drawSets.isEmpty()) { if (m_uint32IndexForRhi) { - const quint32 *id = (const quint32 *)(separateIndexBuffer - ? b->ibo.data - : b->vbo.data + b->drawSets.at(0).indices); + const quint32 *id = (const quint32 *) b->ibo.data; { QDebug iDump = qDebug(); iDump << " -- Index Data, count:" << b->indexCount; @@ -2377,9 +2356,7 @@ void Renderer::uploadBatch(Batch *b) } } } else { - const quint16 *id = (const quint16 *)(separateIndexBuffer - ? b->ibo.data - : b->vbo.data + b->drawSets.at(0).indices); + const quint16 *id = (const quint16 *) b->ibo.data; { QDebug iDump = qDebug(); iDump << " -- Index Data, count:" << b->indexCount; @@ -2400,8 +2377,7 @@ void Renderer::uploadBatch(Batch *b) #endif // QT_NO_DEBUG_OUTPUT unmap(&b->vbo); - if (separateIndexBuffer) - unmap(&b->ibo, true); + unmap(&b->ibo, true); if (Q_UNLIKELY(debug_upload())) qDebug() << " --- vertex/index buffers unmapped, batch upload completed..."; @@ -3061,7 +3037,7 @@ void Renderer::renderMergedBatch(const Batch *batch) // legacy (GL-only) glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id); char *indexBase = nullptr; - const Buffer *indexBuf = m_context->separateIndexBuffer() ? &batch->ibo : &batch->vbo; + const Buffer *indexBuf = &batch->ibo; if (m_context->hasBrokenIndexBufferObjects()) { indexBase = indexBuf->data; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); @@ -3154,8 +3130,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch) // legacy (GL-only) glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id); char *indexBase = nullptr; - const bool separateIndexBuffer = m_context->separateIndexBuffer(); - const Buffer *indexBuf = separateIndexBuffer ? &batch->ibo : &batch->vbo; + const Buffer *indexBuf = &batch->ibo; if (batch->indexCount) { if (m_context->hasBrokenIndexBufferObjects()) { indexBase = indexBuf->data; @@ -3185,15 +3160,6 @@ void Renderer::renderUnmergedBatch(const Batch *batch) // legacy (GL-only) int vOffset = 0; char *iOffset = indexBase; - // If a shared buffer is used, 4 byte alignment was done to avoid issues - // while using glDrawElements with both QSGGeometry::UnsignedShortType and - // QSGGeometry::UnsignedIntType. Here, we need to take this into account - // while calculating iOffset value to end up with the correct offset for drawing. - int vertexDataByteSize = batch->vertexCount * gn->geometry()->sizeOfVertex(); - vertexDataByteSize = aligned(vertexDataByteSize, 4); - if (!separateIndexBuffer) - iOffset += vertexDataByteSize; - QMatrix4x4 rootMatrix = batch->root ? qsg_matrixForRoot(batch->root) : QMatrix4x4(); while (e) { @@ -4363,7 +4329,7 @@ void Renderer::render() if (largestVBO * 2 < m_vertexUploadPool.size()) m_vertexUploadPool.resize(largestVBO * 2); - if (m_context->separateIndexBuffer() && largestIBO * 2 < m_indexUploadPool.size()) + if (largestIBO * 2 < m_indexUploadPool.size()) m_indexUploadPool.resize(largestIBO * 2); renderBatches(); diff --git a/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp b/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp index 9282b6c308..c7af996a30 100644 --- a/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp +++ b/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp @@ -130,7 +130,7 @@ void OpenGLVisualizer::visualizeBatch(Batch *b) if (b->merged) { shader->setUniformValue(shader->matrix, matrix); - const char *dataStart = m_renderer->m_context->separateIndexBuffer() ? b->ibo.data : b->vbo.data; + const char *dataStart = b->ibo.data; for (int ds=0; ds<b->drawSets.size(); ++ds) { const DrawSet &set = b->drawSets.at(ds); m_funcs->glVertexAttribPointer(a.position, 2, a.type, false, g->sizeOfVertex(), diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp index f912da5799..10fd2c094d 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp @@ -818,8 +818,11 @@ void QSGTextMaskMaterial::populate(const QPointF &p, QTextureGlyphCache *cache = glyphCache(); QRawFontPrivate *fontD = QRawFontPrivate::get(m_font); - cache->populate(fontD->fontEngine, glyphIndexes.size(), glyphIndexes.constData(), - fixedPointPositions.data()); + cache->populate(fontD->fontEngine, + glyphIndexes.size(), + glyphIndexes.constData(), + fixedPointPositions.data(), + true); cache->fillInPendingGlyphs(); int margin = fontD->fontEngine->glyphMargin(cache->glyphFormat()); @@ -841,7 +844,7 @@ void QSGTextMaskMaterial::populate(const QPointF &p, QPointF glyphPosition = glyphPositions.at(i) + position; QFixed subPixelPosition; if (supportsSubPixelPositions) - subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPosition.x())); + subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPosition.x() * glyphCacheScaleX)); QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition); const QTextureGlyphCache::Coord &c = cache->coords.value(glyph); diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp index bf7bb052bb..0e11a062de 100644 --- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp +++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp @@ -415,21 +415,6 @@ QSGDefaultRenderContext *QSGDefaultRenderContext::from(QOpenGLContext *context) return qobject_cast<QSGDefaultRenderContext *>(context->property(QSG_RENDERCONTEXT_PROPERTY).value<QObject *>()); } -bool QSGDefaultRenderContext::separateIndexBuffer() const -{ - if (m_rhi) - return true; - - // WebGL: A given WebGLBuffer object may only be bound to one of - // the ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER target in its - // lifetime. An attempt to bind a buffer object to the other - // target will generate an INVALID_OPERATION error, and the - // current binding will remain untouched. - static const bool isWebGL = (qGuiApp->platformName().compare(QLatin1String("webgl")) == 0 - || qGuiApp->platformName().compare(QLatin1String("wasm")) == 0); - return isWebGL; -} - void QSGDefaultRenderContext::preprocess() { for (auto it = m_glyphCaches.begin(); it != m_glyphCaches.end(); ++it) { diff --git a/src/quick/scenegraph/qsgdefaultrendercontext_p.h b/src/quick/scenegraph/qsgdefaultrendercontext_p.h index e90a11eda6..6da67264d1 100644 --- a/src/quick/scenegraph/qsgdefaultrendercontext_p.h +++ b/src/quick/scenegraph/qsgdefaultrendercontext_p.h @@ -140,7 +140,6 @@ public: bool hasBrokenIndexBufferObjects() const { return m_brokenIBOs; } int maxTextureSize() const override { return m_maxTextureSize; } - bool separateIndexBuffer() const; int msaaSampleCount() const { return m_initParams.sampleCount; } diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp index 1cb30f5a8d..7a47f132fe 100644 --- a/src/quick/util/qquickpropertychanges.cpp +++ b/src/quick/util/qquickpropertychanges.cpp @@ -239,18 +239,22 @@ public: void QQuickPropertyChangesParser::verifyList(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding) { - if (binding->type == QV4::CompiledData::Binding::Type_Object) { - error(compilationUnit->objectAt(binding->value.objectIndex), QQuickPropertyChanges::tr("PropertyChanges does not support creating state-specific objects.")); - return; - } - - if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty - || binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { + switch (binding->type()) { + case QV4::CompiledData::Binding::Type_Object: + error(compilationUnit->objectAt(binding->value.objectIndex), + QQuickPropertyChanges::tr( + "PropertyChanges does not support creating state-specific objects.")); + break; + case QV4::CompiledData::Binding::Type_GroupProperty: + case QV4::CompiledData::Binding::Type_AttachedProperty: { const QV4::CompiledData::Object *subObj = compilationUnit->objectAt(binding->value.objectIndex); const QV4::CompiledData::Binding *subBinding = subObj->bindingTable(); - for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding) { + for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding) verifyList(compilationUnit, subBinding); - } + break; + } + default: + break; } } @@ -273,8 +277,9 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, QString propertyName = propertyPrefix + compilationUnit->stringAt(binding->propertyNameIndex); - if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty - || binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { + switch (binding->type()) { + case QV4::CompiledData::Binding::Type_GroupProperty: + case QV4::CompiledData::Binding::Type_AttachedProperty: { QString pre = propertyName + QLatin1Char('.'); const QV4::CompiledData::Object *subObj = compilationUnit->objectAt(binding->value.objectIndex); const QV4::CompiledData::Binding *subBinding = subObj->bindingTable(); @@ -283,6 +288,9 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, } return; } + default: + break; + } if (propertyName.count() >= 3 && propertyName.at(0) == QLatin1Char('o') && @@ -299,7 +307,8 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, } } - if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) { + if (binding->type() == QV4::CompiledData::Binding::Type_Script + || binding->isTranslationBinding()) { QUrl url = QUrl(); int line = -1; int column = -1; @@ -323,7 +332,7 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, } QVariant var; - switch (binding->type) { + switch (binding->type()) { case QV4::CompiledData::Binding::Type_Script: case QV4::CompiledData::Binding::Type_Translation: case QV4::CompiledData::Binding::Type_TranslationById: diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index 39780f8de3..cf021d9a7c 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -978,11 +978,14 @@ void QQuickWidget::createFramebufferObject() } QOpenGLContext *shareWindowContext = QWidgetPrivate::get(window())->shareContext(); + bool nativeContextGotRecreated = false; if (shareWindowContext && context->shareContext() != shareWindowContext && !qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)) { + d->invalidateRenderControl(); context->setShareContext(shareWindowContext); context->setScreen(shareWindowContext->screen()); if (!context->create()) qWarning("QQuickWidget: Failed to recreate context"); + nativeContextGotRecreated = true; // The screen may be different so we must recreate the offscreen surface too. // Unlike QOpenGLContext, QOffscreenSurface's create() does not recreate so have to destroy() first. d->offscreenSurface->destroy(); @@ -1042,6 +1045,10 @@ void QQuickWidget::createFramebufferObject() // Having one would mean create() was called and platforms that only support // a single native window were in trouble. Q_ASSERT(!d->offscreenWindow->handle()); + + // do this at the end it may trigger a recursive call + if (nativeContextGotRecreated) + d->renderControl->initialize(context); #endif } |