diff options
Diffstat (limited to 'src/qml')
24 files changed, 204 insertions, 67 deletions
diff --git a/src/qml/doc/snippets/qml/qsTrId.1.qml b/src/qml/doc/snippets/qml/qsTrId.1.qml index 4989adad25..6776620c77 100644 --- a/src/qml/doc/snippets/qml/qsTrId.1.qml +++ b/src/qml/doc/snippets/qml/qsTrId.1.qml @@ -3,9 +3,18 @@ import QtQuick +Item { //![0] -Text { - //% "hello" - text: qsTrId("hello_id") -} + Text { + //% "hello" + text: qsTrId("hello_id") + } //![0] + +//![1] + Text { + /*% "hello" */ + text: qsTrId("hello_id") + } +//![1] +} diff --git a/src/qml/doc/src/cmake/qt_add_qml_module.qdoc b/src/qml/doc/src/cmake/qt_add_qml_module.qdoc index 79c3cd8082..353505c78f 100644 --- a/src/qml/doc/src/cmake/qt_add_qml_module.qdoc +++ b/src/qml/doc/src/cmake/qt_add_qml_module.qdoc @@ -520,8 +520,8 @@ class MyItem: public QQuickItem { ... }; \endcode then one has to make sure that the module containing \c QQuickItem, called -\c Quick, is declared as a dependency via the \c DEPENDENCIES option. Not doing -so might result in errors during type compilation with +\c QtQuick, is declared as a dependency via the \c DEPENDENCIES option. Not +doing so might result in errors during type compilation with \l{QML type compiler}{qmltc} or during binding and function compilation to C++ with \l{qmlcachegen-auto}{qmlcachegen}. diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 99fad7e3c3..a807cc42df 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -105,7 +105,8 @@ using namespace QV4; // odd while the statics are being initialized, and stays even afterwards. // Any further engines created while the statics are being initialized busy-wait until engineSerial // is even. -static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1); +Q_CONSTINIT static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1); +Q_CONSTINIT static QBasicAtomicInt hasPreview = Q_BASIC_ATOMIC_INITIALIZER(0); int ExecutionEngine::s_maxCallDepth = -1; int ExecutionEngine::s_jitCallCountThreshold = 3; int ExecutionEngine::s_maxJSStackSize = 4 * 1024 * 1024; @@ -889,6 +890,12 @@ void ExecutionEngine::setProfiler(Profiling::Profiler *profiler) Q_ASSERT(!m_profiler); m_profiler.reset(profiler); } + +void ExecutionEngine::setPreviewing(bool enabled) +{ + hasPreview.storeRelease(enabled); +} + #endif // QT_CONFIG(qml_debug) void ExecutionEngine::initRootContext() @@ -2212,7 +2219,7 @@ QV4::Value *ExecutionEngine::registerNativeModule(const QUrl &url, const QV4::Va bool ExecutionEngine::diskCacheEnabled() const { - return (!disableDiskCache() && !debugger()) || forceDiskCache(); + return (!disableDiskCache() && !debugger() && !hasPreview.loadAcquire()) || forceDiskCache(); } void ExecutionEngine::callInContext(QV4::Function *function, QObject *self, diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 75c8efd67e..99b9e526f6 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -514,12 +514,14 @@ public: void setDebugger(Debugging::Debugger *) {} void setProfiler(Profiling::Profiler *) {} + static void setPreviewing(bool) {} #else QV4::Debugging::Debugger *debugger() const { return m_debugger.data(); } QV4::Profiling::Profiler *profiler() const { return m_profiler.data(); } void setDebugger(Debugging::Debugger *debugger); void setProfiler(Profiling::Profiler *profiler); + static void setPreviewing(bool enabled); #endif // QT_CONFIG(qml_debug) ExecutionContext *currentContext() const { return currentStackFrame->context(); } diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index 90eb326d65..eac2aca059 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -94,6 +94,8 @@ void Heap::ForInIteratorObject::markObjects(Heap::Base *that, MarkStack *markSta o->object->mark(markStack); if (o->current) o->current->mark(markStack); + if (o->target) + o->target->mark(markStack); o->workArea[0].mark(markStack); o->workArea[1].mark(markStack); Object::markObjects(that, markStack); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 50389e06ec..ecd947ccc3 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -1021,6 +1021,16 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E ReturnedValue QObjectWrapper::lookupAttached( Lookup *l, ExecutionEngine *engine, const Value &object) { + if (&QObjectWrapper::lookupAttached == &Lookup::getterGeneric) { + // Certain compilers, e.g. MSVC, will "helpfully" deduplicate methods that are completely + // equal. As a result, the pointers are the same, which wreaks havoc on the logic that + // decides how to retrieve the property. + qFatal("Your C++ compiler is broken."); + } + + // This getter marks the presence of a lookup for an attached object. + // It falls back to the generic lookup when run through the interpreter, but AOT-compiled + // code can get clever with it. return Lookup::getterGeneric(l, engine, object); } diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 98bb6347d3..2613cff99a 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -777,7 +777,7 @@ ReturnedValue StringPrototype::method_replace(const FunctionObject *b, const Val nMatchOffsets += re->captureCount() * 2; if (!regExp->global()) break; - offset = qMax(offset + 1, matchOffsets[oldSize + 1]); + offset = qMax(offset, matchOffsets[oldSize + 1]) + 1; } if (regExp->global()) { regExp->setLastIndex(0); diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp index d91dfb95db..7ffdffad7b 100644 --- a/src/qml/qml/ftw/qqmlthread.cpp +++ b/src/qml/qml/ftw/qqmlthread.cpp @@ -195,6 +195,9 @@ void QQmlThread::shutdown() d->m_shutdown = true; + if (d->mainSync) + d->wakeOne(); + if (QCoreApplication::closingDown()) d->quit(); else diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index 94a91629f3..44e8955b7a 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -1602,7 +1602,13 @@ static void initTypeWrapperLookup( QV4::Scoped<QV4::QQmlTypeWrapper> wrapper( scope, QV4::QQmlTypeWrapper::create( scope.engine, nullptr, context->qmlContext->imports(), importRef)); - wrapper = l->qmlContextPropertyGetter(l, context->engine->handle(), wrapper); + + // This is not a contextGetter since we actually load from the namespace. + wrapper = l->getter(l, context->engine->handle(), wrapper); + + // In theory, the getter may have populated the lookup's property cache. + l->releasePropertyCache(); + l->qmlContextPropertyGetter = qmlContextPropertyGetter; if (qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupSingleton) l->qmlContextSingletonLookup.singletonObject = wrapper->heapObject(); diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 0650cee167..73e8a09601 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -630,6 +630,11 @@ QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true) // super types should be registered as CppType (or not at all). We only need the object and its // QML engine to resolve composite types. Therefore, the function is actually a static property // of the C++ type system and we can cache it here for improved performance on further lookups. + if (const auto func = QQmlPrivate::attachedPropertiesFunc<T>()) + return qmlAttachedPropertiesObject(const_cast<QObject *>(obj), func, create); + + // Usually the above func should not be nullptr. However, to be safe, keep this fallback + // via the metaobject. static const auto func = qmlAttachedPropertiesFunction(nullptr, &T::staticMetaObject); return qmlAttachedPropertiesObject(const_cast<QObject *>(obj), func, create); } diff --git a/src/qml/qml/qqmlbuiltinfunctions.cpp b/src/qml/qml/qqmlbuiltinfunctions.cpp index fdc28d727d..0251a72049 100644 --- a/src/qml/qml/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/qqmlbuiltinfunctions.cpp @@ -2307,12 +2307,13 @@ ReturnedValue GlobalExtensions::method_qsTrNoOp(const FunctionObject *, const Va \tt{//% <string>} + \snippet qml/qsTrId.1.qml 0 + or - \tt{\\begincomment% <string> \\endcomment} + \tt{\begincomment% <string> \endcomment} - Example: - \snippet qml/qsTrId.1.qml 0 + \snippet qml/qsTrId.1.qml 1 Creating binary translation (QM) files suitable for use with this function requires passing the \c -idbased option to the \c lrelease tool. diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 5a6fd4c8d3..7b2107b858 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -455,6 +455,10 @@ QQmlComponent::~QQmlComponent() if (d->typeData) { d->typeData->unregisterCallback(d); + if (d->engine) { + QQmlEnginePrivate::get(d->engine)->typeLoader.drop( + QQmlDataBlob::Ptr(d->typeData.data())); + } d->typeData.reset(); } } @@ -1013,6 +1017,14 @@ QObject *QQmlComponent::beginCreate(QQmlContext *context) return d->beginCreate(QQmlContextData::get(context)); } +static QQmlParserStatus *parserStatusCast(const QQmlType &type, QObject *rv) +{ + const int parserStatusCast = type.parserStatusCast(); + return parserStatusCast == -1 + ? nullptr + : reinterpret_cast<QQmlParserStatus *>(reinterpret_cast<char *>(rv) + parserStatusCast); +} + QObject *QQmlComponentPrivate::beginCreate(QQmlRefPointer<QQmlContextData> context) { Q_Q(QQmlComponent); @@ -1074,7 +1086,7 @@ QObject *QQmlComponentPrivate::beginCreate(QQmlRefPointer<QQmlContextData> conte if (!loadedType.isValid()) { enginePriv->referenceScarceResources(); - state.initCreator(std::move(context), compilationUnit, creationContext); + state.initCreator(context, compilationUnit, creationContext); rv = state.creator()->create(start, nullptr, nullptr, isInlineComponent ? QQmlObjectCreator::InlineComponent : QQmlObjectCreator::NormalObject); if (!rv) state.appendCreatorErrors(); @@ -1083,26 +1095,21 @@ QObject *QQmlComponentPrivate::beginCreate(QQmlRefPointer<QQmlContextData> conte // TODO: extract into function rv = loadedType.createWithQQmlData(); QQmlPropertyCache::ConstPtr propertyCache = QQmlData::ensurePropertyCache(rv); - QQmlParserStatus *parserStatus = nullptr; - const int parserStatusCast = loadedType.parserStatusCast(); - if (parserStatusCast != -1) { - parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(rv) + parserStatusCast); + if (QQmlParserStatus *parserStatus = parserStatusCast(loadedType, rv)) { parserStatus->classBegin(); + state.ensureRequiredPropertyStorage(rv); + } else if (loadedType.finalizerCast() != -1) { + state.ensureRequiredPropertyStorage(rv); } + for (int i = 0, propertyCount = propertyCache->propertyCount(); i < propertyCount; ++i) { if (const QQmlPropertyData *propertyData = propertyCache->property(i); propertyData->isRequired()) { - state.ensureRequiredPropertyStorage(); + state.ensureRequiredPropertyStorage(rv); RequiredPropertyInfo info; info.propertyName = propertyData->name(rv); state.addPendingRequiredProperty(rv, propertyData, info); } } - if (parserStatus) - parserStatus->componentComplete(); - if (const int finalizerCast = loadedType.finalizerCast(); finalizerCast != -1) { - auto* hook = reinterpret_cast<QQmlFinalizerHook *>(reinterpret_cast<char *>(rv) + finalizerCast); - hook->componentFinalized(); - } } if (rv) { @@ -1113,6 +1120,12 @@ QObject *QQmlComponentPrivate::beginCreate(QQmlRefPointer<QQmlContextData> conte ddata->indestructible = true; ddata->explicitIndestructibleSet = true; ddata->rootObjectInCreation = false; + + // Assign parent context to the object if we haven't created one. + if (!ddata->outerContext) + ddata->outerContext = context.data(); + if (!ddata->context) + ddata->context = context.data(); } return rv; @@ -1249,7 +1262,18 @@ void QQmlComponentPrivate::completeCreate() state.errors.push_back(QQmlComponentPrivate::AnnotatedQmlError { error, true }); } } + if (loadedType.isValid()) { + QObject *rv = state.target(); + if (QQmlParserStatus *parserStatus = parserStatusCast(loadedType, rv)) + parserStatus->componentComplete(); + + if (const int finalizerCast = loadedType.finalizerCast(); finalizerCast != -1) { + auto *hook = reinterpret_cast<QQmlFinalizerHook *>( + reinterpret_cast<char *>(rv) + finalizerCast); + hook->componentFinalized(); + } + /* We can directly set completePending to false, as finalize is only concerned with setting up pending bindings, but that cannot happen here, as we're diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index df6ccc58ca..35e4a3b219 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -111,7 +111,7 @@ public: QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QQmlComponentPrivate::ConstructionState); - inline void ensureRequiredPropertyStorage(); + inline void ensureRequiredPropertyStorage(QObject *target); inline RequiredProperties *requiredProperties(); inline void addPendingRequiredProperty( const QObject *object, const QQmlPropertyData *propData, @@ -126,16 +126,31 @@ public: inline const QQmlObjectCreator *creator() const; inline void clear(); inline bool hasCreator() const; - inline QQmlObjectCreator *initCreator(QQmlRefPointer<QQmlContextData> parentContext, - const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, - const QQmlRefPointer<QQmlContextData> &creationContext); + inline QQmlObjectCreator *initCreator( + const QQmlRefPointer<QQmlContextData> &parentContext, + const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, + const QQmlRefPointer<QQmlContextData> &creationContext); QList<AnnotatedQmlError> errors; inline bool isCompletePending() const; inline void setCompletePending(bool isPending); - private: - QBiPointer<QQmlObjectCreator, RequiredProperties> m_creatorOrRequiredProperties; + QObject *target() const + { + if (m_creatorOrRequiredProperties.isNull()) + return nullptr; + + if (m_creatorOrRequiredProperties.isT1()) { + const auto &objects = m_creatorOrRequiredProperties.asT1()->allCreatedObjects(); + return objects.isEmpty() ? nullptr : objects.at(0); + } + + Q_ASSERT(m_creatorOrRequiredProperties.isT2()); + return m_creatorOrRequiredProperties.asT2()->target; + } + + private: + QBiPointer<QQmlObjectCreator, RequiredPropertiesAndTarget> m_creatorOrRequiredProperties; }; ConstructionState state; @@ -267,15 +282,17 @@ inline void QQmlComponentPrivate::ConstructionState::clear() } } -inline QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::initCreator(QQmlRefPointer<QQmlContextData> parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QQmlRefPointer<QQmlContextData> &creationContext) +inline QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::initCreator( + const QQmlRefPointer<QQmlContextData> &parentContext, + const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, + const QQmlRefPointer<QQmlContextData> &creationContext) { if (m_creatorOrRequiredProperties.isT1()) delete m_creatorOrRequiredProperties.asT1(); else delete m_creatorOrRequiredProperties.asT2(); m_creatorOrRequiredProperties = new QQmlObjectCreator( - std::move(parentContext), compilationUnit, - creationContext); + parentContext, compilationUnit, creationContext); return m_creatorOrRequiredProperties.asT1(); } @@ -293,13 +310,15 @@ inline void QQmlComponentPrivate::ConstructionState::setCompletePending(bool isP \internal This is meant to be used in the context of QQmlComponent::loadFromModule, when dealing with a C++ type. In that case, we do not have a creator, - and need a separate storage for required properties. + and need a separate storage for required properties and the target object. */ -inline void QQmlComponentPrivate::ConstructionState::ensureRequiredPropertyStorage() +inline void QQmlComponentPrivate::ConstructionState::ensureRequiredPropertyStorage(QObject *target) { Q_ASSERT(m_creatorOrRequiredProperties.isT2() || m_creatorOrRequiredProperties.isNull()); if (m_creatorOrRequiredProperties.isNull()) - m_creatorOrRequiredProperties = new RequiredProperties; + m_creatorOrRequiredProperties = new RequiredPropertiesAndTarget(target); + else + m_creatorOrRequiredProperties.asT2()->target = target; } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index d3f43cb8c4..d68e778ce2 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -132,7 +132,7 @@ int QQmlCustomParser::evaluateEnum(const QString &script, bool *ok) const // Allow recursion so that we can find enums from the same document. const QQmlTypeNameCache::Result result = imports.asT2()->query<QQmlImport::AllowRecursion>(scope); - if (result.isValid()) { + if (result.type.isValid()) { type = result.type; } else if (result.importNamespace) { dot = nextDot(dot); diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index ae1bd87035..fe8ae5295c 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -297,6 +297,18 @@ public: void addPluginPath(const QString& path); + static void sanitizeUNCPath(QString *path) + { + // This handles the UNC path case as when the path is retrieved from the QUrl it + // will convert the host name from upper case to lower case. So the absoluteFilePath + // is changed at this point to make sure it will match later on in that case. + if (path->startsWith(QStringLiteral("//"))) { + // toLocalFile() since that faithfully restores all the things you can do to a + // path but not a URL, in particular weird characters like '%'. + *path = QUrl::fromLocalFile(*path).toLocalFile(); + } + } + template<typename Callback> LocalQmldirResult locateLocalQmldir( const QString &uri, QTypeRevision version, LocalQmldirSearchLocation location, @@ -397,13 +409,7 @@ QQmlImportDatabase::LocalQmldirResult QQmlImportDatabase::locateLocalQmldir( url = QStringLiteral("qrc") + absolutePath; } else { url = QUrl::fromLocalFile(absolutePath).toString(); - // This handles the UNC path case as when the path is retrieved from the QUrl it - // will convert the host name from upper case to lower case. So the absoluteFilePath - // is changed at this point to make sure it will match later on in that case. - if (qmldirAbsoluteFilePath.startsWith(QStringLiteral("//"))) { - qmldirAbsoluteFilePath = QUrl::fromLocalFile(qmldirAbsoluteFilePath) - .toString(QUrl::RemoveScheme); - } + sanitizeUNCPath(&qmldirAbsoluteFilePath); } QmldirCache *cache = new QmldirCache; diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index d0025324f4..64e105c74c 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -8,7 +8,6 @@ #include <QtCore/qtimezone.h> #include <private/qlocale_p.h> -#include <private/qlocale_data_p.h> #include <private/qv4dateobject_p.h> #include <private/qv4numberobject_p.h> diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 80db703e73..119053828f 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -52,7 +52,7 @@ Q_TRACE_POINT(qtqml, QQmlObjectCreator_createInstance_entry, const QV4::Compiled Q_TRACE_POINT(qtqml, QQmlObjectCreator_createInstance_exit, const QString &typeName) QQmlObjectCreator::QQmlObjectCreator( - QQmlRefPointer<QQmlContextData> parentContext, + const QQmlRefPointer<QQmlContextData> &parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QQmlRefPointer<QQmlContextData> &creationContext, QQmlIncubatorPrivate *incubator) @@ -64,7 +64,7 @@ QQmlObjectCreator::QQmlObjectCreator( , isContextObject(true) , incubator(incubator) { - init(std::move(parentContext)); + init(parentContext); sharedState->componentAttached = nullptr; sharedState->allCreatedBindings.allocate(compilationUnit->totalBindingsCount()); @@ -83,7 +83,8 @@ QQmlObjectCreator::QQmlObjectCreator( } } -QQmlObjectCreator::QQmlObjectCreator(QQmlRefPointer<QQmlContextData> parentContext, +QQmlObjectCreator::QQmlObjectCreator( + const QQmlRefPointer<QQmlContextData> &parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState, bool isContextObject) : phase(Startup) @@ -94,12 +95,12 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlRefPointer<QQmlContextData> parentConte , isContextObject(isContextObject) , incubator(nullptr) { - init(std::move(parentContext)); + init(parentContext); } -void QQmlObjectCreator::init(QQmlRefPointer<QQmlContextData> providedParentContext) +void QQmlObjectCreator::init(const QQmlRefPointer<QQmlContextData> &providedParentContext) { - parentContext = std::move(providedParentContext); + parentContext = providedParentContext; engine = parentContext->engine(); v4 = engine->handle(); diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 36249b45bc..07d8da213d 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -78,6 +78,17 @@ private: class RequiredProperties : public QHash<RequiredPropertyKey, RequiredPropertyInfo> {}; +class RequiredPropertiesAndTarget : public RequiredProperties +{ +public: + RequiredPropertiesAndTarget(QObject *target) : target(target) {} + RequiredPropertiesAndTarget(const RequiredPropertiesAndTarget &) = default; + RequiredPropertiesAndTarget(RequiredPropertiesAndTarget &&) = default; + RequiredPropertiesAndTarget &operator=(const RequiredPropertiesAndTarget &) = default; + RequiredPropertiesAndTarget &operator=(RequiredPropertiesAndTarget &&) = default; + QObject *target = nullptr; +}; + struct DeferredQPropertyBinding { QObject *target = nullptr; int properyIndex = -1; @@ -105,10 +116,11 @@ class Q_QML_PRIVATE_EXPORT QQmlObjectCreator { Q_DECLARE_TR_FUNCTIONS(QQmlObjectCreator) public: - QQmlObjectCreator(QQmlRefPointer<QQmlContextData> parentContext, - const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, - const QQmlRefPointer<QQmlContextData> &creationContext, - QQmlIncubatorPrivate *incubator = nullptr); + QQmlObjectCreator( + const QQmlRefPointer<QQmlContextData> &parentContext, + const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, + const QQmlRefPointer<QQmlContextData> &creationContext, + QQmlIncubatorPrivate *incubator = nullptr); ~QQmlObjectCreator(); enum CreationFlags { NormalObject = 1, InlineComponent = 2 }; @@ -159,12 +171,12 @@ public: } private: - QQmlObjectCreator(QQmlRefPointer<QQmlContextData> contextData, - const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, - QQmlObjectCreatorSharedState *inheritedSharedState, - bool isContextObject); + QQmlObjectCreator( + const QQmlRefPointer<QQmlContextData> &contextData, + const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, + QQmlObjectCreatorSharedState *inheritedSharedState, bool isContextObject); - void init(QQmlRefPointer<QQmlContextData> parentContext); + void init(const QQmlRefPointer<QQmlContextData> &parentContext); QObject *createInstance(int index, QObject *parent = nullptr, bool isContextObject = false); diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 1430c20099..e8d5b0c8cb 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -872,18 +872,18 @@ static void removeOldBinding(QObject *object, QQmlPropertyIndex index, QQmlPrope oldBinding = oldBinding->nextBinding(); } - if (valueTypeIndex != -1 - && oldBinding - && oldBinding->kind() == QQmlAbstractBinding::ValueTypeProxy) { - oldBinding = static_cast<QQmlValueTypeProxyBinding *>(oldBinding.data())->binding(index); - } - if (!oldBinding) { // Clear the binding bit so that the binding doesn't appear later for any reason data->clearBindingBit(coreIndex); return; } + if (valueTypeIndex != -1 && oldBinding->kind() == QQmlAbstractBinding::ValueTypeProxy) { + oldBinding = static_cast<QQmlValueTypeProxyBinding *>(oldBinding.data())->binding(index); + if (!oldBinding) + return; + } + if (!(flags & QQmlPropertyPrivate::DontEnable)) oldBinding->setEnabled(false, {}); oldBinding->removeFromObject(); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 5c9916193d..72ad77b41c 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -213,6 +213,13 @@ void QQmlTypeLoader::loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::C doLoad(CachedLoader(unit), blob, mode); } +void QQmlTypeLoader::drop(const QQmlDataBlob::Ptr &blob) +{ + // We must not destroy a QQmlDataBlob from the main thread + // since it will shuffle its dependencies around. + m_thread->drop(blob); +} + void QQmlTypeLoader::loadWithStaticDataThread(const QQmlDataBlob::Ptr &blob, const QByteArray &data) { ASSERT_LOADTHREAD(); diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 1e1a03c607..854778125a 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -151,6 +151,7 @@ public: void load(QQmlDataBlob *, Mode = PreferSynchronous); void loadWithStaticData(QQmlDataBlob *, const QByteArray &, Mode = PreferSynchronous); void loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit, Mode mode = PreferSynchronous); + void drop(const QQmlDataBlob::Ptr &blob); QQmlEngine *engine() const; void initializeEngine(QQmlEngineExtensionInterface *, const char *); diff --git a/src/qml/qml/qqmltypeloaderthread.cpp b/src/qml/qml/qqmltypeloaderthread.cpp index 3d35962c08..66e1300684 100644 --- a/src/qml/qml/qqmltypeloaderthread.cpp +++ b/src/qml/qml/qqmltypeloaderthread.cpp @@ -102,6 +102,11 @@ void QQmlTypeLoaderThread::initializeEngine(QQmlEngineExtensionInterface *iface, callMethodInMain(&This::initializeEngineExtensionMain, iface, uri); } +void QQmlTypeLoaderThread::drop(const QQmlDataBlob::Ptr &b) +{ + postMethodToThread(&This::dropThread, b); +} + void QQmlTypeLoaderThread::loadThread(const QQmlDataBlob::Ptr &b) { m_loader->loadThread(b); @@ -148,4 +153,10 @@ void QQmlTypeLoaderThread::initializeEngineExtensionMain(QQmlEngineExtensionInte iface->initializeEngine(m_loader->engine(), uri); } +void QQmlTypeLoaderThread::dropThread(const QQmlDataBlob::Ptr &b) +{ + // Simply drop the reference to b + Q_UNUSED(b); +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmltypeloaderthread_p.h b/src/qml/qml/qqmltypeloaderthread_p.h index 4f65fc0cbd..e9d2f2da36 100644 --- a/src/qml/qml/qqmltypeloaderthread_p.h +++ b/src/qml/qml/qqmltypeloaderthread_p.h @@ -56,6 +56,7 @@ public: void callDownloadProgressChanged(const QQmlDataBlob::Ptr &b, qreal p); void initializeEngine(QQmlExtensionInterface *, const char *); void initializeEngine(QQmlEngineExtensionInterface *, const char *); + void drop(const QQmlDataBlob::Ptr &b); private: void loadThread(const QQmlDataBlob::Ptr &b); @@ -65,6 +66,7 @@ private: void callDownloadProgressChangedMain(const QQmlDataBlob::Ptr &b, qreal p); void initializeExtensionMain(QQmlExtensionInterface *iface, const char *uri); void initializeEngineExtensionMain(QQmlEngineExtensionInterface *iface, const char *uri); + void dropThread(const QQmlDataBlob::Ptr &b); QQmlTypeLoader *m_loader; #if QT_CONFIG(qml_network) diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index 07ba1bf9ff..6bd26f65dd 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -706,6 +706,16 @@ ReturnedValue QQmlValueTypeWrapper::lookupGetter(Lookup *lookup, ExecutionEngine bool QQmlValueTypeWrapper::lookupSetter( Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { + if (&QQmlValueTypeWrapper::lookupSetter == &QV4::Lookup::setterFallback) { + // Certain compilers, e.g. MSVC, will "helpfully" deduplicate methods that are completely + // equal. As a result, the pointers are the same, which wreaks havoc on the logic that + // decides how to retrieve the property. + qFatal("Your C++ compiler is broken."); + } + + // This setter marks the presence of a value type setter lookup. + // It falls back to the fallback lookup when run through the interpreter, but AOT-compiled + // code can get clever with it. return QV4::Lookup::setterFallback(l, engine, object, value); } |
