From c9a6f55659bc054f835aa682a521425f8fa2bf07 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 21 Sep 2017 14:53:44 +0200 Subject: Fix URL interception for qmldir files We need to intercept the URL when it is created. This relieves us of the need to hack around in it when actually retrieving the content of the qmldir file and prevents the futile attempt to load remote qmldir files via the code path that should load local ones (or vice versa). The back and forth conversion between URLs and strings is unfortunate, but can only be solved by using QUrl rather than QString where we actually mean URL. This would be a bigger change which is unsuitable for 5.9. Mind that nothing changes for code that doesn't use URL interceptors. Task-number: QTBUG-36773 Change-Id: I6bff3ae352009fdc0a17ec209691c7b390367f11 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlimport.cpp | 27 ++++++++++++++++++++++-- src/qml/qml/qqmlimport_p.h | 1 + src/qml/qml/qqmltypeloader.cpp | 48 +++++++++++++++++++++++++++++------------- 3 files changed, 59 insertions(+), 17 deletions(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 4e3b25070f..18dc8e4b28 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -1266,11 +1266,20 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ QQmlTypeLoader &typeLoader = QQmlEnginePrivate::get(database->engine)->typeLoader; - QStringList localImportPaths = database->importPathList(QQmlImportDatabase::Local); + // Interceptor might redirect remote files to local ones. + QQmlAbstractUrlInterceptor *interceptor = typeLoader.engine()->urlInterceptor(); + QStringList localImportPaths = database->importPathList( + interceptor ? QQmlImportDatabase::LocalOrRemote : QQmlImportDatabase::Local); // Search local import paths for a matching version const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(uri, localImportPaths, vmaj, vmin); - for (const QString &qmldirPath : qmlDirPaths) { + for (QString qmldirPath : qmlDirPaths) { + if (interceptor) { + qmldirPath = QQmlFile::urlToLocalFileOrQrc( + interceptor->intercept(QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath), + QQmlAbstractUrlInterceptor::QmldirFile)); + } + QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirPath); if (!absoluteFilePath.isEmpty()) { QString url; @@ -1479,6 +1488,10 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix QString qmldirUrl = resolveLocalUrl(base, importUri + (importUri.endsWith(Slash) ? String_qmldir : Slash_qmldir)); + if (QQmlAbstractUrlInterceptor *interceptor = typeLoader->engine()->urlInterceptor()) { + qmldirUrl = interceptor->intercept(QUrl(qmldirUrl), + QQmlAbstractUrlInterceptor::QmldirFile).toString(); + } QString qmldirIdentifier; if (QQmlFile::isLocalFile(qmldirUrl)) { @@ -1693,6 +1706,16 @@ bool QQmlImports::isLocal(const QUrl &url) return !QQmlFile::urlToLocalFileOrQrc(url).isEmpty(); } +QUrl QQmlImports::urlFromLocalFileOrQrcOrUrl(const QString &file) +{ + QUrl url(QLatin1String(file.at(0) == Colon ? "qrc" : "") + file); + + // We don't support single character schemes as those conflict with windows drive letters. + if (url.scheme().length() < 2) + return QUrl::fromLocalFile(file); + return url; +} + void QQmlImports::setDesignerSupportRequired(bool b) { designerSupportRequired = b; diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index 1bdd287690..9cb5340c68 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -184,6 +184,7 @@ public: static bool isLocal(const QString &url); static bool isLocal(const QUrl &url); + static QUrl urlFromLocalFileOrQrcOrUrl(const QString &); static void setDesignerSupportRequired(bool b); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index d9d7c19312..1a7b8250e7 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1436,8 +1436,13 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL // We haven't yet resolved this import m_unresolvedImports.insert(import, 0); - // Query any network import paths for this library - QStringList remotePathList = importDatabase->importPathList(QQmlImportDatabase::Remote); + QQmlAbstractUrlInterceptor *interceptor = typeLoader()->engine()->urlInterceptor(); + + // Query any network import paths for this library. + // Interceptor might redirect local paths. + QStringList remotePathList = importDatabase->importPathList( + interceptor ? QQmlImportDatabase::LocalOrRemote + : QQmlImportDatabase::Remote); if (!remotePathList.isEmpty()) { // Add this library and request the possible locations for it if (!m_importCache.addLibraryImport(importDatabase, importUri, importQualifier, import->majorVersion, @@ -1448,8 +1453,18 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL int priority = 0; const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(importUri, remotePathList, import->majorVersion, import->minorVersion); for (const QString &qmldirPath : qmlDirPaths) { - if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) + if (interceptor) { + QUrl url = interceptor->intercept( + QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath), + QQmlAbstractUrlInterceptor::QmldirFile); + if (!QQmlFile::isLocalFile(url) + && !fetchQmldir(url, import, ++priority, errors)) { + return false; + } + } else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) { return false; + } + } } } @@ -1872,19 +1887,22 @@ It can also be a remote path for a remote directory import, but it will have bee */ const QQmlTypeLoaderQmldirContent *QQmlTypeLoader::qmldirContent(const QString &filePathIn) { - QUrl url(filePathIn); //May already contain http scheme - if (url.scheme() == QLatin1String("http") || url.scheme() == QLatin1String("https")) - return *(m_importQmlDirCache.value(filePathIn)); //Can't load the remote here, but should be cached - else - url = QUrl::fromLocalFile(filePathIn); - if (engine() && engine()->urlInterceptor()) - url = engine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::QmldirFile); - Q_ASSERT(url.scheme() == QLatin1String("file")); QString filePath; - if (url.scheme() == QLatin1String("file")) - filePath = url.toLocalFile(); - else - filePath = url.path(); + + // Try to guess if filePathIn is already a URL. This is necessarily fragile, because + // - paths can contain ':', which might make them appear as URLs with schemes. + // - windows drive letters appear as schemes (thus "< 2" below). + // - a "file:" URL is equivalent to the respective file, but will be treated differently. + // Yet, this heuristic is the best we can do until we pass more structured information here, + // for example a QUrl also for local files. + QUrl url(filePathIn); + if (url.scheme().length() < 2) { + filePath = filePathIn; + } else { + filePath = QQmlFile::urlToLocalFileOrQrc(url); + if (filePath.isEmpty()) // Can't load the remote here, but should be cached + return *(m_importQmlDirCache.value(filePathIn)); + } QQmlTypeLoaderQmldirContent *qmldir; QQmlTypeLoaderQmldirContent **val = m_importQmlDirCache.value(filePath); -- cgit v1.2.3 From 36ce1490fc541489f9091e9d91234aeac4f9df90 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 22 Sep 2017 15:55:42 +0200 Subject: Don't reject plugin-only qmldir files On QQmlImportsPrivate::updateQmldirContent we need to check if the new module has actually been established after figuring out that it doesn't have any components or scripts. If it has, then we shouldn't fail, as obviously a plugin has been loaded. We don't need to check the component and script versions in that case, as plugins don't have separate versions. Change-Id: Ie328b59038fe65c3f6a2eeecfe969927bba6cd68 Reviewed-by: Lars Knoll --- src/qml/qml/qqmlimport.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 18dc8e4b28..c8d17c4b8e 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -1577,8 +1577,8 @@ bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString & if (import->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors)) { if (import->qmlDirComponents.isEmpty() && import->qmlDirScripts.isEmpty()) { - // The implicit import qmldir can be empty - if (uri != QLatin1String(".")) { + // The implicit import qmldir can be empty, and plugins have no extra versions + if (uri != QLatin1String(".") && !QQmlMetaType::isModule(uri, vmaj, vmin)) { QQmlError error; if (QQmlMetaType::isAnyModule(uri)) error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri).arg(vmaj).arg(vmin)); -- cgit v1.2.3 From d53b07ee19ee940672b1bcd8e692a488f3b6eb4e Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 23 Nov 2017 10:05:30 +0100 Subject: Re-enable QML memory profiling Task-number: QTBUG-64674 Change-Id: I48ed1a51f66ef8d55cc026f140d270baaca04fbf Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4profiling.cpp | 3 ++- src/qml/jsruntime/qv4profiling_p.h | 20 ++++++++++++++------ src/qml/memory/qv4mm.cpp | 27 ++++++++++++++++++++------- src/qml/memory/qv4mm_p.h | 10 ++++++---- src/qml/memory/qv4mmdefs_p.h | 4 ++-- 5 files changed, 44 insertions(+), 20 deletions(-) (limited to 'src/qml') diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp index bedcb5b164..5fd200efc1 100644 --- a/src/qml/jsruntime/qv4profiling.cpp +++ b/src/qml/jsruntime/qv4profiling.cpp @@ -120,7 +120,8 @@ void Profiler::startProfiling(quint64 features) if (features & (1 << FeatureMemoryAllocation)) { qint64 timestamp = m_timer.nsecsElapsed(); MemoryAllocationProperties heap = {timestamp, - (qint64)m_engine->memoryManager->getAllocatedMem(), + (qint64)m_engine->memoryManager->getAllocatedMem() - + (qint64)m_engine->memoryManager->getLargeItemsMem(), HeapPage}; m_memory_data.append(heap); MemoryAllocationProperties small = {timestamp, diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index 9de597ad0e..08b4ba6c76 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -230,16 +230,24 @@ public: bool trackAlloc(size_t size, MemoryType type) { - MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), (qint64)size, type}; - m_memory_data.append(allocation); - return true; + if (size) { + MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), (qint64)size, type}; + m_memory_data.append(allocation); + return true; + } else { + return false; + } } bool trackDealloc(size_t size, MemoryType type) { - MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), -(qint64)size, type}; - m_memory_data.append(allocation); - return true; + if (size) { + MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), -(qint64)size, type}; + m_memory_data.append(allocation); + return true; + } else { + return false; + } } quint64 featuresEnabled; diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 56f1254421..538be0d16a 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -275,7 +275,7 @@ QString binary(quintptr) { return QString(); } #define SDUMP if (1) ; else qDebug #endif -bool Chunk::sweep() +bool Chunk::sweep(ExecutionEngine *engine) { bool hasUsedSlots = false; SDUMP() << "sweeping chunk" << this; @@ -316,6 +316,9 @@ bool Chunk::sweep() b->_checkIsDestroyed(); } } + Q_V4_PROFILE_DEALLOC(engine, qPopulationCount((objectBitmap[i] | extendsBitmap[i]) + - (blackBitmap[i] | e)) * Chunk::SlotSize, + Profiling::SmallItem); objectBitmap[i] = blackBitmap[i]; hasUsedSlots |= (blackBitmap[i] != 0); blackBitmap[i] = 0; @@ -330,7 +333,7 @@ bool Chunk::sweep() return hasUsedSlots; } -void Chunk::freeAll() +void Chunk::freeAll(ExecutionEngine *engine) { // DEBUG << "sweeping chunk" << this << (*freeList); HeapItem *o = realBase(); @@ -361,6 +364,8 @@ void Chunk::freeAll() b->_checkIsDestroyed(); } } + Q_V4_PROFILE_DEALLOC(engine, (qPopulationCount(objectBitmap[i]|extendsBitmap[i]) + - qPopulationCount(e)) * Chunk::SlotSize, Profiling::SmallItem); objectBitmap[i] = 0; blackBitmap[i] = 0; extendsBitmap[i] = e; @@ -560,6 +565,7 @@ HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) { if (!forceAllocation) return 0; Chunk *newChunk = chunkAllocator->allocate(); + Q_V4_PROFILE_ALLOC(engine, Chunk::DataSize, Profiling::HeapPage); chunks.push_back(newChunk); nextFree = newChunk->first(); nFree = Chunk::AvailableSlots; @@ -570,6 +576,7 @@ HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) { done: m->setAllocatedSlots(slotsRequired); + Q_V4_PROFILE_ALLOC(engine, slotsRequired * Chunk::SlotSize, Profiling::SmallItem); // DEBUG << " " << hex << m->chunk() << m->chunk()->objectBitmap[0] << m->chunk()->extendsBitmap[0] << (m - m->chunk()->realBase()); return m; } @@ -584,12 +591,13 @@ void BlockAllocator::sweep() usedSlotsAfterLastSweep = 0; auto isFree = [this] (Chunk *c) { - bool isUsed = c->sweep(); + bool isUsed = c->sweep(engine); if (isUsed) { c->sortIntoBins(freeBins, NumBins); usedSlotsAfterLastSweep += c->nUsedSlots(); } else { + Q_V4_PROFILE_DEALLOC(engine, Chunk::DataSize, Profiling::HeapPage); chunkAllocator->free(c); } return !isUsed; @@ -602,7 +610,8 @@ void BlockAllocator::sweep() void BlockAllocator::freeAll() { for (auto c : chunks) { - c->freeAll(); + c->freeAll(engine); + Q_V4_PROFILE_DEALLOC(engine, Chunk::DataSize, Profiling::HeapPage); chunkAllocator->free(c); } } @@ -642,6 +651,7 @@ HeapItem *HugeItemAllocator::allocate(size_t size) { Chunk *c = chunkAllocator->allocate(size); chunks.push_back(HugeChunk{c, size}); Chunk::setBit(c->objectBitmap, c->first() - c->realBase()); + Q_V4_PROFILE_ALLOC(engine, size, Profiling::LargeItem); return c->first(); } @@ -660,8 +670,10 @@ void HugeItemAllocator::sweep() { auto isBlack = [this] (const HugeChunk &c) { bool b = c.chunk->first()->isBlack(); Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase()); - if (!b) + if (!b) { + Q_V4_PROFILE_DEALLOC(engine, c.size, Profiling::LargeItem); freeHugeChunk(chunkAllocator, c); + } return !b; }; @@ -672,6 +684,7 @@ void HugeItemAllocator::sweep() { void HugeItemAllocator::freeAll() { for (auto &c : chunks) { + Q_V4_PROFILE_DEALLOC(engine, c.size, Profiling::LargeItem); freeHugeChunk(chunkAllocator, c); } } @@ -681,8 +694,8 @@ MemoryManager::MemoryManager(ExecutionEngine *engine) : engine(engine) , chunkAllocator(new ChunkAllocator) , stackAllocator(chunkAllocator) - , blockAllocator(chunkAllocator) - , hugeItemAllocator(chunkAllocator) + , blockAllocator(chunkAllocator, engine) + , hugeItemAllocator(chunkAllocator, engine) , m_persistentValues(new PersistentValueStorage(engine)) , m_weakValues(new PersistentValueStorage(engine)) , unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT) diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 77c5885dfe..e3cccb6aa0 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -117,8 +117,8 @@ struct StackAllocator { }; struct BlockAllocator { - BlockAllocator(ChunkAllocator *chunkAllocator) - : chunkAllocator(chunkAllocator) + BlockAllocator(ChunkAllocator *chunkAllocator, ExecutionEngine *engine) + : chunkAllocator(chunkAllocator), engine(engine) { memset(freeBins, 0, sizeof(freeBins)); #if MM_DEBUG @@ -161,6 +161,7 @@ struct BlockAllocator { size_t usedSlotsAfterLastSweep = 0; HeapItem *freeBins[NumBins]; ChunkAllocator *chunkAllocator; + ExecutionEngine *engine; std::vector chunks; #if MM_DEBUG uint allocations[NumBins]; @@ -168,8 +169,8 @@ struct BlockAllocator { }; struct HugeItemAllocator { - HugeItemAllocator(ChunkAllocator *chunkAllocator) - : chunkAllocator(chunkAllocator) + HugeItemAllocator(ChunkAllocator *chunkAllocator, ExecutionEngine *engine) + : chunkAllocator(chunkAllocator), engine(engine) {} HeapItem *allocate(size_t size); @@ -184,6 +185,7 @@ struct HugeItemAllocator { } ChunkAllocator *chunkAllocator; + ExecutionEngine *engine; struct HugeChunk { Chunk *chunk; size_t size; diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index ef93971ab8..7c82fef056 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -179,8 +179,8 @@ struct Chunk { return usedSlots; } - bool sweep(); - void freeAll(); + bool sweep(ExecutionEngine *engine); + void freeAll(ExecutionEngine *engine); void sortIntoBins(HeapItem **bins, uint nBins); }; -- cgit v1.2.3 From efe1926598c69a09c9365673bba6961a83936d49 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 17 Oct 2017 16:54:22 +0200 Subject: More fine-grained deferred property execution This allows Qt Quick Controls 2 to defer the execution of certain building blocks until needed. For example, a button control can defer its background item so that the default background is not executed at all when replaced by a custom background. First of all, this gives a massive performance boost for customized controls. Secondly, this avoids the most burning issue in QQC2, problems with asynchronous incubation ("Object destroyed during incubation"). Task-number: QTBUG-50992 Change-Id: If3616c9dac70e3a474a20070ad0452874d267164 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmldata_p.h | 3 ++ src/qml/qml/qqmlengine.cpp | 35 ++++++++++++++-- src/qml/qml/qqmlobjectcreator.cpp | 85 +++++++++++++++++++++++++++++++++++---- src/qml/qml/qqmlobjectcreator_p.h | 3 +- 4 files changed, 113 insertions(+), 13 deletions(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index d692feb975..63994a392d 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -76,6 +76,7 @@ class QQmlNotifierEndpoint; namespace QV4 { namespace CompiledData { struct CompilationUnit; +struct Binding; } } @@ -216,12 +217,14 @@ public: struct DeferredData { unsigned int deferredIdx; + QMultiHash bindings; QV4::CompiledData::CompilationUnit *compilationUnit;//Not always the same as the other compilation unit QQmlContextData *context;//Could be either context or outerContext }; QV4::CompiledData::CompilationUnit *compilationUnit; QVector deferredData; + void deferData(int objectIndex, QV4::CompiledData::CompilationUnit *, QQmlContextData *); void releaseDeferredData(); QV4::WeakValue jsWrapper; diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index d99bec4c52..612c3439c1 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1639,13 +1639,40 @@ void QQmlData::NotifyList::layout() todo = 0; } +void QQmlData::deferData(int objectIndex, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlContextData *context) +{ + QQmlData::DeferredData *deferData = new QQmlData::DeferredData; + deferData->deferredIdx = objectIndex; + deferData->compilationUnit = compilationUnit; + deferData->compilationUnit->addref(); + deferData->context = context; + + const QV4::CompiledData::Object *compiledObject = compilationUnit->objectAt(objectIndex); + const QV4::CompiledData::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(objectIndex); + + 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) + deferData->bindings.insert(property->coreIndex(), binding); + } + + deferredData.append(deferData); +} + void QQmlData::releaseDeferredData() { - for (DeferredData *deferData : qAsConst(deferredData)) { - deferData->compilationUnit->release(); - delete deferData; + auto it = deferredData.begin(); + while (it != deferredData.end()) { + DeferredData *deferData = *it; + if (deferData->bindings.isEmpty()) { + deferData->compilationUnit->release(); + delete deferData; + it = deferredData.erase(it); + } else { + ++it; + } } - deferredData.clear(); } void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint) diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index b2f1421bcb..3663b06d55 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -233,6 +233,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI return instance; } +// ### unify or keep in sync with populateDeferredBinding() bool QQmlObjectCreator::populateDeferredProperties(QObject *instance, QQmlData::DeferredData *deferredData) { QQmlData *declarativeData = QQmlData::get(instance); @@ -283,6 +284,80 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance, QQmlData:: qSwap(_qmlContext, qmlContext); qSwap(_scopeObject, scopeObject); + deferredData->bindings.clear(); + phase = ObjectsCreated; + + return errors.isEmpty(); +} + +// ### unify or keep in sync with populateDeferredProperties() +bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, QQmlData::DeferredData *deferredData, const QV4::CompiledData::Binding *binding) +{ + Q_ASSERT(binding->flags & QV4::CompiledData::Binding::IsDeferredBinding); + + QObject *instance = qmlProperty.object(); + QQmlData *declarativeData = QQmlData::get(instance); + context = deferredData->context; + sharedState->rootContext = context; + + QObject *bindingTarget = instance; + + QQmlRefPointer cache = declarativeData->propertyCache; + QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance); + + QObject *scopeObject = instance; + qSwap(_scopeObject, scopeObject); + + QV4::Scope valueScope(v4); + + Q_ASSERT(topLevelCreator); + if (!sharedState->allJavaScriptObjects) + sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount); + + QV4::QmlContext *qmlContext = static_cast(valueScope.alloc(1)); + + qSwap(_qmlContext, qmlContext); + + qSwap(_propertyCache, cache); + qSwap(_qobject, instance); + + int objectIndex = deferredData->deferredIdx; + qSwap(_compiledObjectIndex, objectIndex); + + const QV4::CompiledData::Object *obj = qmlUnit->objectAt(_compiledObjectIndex); + qSwap(_compiledObject, obj); + + qSwap(_ddata, declarativeData); + qSwap(_bindingTarget, bindingTarget); + qSwap(_vmeMetaObject, vmeMetaObject); + + QQmlListProperty savedList; + qSwap(_currentList, savedList); + + const QQmlPropertyData &property = QQmlPropertyPrivate::get(qmlProperty)->core; + + if (property.isQList()) { + void *argv[1] = { (void*)&_currentList }; + QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property.coreIndex(), argv); + } else if (_currentList.object) { + _currentList = QQmlListProperty(); + } + + setPropertyBinding(&property, binding); + + qSwap(_currentList, savedList); + + qSwap(_vmeMetaObject, vmeMetaObject); + qSwap(_bindingTarget, bindingTarget); + qSwap(_ddata, declarativeData); + qSwap(_compiledObject, obj); + qSwap(_compiledObjectIndex, objectIndex); + qSwap(_qobject, instance); + qSwap(_propertyCache, cache); + + qSwap(_qmlContext, qmlContext); + qSwap(_scopeObject, scopeObject); + phase = ObjectsCreated; return errors.isEmpty(); @@ -1341,14 +1416,8 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * qSwap(_propertyCache, cache); qSwap(_vmeMetaObject, vmeMetaObject); - if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings) { - QQmlData::DeferredData *deferData = new QQmlData::DeferredData; - deferData->deferredIdx = _compiledObjectIndex; - deferData->compilationUnit = compilationUnit; - deferData->compilationUnit->addref(); - deferData->context = context; - _ddata->deferredData.append(deferData); - } + if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings) + _ddata->deferData(_compiledObjectIndex, compilationUnit, context); if (_compiledObject->nFunctions > 0) setupFunctions(); diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 0c2d427c58..e2371cb4f1 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -81,7 +81,7 @@ struct QQmlObjectCreatorSharedState : public QSharedData QRecursionNode recursionNode; }; -class QQmlObjectCreator +class Q_QML_PRIVATE_EXPORT QQmlObjectCreator { Q_DECLARE_TR_FUNCTIONS(QQmlObjectCreator) public: @@ -90,6 +90,7 @@ public: QObject *create(int subComponentIndex = -1, QObject *parent = 0, QQmlInstantiationInterrupt *interrupt = 0); bool populateDeferredProperties(QObject *instance, QQmlData::DeferredData *deferredData); + bool populateDeferredBinding(const QQmlProperty &qmlProperty, QQmlData::DeferredData *deferredData, const QV4::CompiledData::Binding *binding); QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt); void cancel(QObject *object); void clear(); -- cgit v1.2.3 From 787dbda672d6df4ff2336bb3afda62a233b88aaa Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 25 Oct 2017 14:50:14 +0200 Subject: Check linked contexts for context objects being deleted In QQmlObjectCreator::createInstance we can assign the new object as context object to a linkedContext of its QQmlData, not only it's ownContext. Consequently, we have to check all the linked contexts and remove the object when found on deletion. Change-Id: I09bccdb0190406245fa5a379edaff0a8f118062f Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlengine.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 612c3439c1..5350ad38a3 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -714,8 +714,11 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o) { if (QQmlData *d = QQmlData::get(o)) { if (d->ownContext) { - for (QQmlContextData *lc = d->ownContext->linkedContext; lc; lc = lc->linkedContext) + for (QQmlContextData *lc = d->ownContext->linkedContext; lc; lc = lc->linkedContext) { lc->invalidate(); + if (lc->contextObject == o) + lc->contextObject = nullptr; + } d->ownContext->invalidate(); if (d->ownContext->contextObject == o) d->ownContext->contextObject = nullptr; -- cgit v1.2.3 From 60d589ccddb036e84883a6c2ef63a5292c8ad022 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Mon, 6 Nov 2017 16:13:13 +0100 Subject: QQmlIntanceModel: use QQmlIncubator::IncubationMode instead of bool to specify incubation mode The current implementation would pass a boolean to signal if asynchronous or synchronous incubation should be used to create an item. The problem with this approach is that passing 'synchronous" would translate to QQmlIncubation::AsynchronousIfNested later down the chain. This meant that even if the caller requested synchronous incubation, it could end up with asynchronous incubation anyway, e.g if an async parent incubator was active at the time of the call. And this can easily come as an unhandled supprise for the caller, and as such, cause unforseen bugs. This patch is a first of a set of patches that is done to fix the bug reported in the task below. It will not change any behavior, it is written to preserve the logic exactly as it were, just as a preparation for subsequent patches. It makes it explicit at the call location what incubation mode will be used, and especially make it clear whenever the AsynchronousIfNested flag is in play. Task-number: QTBUG-61537 Change-Id: I8b3ba5438ebb2cd59983a098bd8ceeeb844da87b Reviewed-by: J-P Nurmi --- src/qml/types/qqmldelegatemodel.cpp | 21 +++++++++------------ src/qml/types/qqmldelegatemodel_p.h | 3 ++- src/qml/types/qqmldelegatemodel_p_p.h | 4 ++-- src/qml/types/qqmlinstantiator.cpp | 4 ++-- src/qml/types/qqmlobjectmodel.cpp | 2 +- src/qml/types/qqmlobjectmodel_p.h | 5 +++-- 6 files changed, 19 insertions(+), 20 deletions(-) (limited to 'src/qml') diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index e3906f2a7e..4da7199d1e 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -931,7 +931,7 @@ void QQmlDelegateModelPrivate::setInitialState(QQDMIncubationTask *incubationTas emitInitItem(incubationTask, cacheItem->object); } -QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, bool asynchronous) +QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQmlIncubator::IncubationMode incubationMode) { if (!m_delegate || index < 0 || index >= m_compositor.count(group)) { qWarning() << "DelegateModel::item: index out range" << index << m_compositor.count(group); @@ -962,7 +962,8 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, bo cacheItem->referenceObject(); if (cacheItem->incubationTask) { - if (!asynchronous && cacheItem->incubationTask->incubationMode() == QQmlIncubator::Asynchronous) { + bool sync = (incubationMode == QQmlIncubator::Synchronous || incubationMode == QQmlIncubator::AsynchronousIfNested); + if (sync && cacheItem->incubationTask->incubationMode() == QQmlIncubator::Asynchronous) { // previously requested async - now needed immediately cacheItem->incubationTask->forceCompletion(); } @@ -971,7 +972,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, bo cacheItem->scriptRef += 1; - cacheItem->incubationTask = new QQDMIncubationTask(this, asynchronous ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested); + cacheItem->incubationTask = new QQDMIncubationTask(this, incubationMode); cacheItem->incubationTask->incubating = cacheItem; cacheItem->incubationTask->clear(); @@ -1024,7 +1025,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, bo to ensure a reference is held. Any call to item() which returns a valid item must be matched by a call to release() in order to destroy the item. */ -QObject *QQmlDelegateModel::object(int index, bool asynchronous) +QObject *QQmlDelegateModel::object(int index, QQmlIncubator::IncubationMode incubationMode) { Q_D(QQmlDelegateModel); if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) { @@ -1032,11 +1033,7 @@ QObject *QQmlDelegateModel::object(int index, bool asynchronous) return 0; } - QObject *object = d->object(d->m_compositorGroup, index, asynchronous); - if (!object) - return 0; - - return object; + return d->object(d->m_compositorGroup, index, incubationMode); } QString QQmlDelegateModelPrivate::stringValue(Compositor::Group group, int index, const QString &name) @@ -2659,7 +2656,7 @@ void QQmlDelegateModelGroup::create(QQmlV4Function *args) return; } - QObject *object = model->object(group, index, false); + QObject *object = model->object(group, index, QQmlIncubator::AsynchronousIfNested); if (object) { QVector inserts; Compositor::iterator it = model->m_compositor.find(group, index); @@ -3147,7 +3144,7 @@ bool QQmlPartsModel::isValid() const return m_model->isValid(); } -QObject *QQmlPartsModel::object(int index, bool asynchronous) +QObject *QQmlPartsModel::object(int index, QQmlIncubator::IncubationMode incubationMode) { QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model); @@ -3156,7 +3153,7 @@ QObject *QQmlPartsModel::object(int index, bool asynchronous) return 0; } - QObject *object = model->object(m_compositorGroup, index, asynchronous); + QObject *object = model->object(m_compositorGroup, index, incubationMode); if (QQuickPackage *package = qmlobject_cast(object)) { QObject *part = package->part(m_part); diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h index 186144d107..5ae2d48969 100644 --- a/src/qml/types/qqmldelegatemodel_p.h +++ b/src/qml/types/qqmldelegatemodel_p.h @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -109,7 +110,7 @@ public: int count() const override; bool isValid() const override { return delegate() != 0; } - QObject *object(int index, bool asynchronous = false) override; + QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override; ReleaseFlags release(QObject *object) override; void cancel(int index) override; QString stringValue(int index, const QString &role) override; diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h index 0f8438870a..a6a7853116 100644 --- a/src/qml/types/qqmldelegatemodel_p_p.h +++ b/src/qml/types/qqmldelegatemodel_p_p.h @@ -261,7 +261,7 @@ public: void connectModel(QQmlAdaptorModel *model); void requestMoreIfNecessary(); - QObject *object(Compositor::Group group, int index, bool asynchronous); + QObject *object(Compositor::Group group, int index, QQmlIncubator::IncubationMode incubationMode); QQmlDelegateModel::ReleaseFlags release(QObject *object); QString stringValue(Compositor::Group group, int index, const QString &name); void emitCreatedPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package); @@ -357,7 +357,7 @@ public: int count() const override; bool isValid() const override; - QObject *object(int index, bool asynchronous = false) override; + QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override; ReleaseFlags release(QObject *item) override; QString stringValue(int index, const QString &role) override; QList watchedRoles() const { return m_watchedRoles; } diff --git a/src/qml/types/qqmlinstantiator.cpp b/src/qml/types/qqmlinstantiator.cpp index 2de5875deb..6e2b66aea7 100644 --- a/src/qml/types/qqmlinstantiator.cpp +++ b/src/qml/types/qqmlinstantiator.cpp @@ -85,7 +85,7 @@ void QQmlInstantiatorPrivate::clear() QObject *QQmlInstantiatorPrivate::modelObject(int index, bool async) { requestedIndex = index; - QObject *o = instanceModel->object(index, async); + QObject *o = instanceModel->object(index, async ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested); requestedIndex = -1; return o; } @@ -123,7 +123,7 @@ void QQmlInstantiatorPrivate::_q_createdItem(int idx, QObject* item) if (objects.contains(item)) //Case when it was created synchronously in regenerate return; if (requestedIndex != idx) // Asynchronous creation, reference the object - (void)instanceModel->object(idx, false); + (void)instanceModel->object(idx); item->setParent(q); if (objects.size() < idx + 1) { int modelCount = instanceModel->count(); diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp index dcd0360199..dcb41469ba 100644 --- a/src/qml/types/qqmlobjectmodel.cpp +++ b/src/qml/types/qqmlobjectmodel.cpp @@ -267,7 +267,7 @@ bool QQmlObjectModel::isValid() const return true; } -QObject *QQmlObjectModel::object(int index, bool) +QObject *QQmlObjectModel::object(int index, QQmlIncubator::IncubationMode) { Q_D(QQmlObjectModel); QQmlObjectModelPrivate::Item &item = d->children[index]; diff --git a/src/qml/types/qqmlobjectmodel_p.h b/src/qml/types/qqmlobjectmodel_p.h index fc4c03874f..5e4a9c686f 100644 --- a/src/qml/types/qqmlobjectmodel_p.h +++ b/src/qml/types/qqmlobjectmodel_p.h @@ -52,6 +52,7 @@ // #include +#include #include #include @@ -74,7 +75,7 @@ public: virtual int count() const = 0; virtual bool isValid() const = 0; - virtual QObject *object(int index, bool asynchronous=false) = 0; + virtual QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) = 0; virtual ReleaseFlags release(QObject *object) = 0; virtual void cancel(int) {} virtual QString stringValue(int, const QString &) = 0; @@ -113,7 +114,7 @@ public: int count() const override; bool isValid() const override; - QObject *object(int index, bool asynchronous = false) override; + QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override; ReleaseFlags release(QObject *object) override; QString stringValue(int index, const QString &role) override; void setWatchedRoles(const QList &) override {} -- cgit v1.2.3 From 816b5a667f0b5b47c3f80c2c775535310c89b727 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Wed, 8 Nov 2017 11:01:35 +0100 Subject: QQmlDelegateModel: add incubationStatus(), and use it to determine 'requestedIndex' We used to assign the currently incubating item to 'requestedIndex' based on requested incubation mode alone. This is not sufficient, as the item can also be loaded async when the mode is AsyncIfNested. To check if the item is really loading async (and that we're not getting nullptr because of some other failure), we need to ask the incubator. Task-number: QTBUG-61537 Change-Id: Id1f458db4a7584a6b58d5bad0e7832ce4fc341dc Reviewed-by: J-P Nurmi --- src/qml/types/qqmldelegatemodel.cpp | 20 ++++++++++++++++++++ src/qml/types/qqmldelegatemodel_p.h | 1 + src/qml/types/qqmldelegatemodel_p_p.h | 1 + src/qml/types/qqmlobjectmodel.cpp | 5 +++++ src/qml/types/qqmlobjectmodel_p.h | 2 ++ 5 files changed, 29 insertions(+) (limited to 'src/qml') diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 4da7199d1e..9dd82494ca 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -1036,6 +1036,16 @@ QObject *QQmlDelegateModel::object(int index, QQmlIncubator::IncubationMode incu return d->object(d->m_compositorGroup, index, incubationMode); } +QQmlIncubator::Status QQmlDelegateModel::incubationStatus(int index) +{ + Q_D(QQmlDelegateModel); + Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index); + if (!it->inCache()) + return QQmlIncubator::Null; + + return d->m_cache.at(it.cacheIndex)->incubationTask->status(); +} + QString QQmlDelegateModelPrivate::stringValue(Compositor::Group group, int index, const QString &name) { Compositor::iterator it = m_compositor.find(group, index); @@ -3203,6 +3213,16 @@ void QQmlPartsModel::setWatchedRoles(const QList &roles) m_watchedRoles = roles; } +QQmlIncubator::Status QQmlPartsModel::incubationStatus(int index) +{ + QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model); + Compositor::iterator it = model->m_compositor.find(model->m_compositorGroup, index); + if (!it->inCache()) + return QQmlIncubator::Null; + + return model->m_cache.at(it.cacheIndex)->incubationTask->status(); +} + int QQmlPartsModel::indexOf(QObject *item, QObject *) const { QHash::const_iterator it = m_packaged.find(item); diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h index 5ae2d48969..71179fd8be 100644 --- a/src/qml/types/qqmldelegatemodel_p.h +++ b/src/qml/types/qqmldelegatemodel_p.h @@ -115,6 +115,7 @@ public: void cancel(int index) override; QString stringValue(int index, const QString &role) override; void setWatchedRoles(const QList &roles) override; + QQmlIncubator::Status incubationStatus(int index) override; int indexOf(QObject *object, QObject *objectContext) const override; diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h index a6a7853116..d8e61b05a1 100644 --- a/src/qml/types/qqmldelegatemodel_p_p.h +++ b/src/qml/types/qqmldelegatemodel_p_p.h @@ -362,6 +362,7 @@ public: QString stringValue(int index, const QString &role) override; QList watchedRoles() const { return m_watchedRoles; } void setWatchedRoles(const QList &roles) override; + QQmlIncubator::Status incubationStatus(int index) override; int indexOf(QObject *item, QObject *objectContext) const override; diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp index dcb41469ba..54da0867d4 100644 --- a/src/qml/types/qqmlobjectmodel.cpp +++ b/src/qml/types/qqmlobjectmodel.cpp @@ -298,6 +298,11 @@ QString QQmlObjectModel::stringValue(int index, const QString &name) return QQmlEngine::contextForObject(d->children.at(index).item)->contextProperty(name).toString(); } +QQmlIncubator::Status QQmlObjectModel::incubationStatus(int) +{ + return QQmlIncubator::Ready; +} + int QQmlObjectModel::indexOf(QObject *item, QObject *) const { Q_D(const QQmlObjectModel); diff --git a/src/qml/types/qqmlobjectmodel_p.h b/src/qml/types/qqmlobjectmodel_p.h index 5e4a9c686f..b3cf45ca62 100644 --- a/src/qml/types/qqmlobjectmodel_p.h +++ b/src/qml/types/qqmlobjectmodel_p.h @@ -80,6 +80,7 @@ public: virtual void cancel(int) {} virtual QString stringValue(int, const QString &) = 0; virtual void setWatchedRoles(const QList &roles) = 0; + virtual QQmlIncubator::Status incubationStatus(int index) = 0; virtual int indexOf(QObject *object, QObject *objectContext) const = 0; @@ -118,6 +119,7 @@ public: ReleaseFlags release(QObject *object) override; QString stringValue(int index, const QString &role) override; void setWatchedRoles(const QList &) override {} + QQmlIncubator::Status incubationStatus(int index) override; int indexOf(QObject *object, QObject *objectContext) const override; -- cgit v1.2.3 From 2cfe1bb09c11432ca5033f9589243e9e62fe9488 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Fri, 27 Oct 2017 12:54:57 +0200 Subject: Add a means to unregister custom qml types In cases where Qt is used in a plugin it is possible that a plugin will be unloaded while Qt itself is still loaded and as a result there is a chance that there will be conflicting types registered. Therefore, to ensure that plugins correctly clean up after themselves cleanly, we need to add a means to unregister qml types. This is intended to only be used when the user knows what they are doing. Task-number: QTBUG-56521 Task-number: QTBUG-56532 Change-Id: Ie396e522385004e6e9f3841e04f8072ff29cb15b Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlmetatype.cpp | 21 +++++++++++++++++++++ src/qml/qml/qqmlmetatype_p.h | 2 ++ 2 files changed, 23 insertions(+) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index ac670bdabb..3a0d5c3daf 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -2238,6 +2238,27 @@ QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVe return data->propertyCache(type, minorVersion); } +void qmlUnregisterType(int typeIndex) +{ + QMutexLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + { + const QQmlTypePrivate *d = data->types.value(typeIndex).priv(); + if (d) { + removeQQmlTypePrivate(data->idToType, d); + removeQQmlTypePrivate(data->nameToType, d); + removeQQmlTypePrivate(data->urlToType, d); + removeQQmlTypePrivate(data->urlToNonFileImportType, d); + removeQQmlTypePrivate(data->metaObjectToType, d); + for (QQmlMetaTypeData::TypeModules::Iterator module = data->uriToModule.begin(); module != data->uriToModule.end(); ++module) { + QQmlTypeModulePrivate *modulePrivate = (*module)->priv(); + modulePrivate->remove(d); + } + data->types[typeIndex] = QQmlType(); + } + } +} + void QQmlMetaType::freeUnusedTypesAndCaches() { QMutexLocker lock(metaTypeDataLock()); diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 4bfdf52de1..f5b9beb905 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -75,6 +75,8 @@ class QQmlCompiledData; namespace QV4 { struct String; } +void Q_QML_PRIVATE_EXPORT qmlUnregisterType(int type); + class Q_QML_PRIVATE_EXPORT QQmlMetaType { public: -- cgit v1.2.3 From 823428d994b0ec0f6b85288d74554660a51b2406 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 1 Dec 2017 10:03:44 +0100 Subject: Restore a temporary QQmlInstanceModel::object() overload The API change in 60d589c broke Qt3D build. Restore a temporary overload to unblock the CI. Change-Id: I4debce4dc4ec7668b75854da3dc7e1813c9c34c5 Reviewed-by: Friedemann Kleint --- src/qml/types/qqmlobjectmodel_p.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src/qml') diff --git a/src/qml/types/qqmlobjectmodel_p.h b/src/qml/types/qqmlobjectmodel_p.h index b3cf45ca62..c98fe13a6b 100644 --- a/src/qml/types/qqmlobjectmodel_p.h +++ b/src/qml/types/qqmlobjectmodel_p.h @@ -75,6 +75,7 @@ public: virtual int count() const = 0; virtual bool isValid() const = 0; + QObject *object(int index, bool async) { return object(index, async ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested); } virtual QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) = 0; virtual ReleaseFlags release(QObject *object) = 0; virtual void cancel(int) {} -- cgit v1.2.3