diff options
author | Liang Qi <liang.qi@qt.io> | 2017-12-12 10:35:21 +0100 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2018-01-04 14:41:16 +0100 |
commit | 2bee46e3f10e2c44d185d7a51a06830b68529676 (patch) | |
tree | b65ac19203edfc2972b6020dd040e46c43b5d1fb /src/qml | |
parent | 52f7ab28172cea3710a16775b7a512fce821fc77 (diff) | |
parent | 41293196b4db1aa7a0c616af312875c484639644 (diff) |
Merge remote-tracking branch 'origin/5.9' into 5.10
Conflicts:
src/qml/memory/qv4mm.cpp
src/qml/memory/qv4mmdefs_p.h
src/quick/items/qquickwindow.cpp
src/quick/items/qquickwindow_p.h
tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro
tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
Change-Id: I7021fa1edf076627a67048f41f7b201220262b09
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/jsruntime/qv4profiling.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4profiling_p.h | 20 | ||||
-rw-r--r-- | src/qml/memory/qv4mm.cpp | 39 | ||||
-rw-r--r-- | src/qml/memory/qv4mm_p.h | 12 | ||||
-rw-r--r-- | src/qml/memory/qv4mmdefs_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmldata_p.h | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 40 | ||||
-rw-r--r-- | src/qml/qml/qqmlimport.cpp | 31 | ||||
-rw-r--r-- | src/qml/qml/qqmlimport_p.h | 1 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 21 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 85 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator_p.h | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 48 | ||||
-rw-r--r-- | src/qml/types/qqmldelegatemodel.cpp | 39 | ||||
-rw-r--r-- | src/qml/types/qqmldelegatemodel_p.h | 4 | ||||
-rw-r--r-- | src/qml/types/qqmldelegatemodel_p_p.h | 5 | ||||
-rw-r--r-- | src/qml/types/qqmlinstantiator.cpp | 4 | ||||
-rw-r--r-- | src/qml/types/qqmlobjectmodel.cpp | 7 | ||||
-rw-r--r-- | src/qml/types/qqmlobjectmodel_p.h | 8 |
20 files changed, 301 insertions, 76 deletions
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 de97918fb0..8821d3c921 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -348,7 +348,8 @@ static void increaseFreedCountForClass(const char *className) (*freedObjectStatsGlobal())[className]++; } -bool Chunk::sweep(ClassDestroyStatsCallback classCountPtr) +//bool Chunk::sweep(ClassDestroyStatsCallback classCountPtr) +bool Chunk::sweep(ExecutionEngine *engine) { bool hasUsedSlots = false; SDUMP() << "sweeping chunk" << this; @@ -387,13 +388,16 @@ bool Chunk::sweep(ClassDestroyStatsCallback classCountPtr) HeapItem *itemToFree = o + index; Heap::Base *b = *itemToFree; const VTable *v = b->vtable(); - if (Q_UNLIKELY(classCountPtr)) - classCountPtr(v->className); +// if (Q_UNLIKELY(classCountPtr)) +// classCountPtr(v->className); if (v->destroy) { v->destroy(b); b->_checkIsDestroyed(); } } + Q_V4_PROFILE_DEALLOC(engine, qPopulationCount((objectBitmap[i] | extendsBitmap[i]) + - (blackBitmap[i] | e)) * Chunk::SlotSize, + Profiling::SmallItem); objectBitmap[i] = blackBitmap[i]; grayBitmap[i] = 0; hasUsedSlots |= (blackBitmap[i] != 0); @@ -408,7 +412,7 @@ bool Chunk::sweep(ClassDestroyStatsCallback classCountPtr) return hasUsedSlots; } -void Chunk::freeAll() +void Chunk::freeAll(ExecutionEngine *engine) { // DEBUG << "sweeping chunk" << this << (*freeList); HeapItem *o = realBase(); @@ -439,6 +443,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; grayBitmap[i] = 0; extendsBitmap[i] = e; @@ -681,6 +687,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; @@ -691,11 +698,12 @@ 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; } -void BlockAllocator::sweep(ClassDestroyStatsCallback classCountPtr) +void BlockAllocator::sweep() { nextFree = 0; nFree = 0; @@ -704,13 +712,14 @@ void BlockAllocator::sweep(ClassDestroyStatsCallback classCountPtr) // qDebug() << "BlockAlloc: sweep"; usedSlotsAfterLastSweep = 0; - auto isFree = [this, classCountPtr] (Chunk *c) { - bool isUsed = c->sweep(classCountPtr); + auto isFree = [this] (Chunk *c) { + 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; @@ -723,7 +732,8 @@ void BlockAllocator::sweep(ClassDestroyStatsCallback classCountPtr) void BlockAllocator::freeAll() { for (auto c : chunks) { - c->freeAll(); + c->freeAll(engine); + Q_V4_PROFILE_DEALLOC(engine, Chunk::DataSize, Profiling::HeapPage); chunkAllocator->free(c); } } @@ -776,6 +786,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(); } @@ -798,8 +809,11 @@ void HugeItemAllocator::sweep(ClassDestroyStatsCallback classCountPtr) { auto isBlack = [this, classCountPtr] (const HugeChunk &c) { bool b = c.chunk->first()->isBlack(); - if (!b) + Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase()); + if (!b) { + Q_V4_PROFILE_DEALLOC(engine, c.size, Profiling::LargeItem); freeHugeChunk(chunkAllocator, c, classCountPtr); + } return !b; }; @@ -828,6 +842,7 @@ void HugeItemAllocator::collectGrayItems(MarkStack *markStack) void HugeItemAllocator::freeAll() { for (auto &c : chunks) { + Q_V4_PROFILE_DEALLOC(engine, c.size, Profiling::LargeItem); freeHugeChunk(chunkAllocator, c, nullptr); } } @@ -837,8 +852,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) @@ -1096,7 +1111,7 @@ void MemoryManager::sweep(bool lastSweep, ClassDestroyStatsCallback classCountPt } } - blockAllocator.sweep(classCountPtr); + blockAllocator.sweep(); hugeItemAllocator.sweep(classCountPtr); } diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 17957d0cd6..e16a0ca544 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -118,8 +118,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 @@ -153,7 +153,7 @@ struct BlockAllocator { return used; } - void sweep(ClassDestroyStatsCallback classCountPtr); + void sweep(); void freeAll(); void resetBlackBits(); void collectGrayItems(MarkStack *markStack); @@ -164,6 +164,7 @@ struct BlockAllocator { size_t usedSlotsAfterLastSweep = 0; HeapItem *freeBins[NumBins]; ChunkAllocator *chunkAllocator; + ExecutionEngine *engine; std::vector<Chunk *> chunks; #if MM_DEBUG uint allocations[NumBins]; @@ -171,8 +172,8 @@ struct BlockAllocator { }; struct HugeItemAllocator { - HugeItemAllocator(ChunkAllocator *chunkAllocator) - : chunkAllocator(chunkAllocator) + HugeItemAllocator(ChunkAllocator *chunkAllocator, ExecutionEngine *engine) + : chunkAllocator(chunkAllocator), engine(engine) {} HeapItem *allocate(size_t size); @@ -189,6 +190,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 328797fb5e..df69f928ef 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -190,6 +190,8 @@ struct Chunk { void freeAll(); void resetBlackBits(); void collectGrayItems(QV4::MarkStack *markStack); + bool sweep(ExecutionEngine *engine); + void freeAll(ExecutionEngine *engine); void sortIntoBins(HeapItem **bins, uint nBins); }; 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<int, const QV4::CompiledData::Binding *> 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 *> 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 f60f148495..20f9b6439d 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -720,8 +720,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; @@ -1672,13 +1675,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/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index a7cafa1a93..8b0bd9d6ec 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -1276,11 +1276,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; @@ -1489,6 +1498,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)) { @@ -1588,8 +1601,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)); @@ -1717,6 +1730,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 a7b65c1048..6298dd9c22 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -191,6 +191,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/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 0f388cf7b7..1e4855f422 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -2402,6 +2402,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 85ee4d7b97..f381b4a010 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: diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 11fc3ceb44..7761eb4677 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<QQmlPropertyCache> 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<QV4::QmlContext *>(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<void> 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<void>(); + } + + 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(); @@ -1342,14 +1417,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 aa0165ec06..593d89e5d5 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(); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 128e37d51b..a4db62eebf 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); diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 4ee1ab1b76..dc41a16e3b 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(); @@ -1026,7 +1027,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)) { @@ -1034,11 +1035,17 @@ QObject *QQmlDelegateModel::object(int index, bool asynchronous) return 0; } - QObject *object = d->object(d->m_compositorGroup, index, asynchronous); - if (!object) - return 0; + 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 object; + return d->m_cache.at(it.cacheIndex)->incubationTask->status(); } QString QQmlDelegateModelPrivate::stringValue(Compositor::Group group, int index, const QString &name) @@ -2637,7 +2644,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<Compositor::Insert> inserts; Compositor::iterator it = model->m_compositor.find(group, index); @@ -3125,7 +3132,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); @@ -3134,7 +3141,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<QQuickPackage *>(object)) { QObject *part = package->part(m_part); @@ -3184,6 +3191,16 @@ void QQmlPartsModel::setWatchedRoles(const QList<QByteArray> &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<QObject *, QQuickPackage *>::const_iterator it = m_packaged.find(item); diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h index 186144d107..71179fd8be 100644 --- a/src/qml/types/qqmldelegatemodel_p.h +++ b/src/qml/types/qqmldelegatemodel_p.h @@ -54,6 +54,7 @@ #include <private/qtqmlglobal_p.h> #include <private/qqmllistcompositor_p.h> #include <private/qqmlobjectmodel_p.h> +#include <private/qqmlincubator_p.h> #include <QtCore/qabstractitemmodel.h> #include <QtCore/qstringlist.h> @@ -109,11 +110,12 @@ 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; void setWatchedRoles(const QList<QByteArray> &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 3759fe8667..6d061cdce4 100644 --- a/src/qml/types/qqmldelegatemodel_p_p.h +++ b/src/qml/types/qqmldelegatemodel_p_p.h @@ -256,7 +256,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); @@ -352,11 +352,12 @@ 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<QByteArray> watchedRoles() const { return m_watchedRoles; } void setWatchedRoles(const QList<QByteArray> &roles) override; + QQmlIncubator::Status incubationStatus(int index) override; int indexOf(QObject *item, QObject *objectContext) const override; 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..54da0867d4 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]; @@ -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 fc4c03874f..c98fe13a6b 100644 --- a/src/qml/types/qqmlobjectmodel_p.h +++ b/src/qml/types/qqmlobjectmodel_p.h @@ -52,6 +52,7 @@ // #include <private/qtqmlglobal_p.h> +#include <private/qqmlincubator_p.h> #include <QtQml/qqml.h> #include <QtCore/qobject.h> @@ -74,11 +75,13 @@ public: virtual int count() const = 0; virtual bool isValid() const = 0; - virtual QObject *object(int index, bool asynchronous=false) = 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) {} virtual QString stringValue(int, const QString &) = 0; virtual void setWatchedRoles(const QList<QByteArray> &roles) = 0; + virtual QQmlIncubator::Status incubationStatus(int index) = 0; virtual int indexOf(QObject *object, QObject *objectContext) const = 0; @@ -113,10 +116,11 @@ 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<QByteArray> &) override {} + QQmlIncubator::Status incubationStatus(int index) override; int indexOf(QObject *object, QObject *objectContext) const override; |