From 894211971ebf8b53ed3a78d771764021f7de2de6 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 27 Nov 2017 10:53:33 +0100 Subject: Add logging categories for GC statistics And use them to dump some useful information. This replaces the old QV4_MM_STATS environment variable and introduces the qt.qml.gc.statistics (for some stats at app exit) and qt.qml.gc.allocatorStats (for stats on each GC run) logging categories. Change-Id: I0a16b25b8663aa7dbfe2adae299d3d990e8e5554 Reviewed-by: Simon Hausmann --- src/qml/memory/qv4mm.cpp | 144 ++++++++++++++++++++--------------------------- src/qml/memory/qv4mm_p.h | 25 +++----- 2 files changed, 70 insertions(+), 99 deletions(-) (limited to 'src/qml') diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 538be0d16a..4f4124d505 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -44,6 +44,7 @@ #include "qv4qobjectwrapper_p.h" #include #include +#include #include #include "PageReservation.h" #include "PageAllocation.h" @@ -87,6 +88,11 @@ #define MIN_UNMANAGED_HEAPSIZE_GC_LIMIT std::size_t(128 * 1024) +Q_LOGGING_CATEGORY(lcGcStats, "qt.qml.gc.statistics") +Q_DECLARE_LOGGING_CATEGORY(lcGcStats) +Q_LOGGING_CATEGORY(lcGcAllocatorStats, "qt.qml.gc.allocatorStats") +Q_DECLARE_LOGGING_CATEGORY(lcGcAllocatorStats) + using namespace WTF; QT_BEGIN_NAMESPACE @@ -485,9 +491,9 @@ template struct StackAllocator; HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) { Q_ASSERT((size % Chunk::SlotSize) == 0); size_t slotsRequired = size >> Chunk::SlotSizeShift; -#if MM_DEBUG - ++allocations[bin]; -#endif + + if (allocationStats) + ++allocationStats[binForSlots(slotsRequired)]; HeapItem **last; @@ -616,36 +622,6 @@ void BlockAllocator::freeAll() } } -#if MM_DEBUG -void BlockAllocator::stats() { - DEBUG << "MM stats:"; - QString s; - for (int i = 0; i < 10; ++i) { - uint c = 0; - HeapItem *item = freeBins[i]; - while (item) { - ++c; - item = item->freeData.next; - } - s += QString::number(c) + QLatin1String(", "); - } - HeapItem *item = freeBins[NumBins - 1]; - uint c = 0; - while (item) { - ++c; - item = item->freeData.next; - } - s += QLatin1String("..., ") + QString::number(c); - DEBUG << "bins:" << s; - QString a; - for (int i = 0; i < 10; ++i) - a += QString::number(allocations[i]) + QLatin1String(", "); - a += QLatin1String("..., ") + QString::number(allocations[NumBins - 1]); - DEBUG << "allocs:" << a; - memset(allocations, 0, sizeof(allocations)); -} -#endif - HeapItem *HugeItemAllocator::allocate(size_t size) { Chunk *c = chunkAllocator->allocate(size); @@ -700,11 +676,15 @@ MemoryManager::MemoryManager(ExecutionEngine *engine) , m_weakValues(new PersistentValueStorage(engine)) , unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT) , aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC")) - , gcStats(!qEnvironmentVariableIsEmpty(QV4_MM_STATS)) + , gcStats(lcGcStats().isDebugEnabled()) + , gcCollectorStats(lcGcAllocatorStats().isDebugEnabled()) { #ifdef V4_USE_VALGRIND VALGRIND_CREATE_MEMPOOL(this, 0, true); #endif + memset(statistics.allocations, 0, sizeof(statistics.allocations)); + if (gcStats) + blockAllocator.allocationStats = statistics.allocations; } #ifndef QT_NO_DEBUG @@ -759,9 +739,6 @@ Heap::Base *MemoryManager::allocData(std::size_t size) runGC(); didRunGC = true; } -#ifdef DETAILED_MM_STATS - willAllocate(size); -#endif // DETAILED_MM_STATS Q_ASSERT(size >= Chunk::SlotSize); Q_ASSERT(size % Chunk::SlotSize == 0); @@ -925,9 +902,10 @@ bool MemoryManager::shouldRunGC() const size_t dumpBins(BlockAllocator *b, bool printOutput = true) { + const QLoggingCategory &stats = lcGcAllocatorStats(); size_t totalFragmentedSlots = 0; if (printOutput) - qDebug() << "Fragmentation map:"; + qDebug(stats) << "Fragmentation map:"; for (uint i = 0; i < BlockAllocator::NumBins; ++i) { uint nEntries = 0; HeapItem *h = b->freeBins[i]; @@ -937,7 +915,7 @@ size_t dumpBins(BlockAllocator *b, bool printOutput = true) h = h->freeData.next; } if (printOutput) - qDebug() << " number of entries in slot" << i << ":" << nEntries; + qDebug(stats) << " number of entries in slot" << i << ":" << nEntries; } SDUMP() << " large slot map"; HeapItem *h = b->freeBins[BlockAllocator::NumBins - 1]; @@ -947,7 +925,7 @@ size_t dumpBins(BlockAllocator *b, bool printOutput = true) } if (printOutput) - qDebug() << " total mem in bins" << totalFragmentedSlots*Chunk::SlotSize; + qDebug(stats) << " total mem in bins" << totalFragmentedSlots*Chunk::SlotSize; return totalFragmentedSlots*Chunk::SlotSize; } @@ -960,25 +938,30 @@ void MemoryManager::runGC() QScopedValueRollback gcBlocker(gcBlocked, true); - if (!gcStats) { -// uint oldUsed = allocator.usedMem(); + if (gcStats) { + statistics.maxReservedMem = qMax(statistics.maxReservedMem, getAllocatedMem()); + statistics.maxAllocatedMem = qMax(statistics.maxAllocatedMem, getUsedMem() + getLargeItemsMem()); + } + + if (!gcCollectorStats) { mark(); sweep(); -// DEBUG << "RUN GC: allocated:" << allocator.allocatedMem() << "used before" << oldUsed << "used now" << allocator.usedMem(); } else { bool triggeredByUnmanagedHeap = (unmanagedHeapSize > unmanagedHeapSizeGCLimit); size_t oldUnmanagedSize = unmanagedHeapSize; + const size_t totalMem = getAllocatedMem(); const size_t usedBefore = getUsedMem(); const size_t largeItemsBefore = getLargeItemsMem(); - qDebug() << "========== GC =========="; + const QLoggingCategory &stats = lcGcAllocatorStats(); + qDebug(stats) << "========== GC =========="; #ifndef QT_NO_DEBUG - qDebug() << " Triggered by alloc request of" << lastAllocRequestedSlots << "slots."; + qDebug(stats) << " Triggered by alloc request of" << lastAllocRequestedSlots << "slots."; #endif size_t oldChunks = blockAllocator.chunks.size(); - qDebug() << "Allocated" << totalMem << "bytes in" << oldChunks << "chunks"; - qDebug() << "Fragmented memory before GC" << (totalMem - usedBefore); + qDebug(stats) << "Allocated" << totalMem << "bytes in" << oldChunks << "chunks"; + qDebug(stats) << "Fragmented memory before GC" << (totalMem - usedBefore); dumpBins(&blockAllocator); QElapsedTimer t; @@ -991,29 +974,32 @@ void MemoryManager::runGC() qint64 sweepTime = t.elapsed(); if (triggeredByUnmanagedHeap) { - qDebug() << "triggered by unmanaged heap:"; - qDebug() << " old unmanaged heap size:" << oldUnmanagedSize; - qDebug() << " new unmanaged heap:" << unmanagedHeapSize; - qDebug() << " unmanaged heap limit:" << unmanagedHeapSizeGCLimit; + qDebug(stats) << "triggered by unmanaged heap:"; + qDebug(stats) << " old unmanaged heap size:" << oldUnmanagedSize; + qDebug(stats) << " new unmanaged heap:" << unmanagedHeapSize; + qDebug(stats) << " unmanaged heap limit:" << unmanagedHeapSizeGCLimit; } size_t memInBins = dumpBins(&blockAllocator); - qDebug() << "Marked object in" << markTime << "ms."; - qDebug() << "Sweeped object in" << sweepTime << "ms."; - qDebug() << "Used memory before GC:" << usedBefore; - qDebug() << "Used memory after GC:" << usedAfter; - qDebug() << "Freed up bytes:" << (usedBefore - usedAfter); - qDebug() << "Freed up chunks:" << (oldChunks - blockAllocator.chunks.size()); + qDebug(stats) << "Marked object in" << markTime << "ms."; + qDebug(stats) << "Sweeped object in" << sweepTime << "ms."; + qDebug(stats) << "Used memory before GC:" << usedBefore; + qDebug(stats) << "Used memory after GC:" << usedAfter; + qDebug(stats) << "Freed up bytes:" << (usedBefore - usedAfter); + qDebug(stats) << "Freed up chunks:" << (oldChunks - blockAllocator.chunks.size()); size_t lost = blockAllocator.allocatedMem() - memInBins - usedAfter; if (lost) - qDebug() << "!!!!!!!!!!!!!!!!!!!!! LOST MEM:" << lost << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; + qDebug(stats) << "!!!!!!!!!!!!!!!!!!!!! LOST MEM:" << lost << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; if (largeItemsBefore || largeItemsAfter) { - qDebug() << "Large item memory before GC:" << largeItemsBefore; - qDebug() << "Large item memory after GC:" << largeItemsAfter; - qDebug() << "Large item memory freed up:" << (largeItemsBefore - largeItemsAfter); + qDebug(stats) << "Large item memory before GC:" << largeItemsBefore; + qDebug(stats) << "Large item memory after GC:" << largeItemsAfter; + qDebug(stats) << "Large item memory freed up:" << (largeItemsBefore - largeItemsAfter); } - qDebug() << "======== End GC ========"; + qDebug(stats) << "======== End GC ========"; } + if (gcStats) + statistics.maxUsedMem = qMax(statistics.maxUsedMem, getUsedMem() + getLargeItemsMem()); + if (aggressiveGC) { // ensure we don't 'loose' any memory Q_ASSERT(blockAllocator.allocatedMem() == getUsedMem() + dumpBins(&blockAllocator, false)); @@ -1039,6 +1025,8 @@ MemoryManager::~MemoryManager() { delete m_persistentValues; + dumpStats(); + sweep(/*lastSweep*/true); blockAllocator.freeAll(); hugeItemAllocator.freeAll(); @@ -1054,30 +1042,20 @@ MemoryManager::~MemoryManager() void MemoryManager::dumpStats() const { -#ifdef DETAILED_MM_STATS - std::cerr << "=================" << std::endl; - std::cerr << "Allocation stats:" << std::endl; - std::cerr << "Requests for each chunk size:" << std::endl; - for (int i = 0; i < allocSizeCounters.size(); ++i) { - if (unsigned count = allocSizeCounters[i]) { - std::cerr << "\t" << (i << 4) << " bytes chunks: " << count << std::endl; - } - } -#endif // DETAILED_MM_STATS -} + if (!gcStats) + return; -#ifdef DETAILED_MM_STATS -void MemoryManager::willAllocate(std::size_t size) -{ - unsigned alignedSize = (size + 15) >> 4; - QVector &counters = allocSizeCounters; - if ((unsigned) counters.size() < alignedSize + 1) - counters.resize(alignedSize + 1); - counters[alignedSize]++; + const QLoggingCategory &stats = lcGcStats(); + qDebug(stats) << "Qml GC memory allocation statistics:"; + qDebug(stats) << "Total memory allocated:" << statistics.maxReservedMem; + qDebug(stats) << "Max memory used before a GC run:" << statistics.maxAllocatedMem; + qDebug(stats) << "Max memory used after a GC run:" << statistics.maxUsedMem; + qDebug(stats) << "Requests for different item sizes:"; + for (int i = 1; i < BlockAllocator::NumBins - 1; ++i) + qDebug(stats) << " <" << (i << Chunk::SlotSizeShift) << " bytes: " << statistics.allocations[i]; + qDebug(stats) << " >=" << ((BlockAllocator::NumBins - 1) << Chunk::SlotSizeShift) << " bytes: " << statistics.allocations[BlockAllocator::NumBins - 1]; } -#endif // DETAILED_MM_STATS - void MemoryManager::collectFromJSStack() const { Value *v = engine->jsStackBase; diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index e3cccb6aa0..aa8d13de8c 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -58,8 +58,6 @@ #include #include -//#define DETAILED_MM_STATS - #define QV4_MM_MAXBLOCK_SHIFT "QV4_MM_MAXBLOCK_SHIFT" #define QV4_MM_MAX_CHUNK_SIZE "QV4_MM_MAX_CHUNK_SIZE" #define QV4_MM_STATS "QV4_MM_STATS" @@ -121,9 +119,6 @@ struct BlockAllocator { : chunkAllocator(chunkAllocator), engine(engine) { memset(freeBins, 0, sizeof(freeBins)); -#if MM_DEBUG - memset(allocations, 0, sizeof(allocations)); -#endif } enum { NumBins = 8 }; @@ -132,10 +127,6 @@ struct BlockAllocator { return nSlots >= NumBins ? NumBins - 1 : nSlots; } -#if MM_DEBUG - void stats(); -#endif - HeapItem *allocate(size_t size, bool forceAllocation = false); size_t totalSlots() const { @@ -163,9 +154,7 @@ struct BlockAllocator { ChunkAllocator *chunkAllocator; ExecutionEngine *engine; std::vector chunks; -#if MM_DEBUG - uint allocations[NumBins]; -#endif + uint *allocationStats = nullptr; }; struct HugeItemAllocator { @@ -449,10 +438,6 @@ protected: Heap::Base *allocData(std::size_t size); Heap::Object *allocObjectWithMemberData(const QV4::VTable *vtable, uint nMembers); -#ifdef DETAILED_MM_STATS - void willAllocate(std::size_t size); -#endif // DETAILED_MM_STATS - private: void collectFromJSStack() const; void mark(); @@ -475,6 +460,14 @@ public: bool gcBlocked = false; bool aggressiveGC = false; bool gcStats = false; + bool gcCollectorStats = false; + + struct { + size_t maxReservedMem = 0; + size_t maxAllocatedMem = 0; + size_t maxUsedMem = 0; + uint allocations[BlockAllocator::NumBins]; + } statistics; }; } -- cgit v1.2.3 From f25203296d4e29b5e7e4000950f76045a5a832bd Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 29 Nov 2017 14:33:16 +0100 Subject: Fix stack use after scope when calling overloaded constructors This is a regression of commit 0d7dd44d781a73c4bd065c0660d4a2f824a86f05 that ended up moving the stack-local storage into a scope that's too close. Pointers into the storage are stored in methodArgTypes and used throughput the surrounding while loop. Covered by tst_QJSEngine::newQMetaObject when run with ASAN. Change-Id: I44928d67ebdb0b5bdcf99ddd8193f692c2a94539 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4qobjectwrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/qml') diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 8d96f5b480..326381f38d 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -1968,10 +1968,10 @@ ReturnedValue QMetaObjectWrapper::callOverloadedConstructor(QV4::ExecutionEngine for (int i = 0; i < numberOfConstructors; i++) { const QQmlPropertyData & attempt = d()->constructors[i]; + QQmlMetaObject::ArgTypeStorage storage; int methodArgumentCount = 0; int *methodArgTypes = 0; if (attempt.hasArguments()) { - QQmlMetaObject::ArgTypeStorage storage; int *args = object.constructorParameterTypes(attempt.coreIndex(), &storage, 0); if (!args) // Must be an unknown argument continue; -- cgit v1.2.3 From 52bc4fbfbae6aa1569dc134dd103e966f04bc2e6 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 11 Dec 2017 12:44:47 +0100 Subject: Use potentially intercepted URL as ID for compilation units We generally have to pass a URL and a file name everywhere because the logical URL might be something else than the actual file being loaded. For example a QQmlFileSelector might modify the URL to be loaded for a specific file. This resulting URL, however, should not be used to resolve further URLs defined in the file loaded that way. As we need to access QQmlTypeLoader::m_url as string more often now, cache it and avoid frequent translations between QUrl and QString. Furthermore, QQmlDataBlob's URLs are changed to follow the same semantics. The finalUrl is the one that should be used to resolve further URLs, the url is the one used to load the content, and subject to any redirects or interceptions. This changes the semantics of URL redirects. Previously a redirected URL was used as the base URL for furher URL resolution. This doesn't work because redirection occurs after interception and interception should not influence the resolution of further URLs. We now use the original URL as base URL for resolution of further URLs and rely on the server to redirect those, too. Task-number: QTBUG-61209 Change-Id: I93822f820bed2515995de3cb118099218b510ca4 Reviewed-by: Michael Brasser --- src/qml/compiler/qqmlirbuilder.cpp | 7 ++- src/qml/compiler/qqmlirbuilder_p.h | 6 +-- src/qml/compiler/qqmltypecompiler.cpp | 5 ++- src/qml/compiler/qv4codegen.cpp | 4 ++ src/qml/compiler/qv4codegen_p.h | 8 ++-- src/qml/compiler/qv4compileddata.cpp | 1 + src/qml/compiler/qv4compileddata_p.h | 22 ++++++++- src/qml/compiler/qv4compiler.cpp | 2 + src/qml/compiler/qv4jsir.cpp | 5 +++ src/qml/compiler/qv4jsir_p.h | 2 + src/qml/jsruntime/qv4engine.cpp | 4 +- src/qml/jsruntime/qv4function_p.h | 1 + src/qml/jsruntime/qv4functionobject.cpp | 2 +- src/qml/jsruntime/qv4script.cpp | 14 +++--- src/qml/jsruntime/qv4script_p.h | 6 ++- src/qml/qml/qqmlcomponent.cpp | 2 +- src/qml/qml/qqmlcontext.cpp | 4 +- src/qml/qml/qqmlincubator.cpp | 2 +- src/qml/qml/qqmlobjectcreator.cpp | 5 ++- src/qml/qml/qqmltypeloader.cpp | 80 +++++++++++++++++++-------------- src/qml/qml/qqmltypeloader_p.h | 2 + 21 files changed, 124 insertions(+), 60 deletions(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 092c0020fa..3974f9ae4e 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1552,8 +1552,10 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, Binding return bindingPtr; } -JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, QV4::IR::Module *jsModule, QQmlJS::Engine *jsEngine, - QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, const QV4::Compiler::StringTableGenerator *stringPool) +JSCodeGen::JSCodeGen(const QString &fileName, const QString &finalUrl, const QString &sourceCode, + QV4::IR::Module *jsModule, QQmlJS::Engine *jsEngine, + QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, + const QV4::Compiler::StringTableGenerator *stringPool) : QQmlJS::Codegen(/*strict mode*/false) , sourceCode(sourceCode) , jsEngine(jsEngine) @@ -1568,6 +1570,7 @@ JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, QV4::IR { _module = jsModule; _module->setFileName(fileName); + _module->setFinalUrl(finalUrl); _fileNameIsUrl = true; } diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index a6ff18927d..8f8a6d090e 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -582,9 +582,9 @@ struct Q_QML_EXPORT PropertyResolver struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QQmlJS::Codegen { - JSCodeGen(const QString &fileName, const QString &sourceCode, QV4::IR::Module *jsModule, - QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, - const QV4::Compiler::StringTableGenerator *stringPool); + JSCodeGen(const QString &fileName, const QString &finalUrl, const QString &sourceCode, + QV4::IR::Module *jsModule, QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, + QQmlTypeNameCache *imports, const QV4::Compiler::StringTableGenerator *stringPool); struct IdMapping { diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index fab865081a..568ad4af89 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -140,7 +140,10 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile() sss.scan(); } - QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, typeNameCache, &document->jsGenerator.stringTable); + QmlIR::JSCodeGen v4CodeGenerator(typeData->urlString(), typeData->finalUrlString(), + document->code, &document->jsModule, + &document->jsParserEngine, document->program, + typeNameCache, &document->jsGenerator.stringTable); QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator); if (!jsCodeGen.generateCodeForComponents()) return nullptr; diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 1e98d1167b..b07e9f55f5 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -489,6 +489,7 @@ Codegen::Codegen(bool strict) } void Codegen::generateFromProgram(const QString &fileName, + const QString &finalUrl, const QString &sourceCode, Program *node, QV4::IR::Module *module, @@ -501,6 +502,7 @@ void Codegen::generateFromProgram(const QString &fileName, _env = 0; _module->setFileName(fileName); + _module->setFinalUrl(finalUrl); ScanFunctions scan(this, sourceCode, mode); scan(node); @@ -511,12 +513,14 @@ void Codegen::generateFromProgram(const QString &fileName, } void Codegen::generateFromFunctionExpression(const QString &fileName, + const QString &finalUrl, const QString &sourceCode, AST::FunctionExpression *ast, QV4::IR::Module *module) { _module = module; _module->setFileName(fileName); + _module->setFinalUrl(finalUrl); _env = 0; ScanFunctions scan(this, sourceCode, GlobalCode); diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 1cbe6949a1..a08b9c1d68 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -86,15 +86,17 @@ public: }; void generateFromProgram(const QString &fileName, + const QString &finalUrl, const QString &sourceCode, AST::Program *ast, QV4::IR::Module *module, CompilationMode mode = GlobalCode, const QStringList &inheritedLocals = QStringList()); void generateFromFunctionExpression(const QString &fileName, - const QString &sourceCode, - AST::FunctionExpression *ast, - QV4::IR::Module *module); + const QString &finalUrl, + const QString &sourceCode, + AST::FunctionExpression *ast, + QV4::IR::Module *module); protected: enum Format { ex, cx, nx }; diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 294eaa25f5..f54a1b0c41 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -502,6 +502,7 @@ Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument) if (jsUnit->sourceFileIndex == quint32(0) || jsUnit->stringAt(jsUnit->sourceFileIndex) != irDocument->jsModule.fileName) { ensureWritableUnit(); jsUnit->sourceFileIndex = stringTable.registerString(irDocument->jsModule.fileName); + jsUnit->finalUrlIndex = stringTable.registerString(irDocument->jsModule.finalUrl); } // Collect signals that have had a change in signature (from onClicked to onClicked(mouse) for example) diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 440dc3e013..188a571394 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -72,7 +72,7 @@ QT_BEGIN_NAMESPACE // Bump this whenever the compiler data structures change in an incompatible way. -#define QV4_DATA_STRUCTURE_VERSION 0x13 +#define QV4_DATA_STRUCTURE_VERSION 0x14 class QIODevice; class QQmlPropertyCache; @@ -661,6 +661,7 @@ struct Unit LEUInt32 offsetToJSClassTable; LEInt32 indexOfRootFunction; LEUInt32 sourceFileIndex; + LEUInt32 finalUrlIndex; /* QML specific fields */ LEUInt32 nImports; @@ -668,6 +669,8 @@ struct Unit LEUInt32 nObjects; LEUInt32 offsetToObjects; + LEUInt32 padding; + const Import *importAt(int idx) const { return reinterpret_cast((reinterpret_cast(this)) + offsetToImports + idx * sizeof(Import)); } @@ -732,7 +735,7 @@ struct Unit } }; -static_assert(sizeof(Unit) == 144, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); +static_assert(sizeof(Unit) == 152, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); struct TypeReference { @@ -842,14 +845,29 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase, public ExecutionEngine *engine; QQmlEnginePrivate *qmlEngine; // only used in QML environment for composite types, not in plain QJSEngine case. + // url() and fileName() shall be used to load the actual QML/JS code or to show errors or + // warnings about that code. They include any potential URL interceptions and thus represent the + // "physical" location of the code. + // + // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code + // They are _not_ intercepted and thus represent the "logical" name for the code. + QString fileName() const { return data->stringAt(data->sourceFileIndex); } + QString finalUrlString() const { return data->stringAt(data->finalUrlIndex); } QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; } + QUrl finalUrl() const + { + if (m_finalUrl.isNull) + m_finalUrl = QUrl(finalUrlString()); + return m_finalUrl; + } QV4::Lookup *runtimeLookups; QV4::Value *runtimeRegularExpressions; QV4::InternalClass **runtimeClasses; QVector runtimeFunctions; mutable QQmlNullableValue m_url; + mutable QQmlNullableValue m_finalUrl; // QML specific fields QQmlPropertyCacheVector propertyCaches; diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 3abdd0370f..0dc40d9698 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -212,6 +212,7 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, IR::ExprList *arg QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorOption option) { registerString(irModule->fileName); + registerString(irModule->finalUrl); for (QV4::IR::Function *f : qAsConst(irModule->functions)) { registerString(*f->name); for (int i = 0; i < f->formals.size(); ++i) @@ -427,6 +428,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp } unit.indexOfRootFunction = -1; unit.sourceFileIndex = getStringId(irModule->fileName); + unit.finalUrlIndex = getStringId(irModule->finalUrl); unit.sourceTimeStamp = irModule->sourceTimeStamp.isValid() ? irModule->sourceTimeStamp.toMSecsSinceEpoch() : 0; unit.nImports = 0; unit.offsetToImports = 0; diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index 0b0ed391fb..a8e18784c7 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -351,6 +351,11 @@ void Module::setFileName(const QString &name) fileName = name; } +void Module::setFinalUrl(const QString &url) +{ + finalUrl = url; +} + Function::Function(Module *module, Function *outer, const QString &name) : module(module) , pool(&module->pool) diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 5c8e79f404..9980a21912 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -952,6 +952,7 @@ struct Q_QML_PRIVATE_EXPORT Module { QVector functions; Function *rootFunction; QString fileName; + QString finalUrl; QDateTime sourceTimeStamp; bool isQmlModule; // implies rootFunction is always 0 uint unitFlags; // flags merged into CompiledData::Unit::flags @@ -977,6 +978,7 @@ struct Q_QML_PRIVATE_EXPORT Module { ~Module(); void setFileName(const QString &name); + void setFinalUrl(const QString &url); }; struct BasicBlock { diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 917f6bffc5..a584c2731f 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -884,14 +884,14 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) while (c) { CallContext *callCtx = c->asCallContext(); if (callCtx && callCtx->d()->v4Function) { - base.setUrl(callCtx->d()->v4Function->sourceFile()); + base = callCtx->d()->v4Function->finalUrl(); break; } c = parentContext(c); } if (base.isEmpty() && globalCode) - base.setUrl(globalCode->sourceFile()); + base = globalCode->finalUrl(); if (base.isEmpty()) return src; diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 54d0528c42..b212b3d027 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -84,6 +84,7 @@ struct Q_QML_EXPORT Function { return compilationUnit->runtimeStrings[compiledFunction->nameIndex]; } inline QString sourceFile() const { return compilationUnit->fileName(); } + inline QUrl finalUrl() const { return compilationUnit->finalUrl(); } inline bool usesArgumentsObject() const { return compiledFunction->flags & CompiledData::Function::UsesArgumentsObject; } inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 9eb9d2ad36..63396998fa 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -229,7 +229,7 @@ void FunctionCtor::construct(const Managed *that, Scope &scope, CallData *callDa IR::Module module(scope.engine->debugger() != 0); QQmlJS::RuntimeCodegen cg(scope.engine, f->strictMode()); - cg.generateFromFunctionExpression(QString(), function, fe, &module); + cg.generateFromFunctionExpression(QString(), QString(), function, fe, &module); Compiler::JSUnitGenerator jsGenerator(&module); QScopedPointer isel(scope.engine->iselFactory->create(QQmlEnginePrivate::get(scope.engine), scope.engine->executableAllocator, &module, &jsGenerator)); diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 62145f36cc..9d1d5e2589 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -127,7 +127,8 @@ void Script::parse() } RuntimeCodegen cg(v4, strictMode); - cg.generateFromProgram(sourceFile, sourceCode, program, &module, QQmlJS::Codegen::EvalCode, inheritedLocals); + cg.generateFromProgram(sourceFile, sourceFile, sourceCode, program, &module, + QQmlJS::Codegen::EvalCode, inheritedLocals); if (v4->hasException) return; @@ -186,7 +187,10 @@ Function *Script::function() return vmFunction; } -QQmlRefPointer Script::precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList *reportedErrors, QQmlJS::Directives *directivesCollector) +QQmlRefPointer Script::precompile( + IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, + const QString &fileName, const QString &finalUrl, const QString &source, + QList *reportedErrors, QQmlJS::Directives *directivesCollector) { using namespace QQmlJS; using namespace QQmlJS::AST; @@ -205,12 +209,12 @@ QQmlRefPointer Script::precompile(IR::Module const auto diagnosticMessages = parser.diagnosticMessages(); for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) { if (m.isWarning()) { - qWarning("%s:%d : %s", qPrintable(url.toString()), m.loc.startLine, qPrintable(m.message)); + qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message)); continue; } QQmlError error; - error.setUrl(url); + error.setUrl(QUrl(fileName)); error.setDescription(m.message); error.setLine(m.loc.startLine); error.setColumn(m.loc.startColumn); @@ -231,7 +235,7 @@ QQmlRefPointer Script::precompile(IR::Module } QQmlJS::Codegen cg(/*strict mode*/false); - cg.generateFromProgram(url.toString(), source, program, module, QQmlJS::Codegen::EvalCode); + cg.generateFromProgram(fileName, finalUrl, source, program, module, QQmlJS::Codegen::EvalCode); errors = cg.qmlErrors(); if (!errors.isEmpty()) { if (reportedErrors) diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index 4ebe2dd609..55a349b5fc 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -139,8 +139,10 @@ struct Q_QML_EXPORT Script { Function *function(); - static QQmlRefPointer precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, - QList *reportedErrors = 0, QQmlJS::Directives *directivesCollector = 0); + static QQmlRefPointer precompile( + IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, + const QString &fileName, const QString &finalUrl, const QString &source, + QList *reportedErrors = 0, QQmlJS::Directives *directivesCollector = 0); static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext); }; diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 7f1121c1e1..e872b1d92e 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -561,7 +561,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QV4::CompiledData::CompilationU Q_D(QQmlComponent); d->compilationUnit = compilationUnit; d->start = start; - d->url = compilationUnit->url(); + d->url = compilationUnit->finalUrl(); d->progress = 1.0; } diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index 37cb328b36..59e2c83a63 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -845,14 +845,14 @@ QV4::IdentifierHash &QQmlContextData::detachedPropertyNames() QUrl QQmlContextData::url() const { if (typeCompilationUnit) - return typeCompilationUnit->url(); + return typeCompilationUnit->finalUrl(); return baseUrl; } QString QQmlContextData::urlString() const { if (typeCompilationUnit) - return typeCompilationUnit->fileName(); + return typeCompilationUnit->finalUrlString(); return baseUrlString; } diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp index 6d0e4b915a..93bb67de20 100644 --- a/src/qml/qml/qqmlincubator.cpp +++ b/src/qml/qml/qqmlincubator.cpp @@ -272,7 +272,7 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i) if (!compilationUnit) return; - QML_MEMORY_SCOPE_URL(compilationUnit->url()); + QML_MEMORY_SCOPE_URL(compilationUnit->finalUrl()); QExplicitlySharedDataPointer protectThis(this); diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 3663b06d55..9c6630190f 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -445,7 +445,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QString string = binding->valueAsString(qmlUnit); // Encoded dir-separators defeat QUrl processing - decode them first string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive); - QUrl value = string.isEmpty() ? QUrl() : compilationUnit->url().resolved(QUrl(string)); + QUrl value = string.isEmpty() ? QUrl() : compilationUnit->finalUrl().resolved(QUrl(string)); // Apply URL interceptor if (engine->urlInterceptor()) value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString); @@ -643,7 +643,8 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const } else if (property->propType() == qMetaTypeId >()) { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String); QString urlString = binding->valueAsString(qmlUnit); - QUrl u = urlString.isEmpty() ? QUrl() : compilationUnit->url().resolved(QUrl(urlString)); + QUrl u = urlString.isEmpty() ? QUrl() + : compilationUnit->finalUrl().resolved(QUrl(urlString)); QList value; value.append(u); property->writeProperty(_qobject, &value, propertyWriteFlags); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index f3077f673b..19e57fbdba 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -356,8 +356,10 @@ qreal QQmlDataBlob::progress() const } /*! -Returns the blob url passed to the constructor. If a network redirect -happens while fetching the data, this url remains the same. +Returns the physical url of the data. Initially this is the same as +finalUrl(), but if a network redirect happens while fetching the data, this url +is updated to reflect the new location. Also, if a URL interceptor is set, it +will work on this URL and leave finalUrl() alone. \sa finalUrl() */ @@ -366,16 +368,25 @@ QUrl QQmlDataBlob::url() const return m_url; } +QString QQmlDataBlob::urlString() const +{ + if (m_urlString.isEmpty()) + m_urlString = m_url.toString(); + + return m_urlString; +} + /*! -Returns the final url of the data. Initially this is the same as -url(), but if a network redirect happens while fetching the data, this url -is updated to reflect the new location. +Returns the logical URL to be used for resolving further URLs referred to in +the code. -May only be called from the load thread, or after the blob isCompleteOrError(). +This is the blob url passed to the constructor. If a network redirect +happens while fetching the data, this url remains the same. + +\sa url() */ QUrl QQmlDataBlob::finalUrl() const { - Q_ASSERT(isCompleteOrError() || (m_typeLoader && m_typeLoader->m_thread->isThisThread())); return m_finalUrl; } @@ -384,7 +395,6 @@ Returns the finalUrl() as a string. */ QString QQmlDataBlob::finalUrlString() const { - Q_ASSERT(isCompleteOrError() || (m_typeLoader && m_typeLoader->m_thread->isThisThread())); if (m_finalUrlString.isEmpty()) m_finalUrlString = m_finalUrl.toString(); @@ -433,7 +443,7 @@ void QQmlDataBlob::setError(const QList &errors) m_data.setStatus(Error); if (dumpErrors()) { - qWarning().nospace() << "Errors for " << m_finalUrl.toString(); + qWarning().nospace() << "Errors for " << urlString(); for (int ii = 0; ii < errors.count(); ++ii) qWarning().nospace() << " " << qPrintable(errors.at(ii).toString()); } @@ -472,7 +482,7 @@ void QQmlDataBlob::setError(const QString &description) { QQmlError e; e.setDescription(description); - e.setUrl(finalUrl()); + e.setUrl(url()); setError(e); } @@ -537,7 +547,7 @@ void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError) Q_UNUSED(networkError); QQmlError error; - error.setUrl(m_finalUrl); + error.setUrl(m_url); const char *errorString = 0; switch (networkError) { @@ -654,7 +664,7 @@ void QQmlDataBlob::tryDone() addref(); #ifdef DATABLOB_DEBUG - qWarning("QQmlDataBlob::done() %s", qPrintable(url().toString())); + qWarning("QQmlDataBlob::done() %s", qPrintable(urlString())); #endif done(); @@ -893,7 +903,7 @@ void QQmlTypeLoaderThread::callCompletedMain(QQmlDataBlob *b) { QML_MEMORY_SCOPE_URL(b->url()); #ifdef DATABLOB_DEBUG - qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->url().toString())); + qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->urlString())); #endif b->completed(); b->release(); @@ -903,7 +913,7 @@ void QQmlTypeLoaderThread::callDownloadProgressChangedMain(QQmlDataBlob *b, qrea { #ifdef DATABLOB_DEBUG qWarning("QQmlTypeLoaderThread: %s downloadProgressChanged(%f) callback", - qPrintable(b->url().toString()), p); + qPrintable(b->urlString()), p); #endif b->downloadProgressChanged(p); b->release(); @@ -1037,7 +1047,7 @@ template void QQmlTypeLoader::doLoad(const Loader &loader, QQmlDataBlob *blob, Mode mode) { #ifdef DATABLOB_DEBUG - qWarning("QQmlTypeLoader::doLoad(%s): %s thread", qPrintable(blob->m_url.toString()), + qWarning("QQmlTypeLoader::doLoad(%s): %s thread", qPrintable(blob->urlString()), m_thread->isThisThread()?"Compile":"Engine"); #endif blob->startLoading(); @@ -1159,7 +1169,7 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob) } #ifdef DATABLOB_DEBUG - qWarning("QQmlDataBlob: requested %s", qPrintable(blob->url().toString())); + qWarning("QQmlDataBlob: requested %s", qPrintable(blob->urlString())); #endif // DATABLOB_DEBUG #endif // qml_network } @@ -1185,14 +1195,15 @@ void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply) QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); if (redirect.isValid()) { QUrl url = reply->url().resolved(redirect.toUrl()); - blob->m_finalUrl = url; + blob->m_url = url; + blob->m_urlString.clear(); QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(url)); QObject *nrp = m_thread->networkReplyProxy(); QObject::connect(reply, SIGNAL(finished()), nrp, SLOT(finished())); m_networkReplies.insert(reply, blob); #ifdef DATABLOB_DEBUG - qWarning("QQmlDataBlob: redirected to %s", qPrintable(blob->m_finalUrl.toString())); + qWarning("QQmlDataBlob: redirected to %s", qPrintable(blob->urlString())); #endif return; } @@ -1348,7 +1359,7 @@ bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QV4::CompiledData: bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::CompiledData::Import *import, QList *errors) { - QString qmldirIdentifier = data->url().toString(); + QString qmldirIdentifier = data->urlString(); QString qmldirUrl = qmldirIdentifier.left(qmldirIdentifier.lastIndexOf(QLatin1Char('/')) + 1); typeLoader()->setQmldirContent(qmldirIdentifier, data->content()); @@ -2104,7 +2115,7 @@ bool QQmlTypeData::tryLoadFromDiskCache() { QString error; if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), v4->iselFactory.data(), &error)) { - qCDebug(DBG_DISK_CACHE) << "Error loading" << url().toString() << "from disk cache:" << error; + qCDebug(DBG_DISK_CACHE) << "Error loading" << urlString() << "from disk cache:" << error; return false; } } @@ -2224,10 +2235,10 @@ void QQmlTypeData::done() if (script.script->isError()) { QList errors = script.script->errors(); QQmlError error; - error.setUrl(finalUrl()); + error.setUrl(url()); error.setLine(script.location.line); error.setColumn(script.location.column); - error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString())); + error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString())); errors.prepend(error); setError(errors); return; @@ -2244,7 +2255,7 @@ void QQmlTypeData::done() QList errors = type.typeData->errors(); QQmlError error; - error.setUrl(finalUrl()); + error.setUrl(url()); error.setLine(type.location.line); error.setColumn(type.location.column); error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName)); @@ -2263,7 +2274,7 @@ void QQmlTypeData::done() QList errors = type.typeData->errors(); QQmlError error; - error.setUrl(finalUrl()); + error.setUrl(url()); error.setLine(type.location.line); error.setColumn(type.location.column); error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName)); @@ -2293,7 +2304,7 @@ void QQmlTypeData::done() // verify if any dependencies changed if we're using a cache if (m_document.isNull() && !m_compiledData->verifyChecksum(dependencyHasher)) { - qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->url().toString(); + qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->fileName(); if (!loadFromSource()) return; m_backupSourceCode = SourceCodeData(); @@ -2458,7 +2469,7 @@ bool QQmlTypeData::loadFromSource() errors.reserve(compiler.errors.count()); for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) { QQmlError e; - e.setUrl(finalUrl()); + e.setUrl(url()); e.setLine(msg.loc.startLine); e.setColumn(msg.loc.startColumn); e.setDescription(msg.message); @@ -2475,7 +2486,8 @@ void QQmlTypeData::restoreIR(QQmlRefPointer m_document.reset(new QmlIR::Document(isDebugging())); QmlIR::IRLoader loader(unit->data, m_document.data()); loader.load(); - m_document->jsModule.setFileName(finalUrlString()); + m_document->jsModule.setFileName(urlString()); + m_document->jsModule.setFinalUrl(finalUrlString()); m_document->javaScriptCompilationUnit = unit; continueLoadFromIR(); } @@ -2598,7 +2610,7 @@ void QQmlTypeData::compile(const QQmlRefPointer &typeNameCach // ignore error, keep using the in-memory compilation unit. } } else { - qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->url().toString() << "to disk:" << errorString; + qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->fileName() << "to disk:" << errorString; } } } @@ -2969,7 +2981,7 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) initializeFromCompilationUnit(unit); return; } else { - qCDebug(DBG_DISK_CACHE()) << "Error loading" << url().toString() << "from disk cache:" << error; + qCDebug(DBG_DISK_CACHE()) << "Error loading" << urlString() << "from disk cache:" << error; } } @@ -2987,7 +2999,9 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) QmlIR::ScriptDirectivesCollector collector(&irUnit.jsParserEngine, &irUnit.jsGenerator); QList errors; - QQmlRefPointer unit = QV4::Script::precompile(&irUnit.jsModule, &irUnit.jsGenerator, v4, finalUrl(), source, &errors, &collector); + QQmlRefPointer unit = QV4::Script::precompile( + &irUnit.jsModule, &irUnit.jsGenerator, v4, urlString(), finalUrlString(), + source, &errors, &collector); // No need to addref on unit, it's initial refcount is 1 source.clear(); if (!errors.isEmpty()) { @@ -3011,7 +3025,7 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) if (!disableDiskCache() || forceDiskCache()) { QString errorString; if (!unit->saveToDisk(url(), &errorString)) { - qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->url().toString() << "to disk:" << errorString; + qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->fileName() << "to disk:" << errorString; } } @@ -3035,10 +3049,10 @@ void QQmlScriptBlob::done() if (script.script->isError()) { QList errors = script.script->errors(); QQmlError error; - error.setUrl(finalUrl()); + error.setUrl(url()); error.setLine(script.location.line); error.setColumn(script.location.column); - error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString())); + error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString())); errors.prepend(error); setError(errors); return; diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 22ac61968f..ab32bac7b2 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -129,6 +129,7 @@ public: qreal progress() const; QUrl url() const; + QString urlString() const; QUrl finalUrl() const; QString finalUrlString() const; @@ -207,6 +208,7 @@ private: QUrl m_url; QUrl m_finalUrl; + mutable QString m_urlString; mutable QString m_finalUrlString; // List of QQmlDataBlob's that are waiting for me to complete. -- cgit v1.2.3 From 78a5add79497300802c2152b5bf561b6bef305f1 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Thu, 21 Dec 2017 11:03:53 -0600 Subject: Remove extra addref The code was previously updated to use QQmlRefPointer, so we shouldn't explicitly addref. This allows more components to be correctly trimmed when needed. Change-Id: I15a961cfc456eeab5c791c8a282cc7e2852912cb Reviewed-by: Lars Knoll --- src/qml/types/qqmldelegatemodel.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/qml') diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 9dd82494ca..2f8a70d63b 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -1969,7 +1969,6 @@ void QQmlDelegateModelItem::incubateObject( QQmlComponentPrivate *componentPriv = QQmlComponentPrivate::get(component); incubatorPriv->compilationUnit = componentPriv->compilationUnit; - incubatorPriv->compilationUnit->addref(); incubatorPriv->enginePriv = enginePriv; incubatorPriv->creator.reset(new QQmlObjectCreator(context, componentPriv->compilationUnit, componentPriv->creationContext)); incubatorPriv->subComponentToCreate = componentPriv->start; -- cgit v1.2.3 From 8836896dff45fe1d21736835845e36d03763117f Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 12 Dec 2017 11:16:45 +0100 Subject: Allow QQmlComponent::loadUrl() to load absolute URLs with relative paths Currently, QQmlTypeLoader::getType() will assert if passed a relative URL, because it needs absolute URLs in order to ensure that it can use them as keys for its cache. After dc6b73390 was merged, URLs like QUrl::fromLocalFile("main.qml") (which are currently used in examples of how to load a QQmlComponent) started causing the assertion to fail. As mentioned in the comments of the bug report, some patches have already been applied to QQmlComponent's QString-based constructors, but both the constructors taking a QUrl and loadUrl() itself need fixing. This patch puts the fix into loadUrl() (the constructors call this function) so that every operation involving URLs is successful when using the documented methods. Task-number: QTBUG-58837 Change-Id: Ib54ca52eddce6e7781cf96015f4c15af604233d3 Reviewed-by: David Faure --- src/qml/doc/src/includes/qqmlcomponent.qdoc | 58 +++++++++++++++++++++++++++++ src/qml/qml/qqmlcomponent.cpp | 32 +++++++++------- 2 files changed, 77 insertions(+), 13 deletions(-) create mode 100644 src/qml/doc/src/includes/qqmlcomponent.qdoc (limited to 'src/qml') diff --git a/src/qml/doc/src/includes/qqmlcomponent.qdoc b/src/qml/doc/src/includes/qqmlcomponent.qdoc new file mode 100644 index 0000000000..0eb60ed743 --- /dev/null +++ b/src/qml/doc/src/includes/qqmlcomponent.qdoc @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [url-note] +Ensure that the URL provided is full and correct, in particular, use +\l QUrl::fromLocalFile() when loading a file from the local filesystem. + +Relative paths will be resolved against the engine's +\l {QQmlEngine::baseUrl}{baseUrl()}, which is the current working directory +unless specified. +//! [url-note] diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index e872b1d92e..4da6b7958c 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -496,8 +496,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QObject *parent) Create a QQmlComponent from the given \a url and give it the specified \a parent and \a engine. - Ensure that the URL provided is full and correct, in particular, use - \l QUrl::fromLocalFile() when loading a file from the local filesystem. + \include qqmlcomponent.qdoc url-note \sa loadUrl() */ @@ -511,8 +510,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *paren specified \a parent and \a engine. If \a mode is \l Asynchronous, the component will be loaded and compiled asynchronously. - Ensure that the URL provided is full and correct, in particular, use - \l QUrl::fromLocalFile() when loading a file from the local filesystem. + \include qqmlcomponent.qdoc url-note \sa loadUrl() */ @@ -548,7 +546,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName, : QQmlComponent(engine, parent) { Q_D(QQmlComponent); - const QUrl url = QDir::isAbsolutePath(fileName) ? QUrl::fromLocalFile(fileName) : d->engine->baseUrl().resolved(QUrl(fileName)); + const QUrl url = QDir::isAbsolutePath(fileName) ? QUrl::fromLocalFile(fileName) : QUrl(fileName); d->loadUrl(url, mode); } @@ -608,8 +606,7 @@ QQmlContext *QQmlComponent::creationContext() const /*! Load the QQmlComponent from the provided \a url. - Ensure that the URL provided is full and correct, in particular, use - \l QUrl::fromLocalFile() when loading a file from the local filesystem. + \include qqmlcomponent.qdoc url-note */ void QQmlComponent::loadUrl(const QUrl &url) { @@ -621,8 +618,7 @@ void QQmlComponent::loadUrl(const QUrl &url) Load the QQmlComponent from the provided \a url. If \a mode is \l Asynchronous, the component will be loaded and compiled asynchronously. - Ensure that the URL provided is full and correct, in particular, use - \l QUrl::fromLocalFile() when loading a file from the local filesystem. + \include qqmlcomponent.qdoc url-note */ void QQmlComponent::loadUrl(const QUrl &url, QQmlComponent::CompilationMode mode) { @@ -635,11 +631,21 @@ void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::Compilatio Q_Q(QQmlComponent); clear(); - if ((newUrl.isRelative() && !newUrl.isEmpty()) - || newUrl.scheme() == QLatin1String("file")) // Workaround QTBUG-11929 - url = engine->baseUrl().resolved(newUrl); - else + if (newUrl.isRelative()) { + // The new URL is a relative URL like QUrl("main.qml"). + url = engine->baseUrl().resolved(QUrl(newUrl.toString())); + } else if (engine->baseUrl().isLocalFile() && newUrl.isLocalFile() && !QDir::isAbsolutePath(newUrl.toLocalFile())) { + // The new URL is a file on disk but it's a relative path; e.g.: + // QUrl::fromLocalFile("main.qml") or QUrl("file:main.qml") + // We need to remove the scheme so that it becomes a relative URL with a relative path: + QUrl fixedUrl(newUrl); + fixedUrl.setScheme(QString()); + // Then, turn it into an absolute URL with an absolute path by resolving it against the engine's baseUrl(). + // This is a compatibility hack for QTBUG-58837. + url = engine->baseUrl().resolved(fixedUrl); + } else { url = newUrl; + } if (newUrl.isEmpty()) { QQmlError error; -- cgit v1.2.3 From 529b4484e558376598b5bf12a3cfae6fd3969827 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 14 Dec 2017 20:04:47 +0100 Subject: Qml Profiling: Track signals globally Previously they were tracked per object sending them. This is not only too much overhead, but also confusing. Task-number: QTBUG-65190 Change-Id: I4c374f2c3794a19cd825e8681d189107cef23813 Reviewed-by: Simon Hausmann --- src/qml/debugger/qqmlprofiler_p.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src/qml') diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h index 88f8e94f25..b69a6e7a59 100644 --- a/src/qml/debugger/qqmlprofiler_p.h +++ b/src/qml/debugger/qqmlprofiler_p.h @@ -234,9 +234,10 @@ public: { // Use the QV4::Function as ID, as that is common among different instances of the same // component. QQmlBinding is per instance. - // Add 1 to the ID, to make it different from the IDs the V4 profiler produces. The +1 makes - // the pointer point into the middle of the QV4::Function. Thus it still points to valid - // memory but we cannot accidentally create a duplicate key from another object. + // Add 1 to the ID, to make it different from the IDs the V4 and signal handling profilers + // produce. The +1 makes the pointer point into the middle of the QV4::Function. Thus it + // still points to valid memory but we cannot accidentally create a duplicate key from + // another object. quintptr locationId(id(function) + 1); m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), (1 << RangeStart | 1 << RangeLocation), Binding, @@ -263,7 +264,12 @@ public: void startHandlingSignal(QQmlBoundSignalExpression *expression) { - quintptr locationId(id(expression)); + // Use the QV4::Function as ID, as that is common among different instances of the same + // component. QQmlBoundSignalExpression is per instance. + // Add 2 to the ID, to make it different from the IDs the V4 and binding profilers produce. + // The +2 makes the pointer point into the middle of the QV4::Function. Thus it still points + // to valid memory but we cannot accidentally create a duplicate key from another object. + quintptr locationId(id(expression->function()) + 2); m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), (1 << RangeStart | 1 << RangeLocation), HandlingSignal, locationId)); -- cgit v1.2.3 From bc49400b7df51312e918097de429826484fa5c61 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Thu, 4 Jan 2018 13:13:43 +0100 Subject: Doc: state that property aliases do not work with grouped properties It seems to have been the case since the beginning (a bug report linked to from the report referenced here is from 2010), so we should document it until the opposite becomes true. Task-number: QTBUG-65011 Change-Id: I9de0836e024df35968c85c7136cec04b6b4a741c Reviewed-by: Simon Hausmann --- .../qmllanguageref/syntax/objectattributes.qdoc | 39 ++++++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) (limited to 'src/qml') diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc index d789c67fde..568ad930f2 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc @@ -448,13 +448,38 @@ right-hand-side of the property declaration must be a valid alias reference: [default] property alias : \endcode -Unlike an ordinary property, an alias can only refer to an object, or the -property of an object, that is within the scope of the \l{QML Object Types} -{type} within which the alias is declared. It cannot contain arbitrary -JavaScript expressions and it cannot refer to objects declared outside of -the scope of its type. Also note the \e {alias reference} is not optional, -unlike the optional default value for an ordinary property; the alias reference -must be provided when the alias is first declared. +Unlike an ordinary property, an alias has the following restrictions: + +\list +\li It can only refer to an object, or the + property of an object, that is within the scope of the \l{QML Object Types} + {type} within which the alias is declared. +\li It cannot contain arbitrary + JavaScript expressions +\li It cannot refer to objects declared outside of + the scope of its type. +\li The \e {alias reference} is not optional, + unlike the optional default value for an ordinary property; the alias reference + must be provided when the alias is first declared. +\li It cannot refer to grouped properties; the following code will not work: + \code + property alias color: rectangle.border.color + + Rectangle { + id: rectangle + } + \endcode + + However, aliases to \l {QML Basic Types}{value type} properties do work: + \code + property alias rectX: object.rectProperty.x + + Item { + id: object + property rect rectProperty + } + \endcode +\endlist For example, below is a \c Button type with a \c buttonText aliased property which is connected to the \c text object of the \l Text child: -- cgit v1.2.3 From ccee761f06be0f62b84f944a76b0aa4dc759091f Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Thu, 4 Jan 2018 14:52:56 +0100 Subject: Fix segfault on invalid property alias syntax Task-number: QTBUG-64798 Change-Id: Id1eb434f83ec89c5ea1ebaa4d8ec86fce9f4428f Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmltypecompiler.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 568ad4af89..0dd3cf9bfa 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -1080,7 +1080,11 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject; } else { QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex); - Q_ASSERT(targetCache); + if (!targetCache) { + *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString())); + break; + } + QmlIR::PropertyResolver resolver(targetCache); QQmlPropertyData *targetProperty = resolver.property(property.toString()); -- cgit v1.2.3 From 6b1fe1a54183498cd87266c41e79eb4d3c396e42 Mon Sep 17 00:00:00 2001 From: Adam Treat Date: Mon, 18 Dec 2017 14:50:02 -0500 Subject: Compile under QNX 7.0 with qcc 5.4 for instance Change-Id: Ib1a3d51a1c22d0ba0992ca98ad1e51658a871b38 Reviewed-by: Thiago Macieira Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4compileddata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index f54a1b0c41..7735cd03d8 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -747,7 +747,7 @@ static QByteArray ownLibraryChecksum() // the cache files may end up being re-used. To avoid that we also add the checksum of // the QtQml library. Dl_info libInfo; - if (dladdr(reinterpret_cast(&ownLibraryChecksum), &libInfo) != 0) { + if (dladdr(reinterpret_cast(&ownLibraryChecksum), &libInfo) != 0) { QFile library(QFile::decodeName(libInfo.dli_fname)); if (library.open(QIODevice::ReadOnly)) { QCryptographicHash hash(QCryptographicHash::Md5); -- cgit v1.2.3 From 1dd3769fb50ff70c7f3d7a5d0210fb83ae7bc62a Mon Sep 17 00:00:00 2001 From: Adam Treat Date: Tue, 9 Jan 2018 15:02:11 -0500 Subject: Enable JIT on QNX for X86_64 [ChangeLog][Qml] Enabled x86-64 JIT for QNX Change-Id: I41eeff4c3ff687e096098982614a739af8d697f9 Reviewed-by: Simon Hausmann Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4global_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/qml') diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 3abda68ae6..6f10dd738b 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -95,7 +95,7 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); } && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD)) # define V4_ENABLE_JIT #elif defined(Q_PROCESSOR_X86_64) && (QT_POINTER_SIZE == 8) \ - && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)) + && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)) # define V4_ENABLE_JIT #elif defined(Q_PROCESSOR_ARM_32) && (QT_POINTER_SIZE == 4) # if defined(thumb2) || defined(__thumb2__) || ((defined(__thumb) || defined(__thumb__)) && __TARGET_ARCH_THUMB-0 == 4) -- cgit v1.2.3 From 7cf3421858c96ff3a2fe3b860be01a3e0e1133cf Mon Sep 17 00:00:00 2001 From: Samuli Piippo Date: Wed, 10 Jan 2018 16:11:30 +0200 Subject: Enable JIT on QNX7 for ARM64 Remove abs(long) definition, since the #ifdef check no longer works with QNX7 and QNX < 6.6 is no longer supported. [ChangeLog][Qml] Enabled ARM64 JIT for QNX7 Change-Id: Ife02f3edb508eddaf15da65954496265366e232d Reviewed-by: Simon Hausmann Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4global_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/qml') diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 6f10dd738b..a3ef395076 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -104,7 +104,7 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); } # define V4_ENABLE_JIT # endif #elif defined(Q_PROCESSOR_ARM_64) && (QT_POINTER_SIZE == 8) -# if defined(Q_OS_LINUX) +# if defined(Q_OS_LINUX) || defined(Q_OS_QNX) # define V4_ENABLE_JIT # endif #elif defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX) -- cgit v1.2.3 From ecb52e7991abe8d880f74f65dcdd92d7fde715d5 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 10 Jan 2018 15:39:53 +0100 Subject: Constify QObject* argument to QQmlData::wasDeleted() Because it doesn't hurt and it makes it easier to use it in QObjectWrapper::query(). Change-Id: I727ce4b862fa34866513cbb80a221a8a3aeca363 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmldata_p.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index 63994a392d..4848f48766 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -259,7 +259,7 @@ public: bool hasExtendedData() const { return extendedData != 0; } QHash *attachedProperties() const; - static inline bool wasDeleted(QObject *); + static inline bool wasDeleted(const QObject *); static void markAsDeleted(QObject *); static void setQueuedForDeletion(QObject *); @@ -296,16 +296,16 @@ private: } }; -bool QQmlData::wasDeleted(QObject *object) +bool QQmlData::wasDeleted(const QObject *object) { if (!object) return true; - QObjectPrivate *priv = QObjectPrivate::get(object); + const QObjectPrivate *priv = QObjectPrivate::get(object); if (!priv || priv->wasDeleted) return true; - QQmlData *ddata = QQmlData::get(object); + const QQmlData *ddata = QQmlData::get(object); return ddata && ddata->isQueuedForDeletion; } -- cgit v1.2.3 From bbf3c4715a1569b26a3aa029046e26989efd6edc Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 10 Jan 2018 15:42:01 +0100 Subject: Fix crash when accessing a deleted object In QObjectWrapper::query(), return QV4::Attr_Invalid if the object was deleted. Task-number: QTBUG-44153 Change-Id: I53e8be6196489c323b190dbfa20d2dda2a54315e Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4qobjectwrapper.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/qml') diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 326381f38d..89c10e0995 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -651,6 +651,10 @@ void QObjectWrapper::put(Managed *m, String *name, const Value &value) PropertyAttributes QObjectWrapper::query(const Managed *m, String *name) { const QObjectWrapper *that = static_cast(m); + const QObject *thatObject = that->d()->object(); + if (QQmlData::wasDeleted(thatObject)) + return QV4::Object::query(m, name); + ExecutionEngine *engine = that->engine(); QQmlContextData *qmlContext = engine->callingQmlContext(); QQmlPropertyData local; -- cgit v1.2.3 From 52874a0e6f739ce410c8401e19b0a9ef6d02cabf Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 15 Jan 2018 11:30:26 +0100 Subject: Optimizations for Repeater::clear() and ~QQmlItem() QQmlRepeater::clear() had quadratic complexity in the number of items, because the items where removed from the back. Fix this by searching the cache from the back as well as searching for child items to remove from the back. Change-Id: I92e491a8abf47cee9d382ef15cd2471f722fa6dd Reviewed-by: Simon Hausmann --- src/qml/types/qqmldelegatemodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/qml') diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 2f8a70d63b..f1b5759a7d 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -864,7 +864,7 @@ void QQmlDelegateModelPrivate::releaseIncubator(QQDMIncubationTask *incubationTa void QQmlDelegateModelPrivate::removeCacheItem(QQmlDelegateModelItem *cacheItem) { - int cidx = m_cache.indexOf(cacheItem); + int cidx = m_cache.lastIndexOf(cacheItem); if (cidx >= 0) { m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag); m_cache.removeAt(cidx); -- cgit v1.2.3 From 4e0277664071c31e2189e2351e3e9d12c4e7e08c Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 16 Jan 2018 16:24:34 +0100 Subject: Speed up V4 QML context creation After commit cae7975a036352ca4bbcf1381a445362f8e01367 the vtable became part of the internal class, which meant that for allocating the V4::QmlContext and the QV4::QmlContextWrapper we had one additional IC transition upon allocation. We can avoid that by providing a default IC for both types. Task-number: QTBUG-65708 Change-Id: I22815a24a8389b59103309806f6ac4ca382405f0 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4engine.cpp | 2 ++ src/qml/jsruntime/qv4enginebase_p.h | 2 ++ src/qml/jsruntime/qv4qmlcontext_p.h | 2 ++ 3 files changed, 6 insertions(+) (limited to 'src/qml') diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index a584c2731f..0d3f29d089 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -214,6 +214,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) internalClasses[Class_SimpleArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable()); internalClasses[Class_SparseArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable()); internalClasses[Class_ExecutionContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable()); + internalClasses[EngineBase::Class_QmlContext] = internalClasses[EngineBase::Class_ExecutionContext]->changeVTable(QV4::QmlContext::staticVTable()); internalClasses[Class_CallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable()); jsStrings[String_Empty] = newIdentifier(QString()); @@ -256,6 +257,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) InternalClass *ic = internalClasses[Class_Empty]->changeVTable(QV4::Object::staticVTable()); jsObjects[ObjectProto] = memoryManager->allocObject(ic); internalClasses[Class_Object] = ic->changePrototype(objectPrototype()->d()); + internalClasses[EngineBase::Class_QmlContextWrapper] = internalClasses[Class_Object]->changeVTable(QV4::QmlContextWrapper::staticVTable()); ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype()); Q_ASSERT(ic->prototype); diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index 06c346b3c0..38b5ed8909 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -104,6 +104,8 @@ struct EngineBase { Class_ErrorObject, Class_ErrorObjectWithMessage, Class_ErrorProto, + Class_QmlContextWrapper, + Class_QmlContext, NClasses }; InternalClass *internalClasses[NClasses]; diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index 9caeb75b8c..8ef7356f4c 100644 --- a/src/qml/jsruntime/qv4qmlcontext_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -88,6 +88,7 @@ struct Q_QML_EXPORT QmlContextWrapper : Object { V4_OBJECT2(QmlContextWrapper, Object) V4_NEEDS_DESTROY + V4_INTERNALCLASS(QmlContextWrapper) inline QObject *getScopeObject() const { return d()->scopeObject; } inline QQmlContextData *getContext() const { return *d()->context; } @@ -101,6 +102,7 @@ struct Q_QML_EXPORT QmlContextWrapper : Object struct Q_QML_EXPORT QmlContext : public ExecutionContext { V4_MANAGED(QmlContext, ExecutionContext) + V4_INTERNALCLASS(QmlContext) static Heap::QmlContext *createWorkerContext(QV4::ExecutionContext *parent, const QUrl &source, Value *sendFunction); static Heap::QmlContext *create(QV4::ExecutionContext *parent, QQmlContextData *context, QObject *scopeObject); -- cgit v1.2.3 From c2d0693ca99171ebeb8f35423f29562b0d26c6c0 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 16 Jan 2018 16:34:03 +0100 Subject: Have more bindingBits available inline Many QML items have more than 32 properties, so we ended up malloc'ing the binding bit table on the heap quite often. Extending the inline data to be able to accommodate for up to 64 properties fixes that. Change-Id: I90a42d601a5406ffacf2506f1957b0c2080bbb7b Reviewed-by: Simon Hausmann --- src/qml/qml/qqmldata_p.h | 23 +++++++++++------- src/qml/qml/qqmlengine.cpp | 60 ++++++++++++++++++++-------------------------- 2 files changed, 40 insertions(+), 43 deletions(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index 4848f48766..5794e6f0c5 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -156,18 +156,21 @@ public: quint32 hasInterceptorMetaObject:1; quint32 hasVMEMetaObject:1; quint32 parentFrozen:1; - quint32 dummy:22; + quint32 dummy:6; // When bindingBitsSize < sizeof(ptr), we store the binding bit flags inside // bindingBitsValue. When we need more than sizeof(ptr) bits, we allocated // sufficient space and use bindingBits to point to it. - int bindingBitsSize; + quint32 bindingBitsArraySize : 16; typedef quintptr BindingBitsType; + enum { + BitsPerType = sizeof(BindingBitsType) * 8, + InlineBindingArraySize = 2 + }; union { BindingBitsType *bindingBits; - BindingBitsType bindingBitsValue; + BindingBitsType bindingBitsValue[InlineBindingArraySize]; }; - enum { MaxInlineBits = sizeof(BindingBitsType) * 8 }; struct NotifyList { quint64 connectionMask; @@ -275,6 +278,9 @@ public: return createPropertyCache(engine, object); } + Q_ALWAYS_INLINE static uint offsetForBit(int bit) { return static_cast(bit) / BitsPerType; } + Q_ALWAYS_INLINE static BindingBitsType bitFlagForBit(int bit) { return BindingBitsType(1) << (static_cast(bit) & (BitsPerType - 1)); } + private: // For attachedProperties mutable QQmlDataExtended *extendedData; @@ -286,13 +292,12 @@ private: Q_ALWAYS_INLINE bool hasBitSet(int bit) const { - if (bindingBitsSize <= bit) + uint offset = offsetForBit(bit); + if (bindingBitsArraySize <= offset) return false; - if (bindingBitsSize == MaxInlineBits) - return bindingBitsValue & (BindingBitsType(1) << bit); - else - return bindingBits[bit / MaxInlineBits] & (BindingBitsType(1) << (bit % MaxInlineBits)); + const BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits; + return bits[offset] & bitFlagForBit(bit); } }; diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 5350ad38a3..c09c048307 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -110,7 +110,10 @@ Q_DECLARE_METATYPE(QQmlProperty) QT_BEGIN_NAMESPACE typedef QQmlData::BindingBitsType BindingBitsType; -enum { MaxInlineBits = QQmlData::MaxInlineBits }; +enum { + BitsPerType = QQmlData::BitsPerType, + InlineBindingArraySize = QQmlData::InlineBindingArraySize +}; void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor) { @@ -741,11 +744,12 @@ QQmlData::QQmlData() : ownedByQml1(false), ownMemory(true), indestructible(true), explicitIndestructibleSet(false), hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false), hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false), - bindingBitsSize(MaxInlineBits), bindingBitsValue(0), notifyList(0), + bindingBitsArraySize(InlineBindingArraySize), notifyList(0), bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0), lineNumber(0), columnNumber(0), jsEngineId(0), compilationUnit(0), propertyCache(0), guards(0), extendedData(0) { + memset(bindingBitsValue, 0, sizeof(bindingBitsValue)); init(); } @@ -1792,7 +1796,7 @@ void QQmlData::destroyed(QObject *object) signalHandler = next; } - if (bindingBitsSize > MaxInlineBits) + if (bindingBitsArraySize > InlineBindingArraySize) free(bindingBits); if (propertyCache) @@ -1841,47 +1845,35 @@ void QQmlData::parentChanged(QObject *object, QObject *parent) static void QQmlData_setBit(QQmlData *data, QObject *obj, int bit) { - if (Q_UNLIKELY(data->bindingBitsSize <= bit)) { + uint offset = QQmlData::offsetForBit(bit); + BindingBitsType *bits = (data->bindingBitsArraySize == InlineBindingArraySize) ? data->bindingBitsValue : data->bindingBits; + if (Q_UNLIKELY(data->bindingBitsArraySize <= offset)) { int props = QQmlMetaObject(obj).propertyCount(); Q_ASSERT(bit < 2 * props); - int arraySize = (2 * props + MaxInlineBits - 1) / MaxInlineBits; - Q_ASSERT(arraySize > 1); - - // special handling for 32 here is to make sure we wipe the first byte - // when going from bindingBitsValue to bindingBits, and preserve the old - // set bits so we can restore them after the allocation - int oldArraySize = data->bindingBitsSize > MaxInlineBits ? data->bindingBitsSize / MaxInlineBits : 0; - quintptr oldValue = data->bindingBitsSize == MaxInlineBits ? data->bindingBitsValue : 0; - - data->bindingBits = static_cast(realloc((data->bindingBitsSize == MaxInlineBits) ? 0 : data->bindingBits, - arraySize * sizeof(BindingBitsType))); - - memset(data->bindingBits + oldArraySize, - 0x00, - sizeof(BindingBitsType) * (arraySize - oldArraySize)); + uint arraySize = (2 * static_cast(props) + BitsPerType - 1) / BitsPerType; + Q_ASSERT(arraySize > InlineBindingArraySize && arraySize > data->bindingBitsArraySize); - data->bindingBitsSize = arraySize * MaxInlineBits; + BindingBitsType *newBits = static_cast(malloc(arraySize*sizeof(BindingBitsType))); + memcpy(newBits, bits, data->bindingBitsArraySize * sizeof(BindingBitsType)); + memset(newBits + data->bindingBitsArraySize, 0, sizeof(BindingBitsType) * (arraySize - data->bindingBitsArraySize)); - // reinstate bindingBitsValue after we dropped it - if (oldValue) { - memcpy(data->bindingBits, &oldValue, sizeof(oldValue)); - } + if (data->bindingBitsArraySize > InlineBindingArraySize) + free(bits); + data->bindingBits = newBits; + bits = newBits; + data->bindingBitsArraySize = arraySize; } - - if (data->bindingBitsSize == MaxInlineBits) - data->bindingBitsValue |= BindingBitsType(1) << bit; - else - data->bindingBits[bit / MaxInlineBits] |= (BindingBitsType(1) << (bit % MaxInlineBits)); + Q_ASSERT(offset < data->bindingBitsArraySize); + bits[offset] |= QQmlData::bitFlagForBit(bit); } static void QQmlData_clearBit(QQmlData *data, int bit) { - if (data->bindingBitsSize > bit) { - if (data->bindingBitsSize == MaxInlineBits) - data->bindingBitsValue &= ~(BindingBitsType(1) << (bit % MaxInlineBits)); - else - data->bindingBits[bit / MaxInlineBits] &= ~(BindingBitsType(1) << (bit % MaxInlineBits)); + uint offset = QQmlData::offsetForBit(bit); + if (data->bindingBitsArraySize > offset) { + BindingBitsType *bits = (data->bindingBitsArraySize == InlineBindingArraySize) ? data->bindingBitsValue : data->bindingBits; + bits[offset] &= ~QQmlData::bitFlagForBit(bit); } } -- cgit v1.2.3 From c2b4c6393fee37e0c6c4a8c5d40d13120cc8a94e Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 15 Jan 2018 15:36:25 +0100 Subject: Use a more optimized lookup for global properties Force the use of a global lookup if we know that the property can and will be found in the global object. This is possible, as the global object is frozen in QML mode and can't be overwritten. Shaves of .5% on the delegates_item_states benchmark, and will significantly speed up all accesses to e.g. the Math object. Change-Id: Ia1e248781a13ebaeb8bc43652e53a6fdde336d0d Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmlirbuilder.cpp | 6 +++++- src/qml/compiler/qqmlirbuilder_p.h | 3 ++- src/qml/compiler/qqmltypecompiler.cpp | 2 +- src/qml/compiler/qv4isel_moth.cpp | 6 +++--- src/qml/compiler/qv4jsir.cpp | 5 ++++- src/qml/compiler/qv4jsir_p.h | 9 +++++---- src/qml/jit/qv4isel_masm.cpp | 6 +++--- 7 files changed, 23 insertions(+), 14 deletions(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 3974f9ae4e..9749324060 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1555,7 +1555,7 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, Binding JSCodeGen::JSCodeGen(const QString &fileName, const QString &finalUrl, const QString &sourceCode, QV4::IR::Module *jsModule, QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, - const QV4::Compiler::StringTableGenerator *stringPool) + const QV4::Compiler::StringTableGenerator *stringPool, const QSet &globalNames) : QQmlJS::Codegen(/*strict mode*/false) , sourceCode(sourceCode) , jsEngine(jsEngine) @@ -1567,6 +1567,7 @@ JSCodeGen::JSCodeGen(const QString &fileName, const QString &finalUrl, const QSt , _scopeObject(0) , _qmlContextTemp(-1) , _importedScriptsTemp(-1) + , m_globalNames(globalNames) { _module = jsModule; _module->setFileName(fileName); @@ -2010,6 +2011,9 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int } } + if (m_globalNames.contains(name)) + return _block->GLOBALNAME(name, line, col, /*forceLookup =*/ true); + #else Q_UNUSED(name) #endif // V4_BOOTSTRAP diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 8f8a6d090e..ad34864242 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -584,7 +584,7 @@ struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QQmlJS::Codegen { JSCodeGen(const QString &fileName, const QString &finalUrl, const QString &sourceCode, QV4::IR::Module *jsModule, QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, - QQmlTypeNameCache *imports, const QV4::Compiler::StringTableGenerator *stringPool); + QQmlTypeNameCache *imports, const QV4::Compiler::StringTableGenerator *stringPool, const QSet &globalNames); struct IdMapping { @@ -619,6 +619,7 @@ private: QQmlPropertyCache *_scopeObject; int _qmlContextTemp; int _importedScriptsTemp; + QSet m_globalNames; }; struct Q_QML_PRIVATE_EXPORT IRLoader { diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 0dd3cf9bfa..d152d26968 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -143,7 +143,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile() QmlIR::JSCodeGen v4CodeGenerator(typeData->urlString(), typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, - typeNameCache, &document->jsGenerator.stringTable); + typeNameCache, &document->jsGenerator.stringTable, engine->v8engine()->illegalNames()); QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator); if (!jsCodeGen.generateCodeForComponents()) return nullptr; diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index 82f5225f28..c29ffa10c2 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -386,7 +386,7 @@ void InstructionSelection::constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *target) { - if (useFastLookups && func->global) { + if ((useFastLookups || func->forceLookup) && func->global) { Instruction::ConstructGlobalLookup call; call.index = registerGlobalGetterLookup(*func->id); prepareCallArgs(args, call.argc); @@ -491,7 +491,7 @@ void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Expr *target) { - if (useFastLookups && name->global) { + if ((useFastLookups || name->forceLookup) && name->global) { Instruction::GetGlobalLookup load; load.index = registerGlobalGetterLookup(*name->id); load.result = getResultParam(target); @@ -1015,7 +1015,7 @@ void InstructionSelection::visitRet(IR::Ret *s) void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result) { - if (useFastLookups && func->global) { + if ((useFastLookups || func->forceLookup) && func->global) { Instruction::CallGlobalLookup call; call.index = registerGlobalGetterLookup(*func->id); prepareCallArgs(args, call.argc); diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index a8e18784c7..a4038f827a 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -243,11 +243,12 @@ private: } }; -void Name::initGlobal(const QString *id, quint32 line, quint32 column) +void Name::initGlobal(const QString *id, quint32 line, quint32 column, bool forceLookup) { this->id = id; this->builtin = builtin_invalid; this->global = true; + this->forceLookup = forceLookup; this->qmlSingleton = false; this->freeOfSideEffects = false; this->line = line; @@ -259,6 +260,7 @@ void Name::init(const QString *id, quint32 line, quint32 column) this->id = id; this->builtin = builtin_invalid; this->global = false; + this->forceLookup = false; this->qmlSingleton = false; this->freeOfSideEffects = false; this->line = line; @@ -270,6 +272,7 @@ void Name::init(Builtin builtin, quint32 line, quint32 column) this->id = 0; this->builtin = builtin; this->global = false; + this->forceLookup = false; this->qmlSingleton = false; this->freeOfSideEffects = false; this->line = line; diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 9980a21912..317abd09bb 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -480,6 +480,7 @@ struct Name: Expr { const QString *id; Builtin builtin; bool global : 1; + bool forceLookup : 1; bool qmlSingleton : 1; bool freeOfSideEffects : 1; quint32 line; @@ -487,7 +488,7 @@ struct Name: Expr { Name(): Expr(NameExpr) {} - void initGlobal(const QString *id, quint32 line, quint32 column); + void initGlobal(const QString *id, quint32 line, quint32 column, bool forceLookup = false); void init(const QString *id, quint32 line, quint32 column); void init(Builtin builtin, quint32 line, quint32 column); @@ -1141,7 +1142,7 @@ public: Name *NAME(const QString &id, quint32 line, quint32 column); Name *NAME(Name::Builtin builtin, quint32 line, quint32 column); - Name *GLOBALNAME(const QString &id, quint32 line, quint32 column); + Name *GLOBALNAME(const QString &id, quint32 line, quint32 column, bool forceLookup = false); Closure *CLOSURE(int functionInModule); @@ -1583,11 +1584,11 @@ inline Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column) return e; } -inline Name *BasicBlock::GLOBALNAME(const QString &id, quint32 line, quint32 column) +inline Name *BasicBlock::GLOBALNAME(const QString &id, quint32 line, quint32 column, bool forceLookup) { Q_ASSERT(!isRemoved()); Name *e = function->New(); - e->initGlobal(function->newString(id), line, column); + e->initGlobal(function->newString(id), line, column, forceLookup); return e; } diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 50d40f6f98..9ddab8f838 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -168,7 +168,7 @@ void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR:: { prepareCallData(args, 0); - if (useFastLookups && func->global) { + if ((useFastLookups || func->forceLookup) && func->global) { uint index = registerGlobalGetterLookup(*func->id); generateRuntimeCall(_as, result, callGlobalLookup, JITTargetPlatform::EngineRegister, @@ -517,7 +517,7 @@ void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR template void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Expr *target) { - if (useFastLookups && name->global) { + if ((useFastLookups || name->forceLookup) && name->global) { uint index = registerGlobalGetterLookup(*name->id); generateLookupCall(target, index, offsetof(QV4::Lookup, globalGetter), JITTargetPlatform::EngineRegister, JITAssembler::Void); return; @@ -1128,7 +1128,7 @@ void InstructionSelection::constructActivationProperty(IR::Name *f Q_ASSERT(func != 0); prepareCallData(args, 0); - if (useFastLookups && func->global) { + if ((useFastLookups || func->forceLookup) && func->global) { uint index = registerGlobalGetterLookup(*func->id); generateRuntimeCall(_as, result, constructGlobalLookup, JITTargetPlatform::EngineRegister, -- cgit v1.2.3 From 22e5f2f64369ffbdcb8184c9b35c946a1d20f4e1 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 11 Jan 2018 15:33:28 +0100 Subject: Revert "Allow canceling incubation" This reverts commit ca6b787a01ea289bd5c2a3e4ff3c7442a4ff58fc. This internal API was added as a workaround for Qt Quick Controls 2. It is no longer needed now that Qt Quick Controls 2 are using deferred execution. Task-number: QTBUG-50992 Change-Id: Iaddf22460f091743e1a68acd16813a28f3e82ecb Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlincubator.cpp | 17 ----------------- src/qml/qml/qqmlincubator_p.h | 3 --- src/qml/qml/qqmlobjectcreator.cpp | 15 --------------- src/qml/qml/qqmlobjectcreator_p.h | 1 - src/qml/qml/qqmlvme.cpp | 12 ------------ src/qml/qml/qqmlvme_p.h | 1 - 6 files changed, 49 deletions(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp index 93bb67de20..9855c27375 100644 --- a/src/qml/qml/qqmlincubator.cpp +++ b/src/qml/qml/qqmlincubator.cpp @@ -377,23 +377,6 @@ finishIncubate: } } -void QQmlIncubatorPrivate::cancel(QObject *object, QQmlContext *context) -{ - if (!context) - context = qmlContext(object); - if (!context) - return; - - QQmlContextData *data = QQmlContextData::get(context); - QQmlIncubatorPrivate *p = data->incubator; - if (!p) - return; - - p->vmeGuard.unguard(object); - if (!p->creator.isNull()) - p->creator->cancel(object); -} - /*! Incubate objects for \a msecs, or until there are no more objects to incubate. */ diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h index 758e0a29f6..676ba1a29a 100644 --- a/src/qml/qml/qqmlincubator_p.h +++ b/src/qml/qml/qqmlincubator_p.h @@ -102,9 +102,6 @@ public: void forceCompletion(QQmlInstantiationInterrupt &i); void incubate(QQmlInstantiationInterrupt &i); - - // used by Qt Quick Controls 2 - Q_QML_PRIVATE_EXPORT static void cancel(QObject *object, QQmlContext *context = 0); }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 9c6630190f..dfb733f4cb 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -1349,21 +1349,6 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru return sharedState->rootContext; } -void QQmlObjectCreator::cancel(QObject *object) -{ - int last = sharedState->allCreatedObjects.count() - 1; - int i = last; - while (i >= 0) { - if (sharedState->allCreatedObjects.at(i) == object) { - if (i < last) - qSwap(sharedState->allCreatedObjects[i], sharedState->allCreatedObjects[last]); - sharedState->allCreatedObjects.pop(); - break; - } - --i; - } -} - void QQmlObjectCreator::clear() { if (phase == Done || phase == Finalizing || phase == Startup) diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index e2371cb4f1..4536b2e1af 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -92,7 +92,6 @@ public: 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(); QQmlComponentAttached **componentAttachment() const { return &sharedState->componentAttached; } diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index c60f4edc80..72d4ab7e8f 100644 --- a/src/qml/qml/qqmlvme.cpp +++ b/src/qml/qml/qqmlvme.cpp @@ -120,18 +120,6 @@ void QQmlVMEGuard::guard(QQmlObjectCreator *creator) m_contexts[0] = creator->parentContextData(); } -void QQmlVMEGuard::unguard(QObject *object) -{ - for (int ii = 0; ii < m_objectCount; ++ii) { - if (m_objects[ii] == object) { - if (ii < m_objectCount - 1) - ::memmove((void *) m_objects[ii], (void *) m_objects[ii + 1], sizeof(QPointer *)); - delete m_objects[--m_objectCount]; - break; - } - } -} - void QQmlVMEGuard::clear() { delete [] m_objects; diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h index 9585b5b6df..99d63380ad 100644 --- a/src/qml/qml/qqmlvme_p.h +++ b/src/qml/qml/qqmlvme_p.h @@ -131,7 +131,6 @@ public: ~QQmlVMEGuard(); void guard(QQmlObjectCreator *); - void unguard(QObject *); void clear(); bool isOK() const; -- cgit v1.2.3 From 859a7b7da05040e33d886b4257e81bd278e0238b Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 17 Jan 2018 09:59:35 +0100 Subject: Prevent a QVector detach Change-Id: Ibda07de7a83cf9a1434532c485583b8b49b0a605 Reviewed-by: Lars Knoll --- src/qml/qml/qqmlobjectcreator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index dfb733f4cb..f85d9ee639 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -879,7 +879,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(property->coreIndex())); if (binding->type == QV4::CompiledData::Binding::Type_Script) { - QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; + QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions.at(binding->value.compiledScriptIndex); QV4::Scope scope(v4); QV4::Scoped qmlContext(scope, currentQmlContext()); -- cgit v1.2.3 From e4ffad84fecebb3c1fc554b3252fd5d059c0ff38 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 16 Jan 2018 09:29:59 +0100 Subject: Speed up PropertyChange state application Every time we decode a potential binding of a PropertyChanges{} object, we call qmlContext(this) and we go through a full QQmlProperty construction (which involves property name decoding by dots and property lookups), just to determine if we're doing a binding on a property or a signal. QQmlProperty::isSignalProperty() will only return true if the property is valid and if it's a "function" type. The QQmlProperty constructor on the other hand only constructs a valid regular property if it's _not_ a function type and a signal property _has_ to start with "on" followed by an upper case character. We can copy this shortcut out into decodeBinding() to avoid the QQmlProperty construction in the common case of plain property bindings. This is also legit in the scope of group properties, as signal bindings on group properties are not supported (we always use the state's target object for signal lookup, never the group object). In addition, avoid creating a public QQmlContext for the PropertyChange object by allowing for the construction of the QQmlProperty object via the QQmlContextData, as that's the only data structure we really need. These two changes used to be separate, but they need to go together to keep the tests passing, as the property validation and warning issuing is now moved from decodeBinding() into ::actions() itself. Shaves off 1.5% off delegates_item_states.qml Task-number: QTBUG-65708 Change-Id: I32a17d815bd3495a907a51068a971eb7cb69c6ef Reviewed-by: Lars Knoll --- src/qml/qml/qqmlproperty.cpp | 16 ++++++++++++++++ src/qml/qml/qqmlproperty_p.h | 2 ++ 2 files changed, 18 insertions(+) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 9a138dcf80..b79418761b 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -223,6 +223,22 @@ QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlEngine *engine if (!isValid()) { d->object = 0; d->context = 0; d->engine = 0; } } +QQmlProperty QQmlPropertyPrivate::create(QObject *target, const QString &propertyName, QQmlContextData *context) +{ + QQmlProperty result; + auto d = new QQmlPropertyPrivate; + result.d = d; + d->context = context; + d->engine = context->engine; + d->initProperty(target, propertyName); + if (!result.isValid()) { + d->object = nullptr; + d->context = nullptr; + d->engine = nullptr; + } + return result; +} + QQmlPropertyPrivate::QQmlPropertyPrivate() : context(0), engine(0), object(0), isNameCached(false) { diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h index 53062a2f13..7a66d8113c 100644 --- a/src/qml/qml/qqmlproperty_p.h +++ b/src/qml/qml/qqmlproperty_p.h @@ -144,6 +144,8 @@ public: static void flushSignal(const QObject *sender, int signal_index); static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context); + static QQmlProperty create(QObject *target, const QString &propertyName, QQmlContextData *context); + }; Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::BindingFlags) -- cgit v1.2.3 From 15a81d9689cad5c957aed09161fdab253b27c130 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 16 Jan 2018 13:47:51 +0100 Subject: Optimize QQmlProperty constructor for the common property case The common case is that QQmlProperty is constructed on the property of an object, not a group property. Therefore we should do the QVector split on the property name by '.' only if a dot exists, and can avoid the allocation and deallocation of the vector. Shaves off ~1.2% off delegates_item_states.qml. Task-number: QTBUG-65708 Change-Id: Iffbde176e616beec0ae0a47216360558adc793ee Reviewed-by: Lars Knoll --- src/qml/qml/qqmlproperty.cpp | 136 ++++++++++++++++++++++--------------------- 1 file changed, 70 insertions(+), 66 deletions(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index b79418761b..50d9f13049 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -229,7 +229,7 @@ QQmlProperty QQmlPropertyPrivate::create(QObject *target, const QString &propert auto d = new QQmlPropertyPrivate; result.d = d; d->context = context; - d->engine = context->engine; + d->engine = context ? context->engine : nullptr; d->initProperty(target, propertyName); if (!result.isValid()) { d->object = nullptr; @@ -257,89 +257,93 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) QQmlTypeNameCache *typeNameCache = context?context->imports:0; - const auto path = name.splitRef(QLatin1Char('.')); - if (path.isEmpty()) return; - QObject *currentObject = obj; - - // Everything up to the last property must be an "object type" property - for (int ii = 0; ii < path.count() - 1; ++ii) { - const QStringRef &pathName = path.at(ii); - - if (typeNameCache) { - QQmlTypeNameCache::Result r = typeNameCache->query(pathName); - if (r.isValid()) { - if (r.type.isValid()) { - QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine); - QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate); - if (!func) return; // Not an attachable type - - currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject); - if (!currentObject) return; // Something is broken with the attachable type - } else if (r.importNamespace) { - if ((ii + 1) == path.count()) return; // No type following the namespace - - ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace); - if (!r.type.isValid()) return; // Invalid type in namespace - - QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine); - QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate); - if (!func) return; // Not an attachable type - - currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject); - if (!currentObject) return; // Something is broken with the attachable type - - } else if (r.scriptIndex != -1) { - return; // Not a type - } else { - Q_ASSERT(!"Unreachable"); + QVector path; + QStringRef terminal(&name); + + if (name.contains(QLatin1Char('.'))) { + path = name.splitRef(QLatin1Char('.')); + if (path.isEmpty()) return; + + // Everything up to the last property must be an "object type" property + for (int ii = 0; ii < path.count() - 1; ++ii) { + const QStringRef &pathName = path.at(ii); + + if (typeNameCache) { + QQmlTypeNameCache::Result r = typeNameCache->query(pathName); + if (r.isValid()) { + if (r.type.isValid()) { + QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine); + QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate); + if (!func) return; // Not an attachable type + + currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject); + if (!currentObject) return; // Something is broken with the attachable type + } else if (r.importNamespace) { + if ((ii + 1) == path.count()) return; // No type following the namespace + + ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace); + if (!r.type.isValid()) return; // Invalid type in namespace + + QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine); + QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate); + if (!func) return; // Not an attachable type + + currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject); + if (!currentObject) return; // Something is broken with the attachable type + + } else if (r.scriptIndex != -1) { + return; // Not a type + } else { + Q_ASSERT(!"Unreachable"); + } + continue; } - continue; + } - } + QQmlPropertyData local; + QQmlPropertyData *property = + QQmlPropertyCache::property(engine, currentObject, pathName, context, local); - QQmlPropertyData local; - QQmlPropertyData *property = - QQmlPropertyCache::property(engine, currentObject, pathName, context, local); + if (!property) return; // Not a property + if (property->isFunction()) + return; // Not an object property - if (!property) return; // Not a property - if (property->isFunction()) - return; // Not an object property + if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType())) { + // We're now at a value type property + const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType()); + if (!valueTypeMetaObject) return; // Not a value type - if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType())) { - // We're now at a value type property - const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType()); - if (!valueTypeMetaObject) return; // Not a value type + int idx = valueTypeMetaObject->indexOfProperty(path.last().toUtf8().constData()); + if (idx == -1) return; // Value type property does not exist - int idx = valueTypeMetaObject->indexOfProperty(path.last().toUtf8().constData()); - if (idx == -1) return; // Value type property does not exist + QMetaProperty vtProp = valueTypeMetaObject->property(idx); - QMetaProperty vtProp = valueTypeMetaObject->property(idx); + Q_ASSERT(vtProp.userType() <= 0x0000FFFF); + Q_ASSERT(idx <= 0x0000FFFF); - Q_ASSERT(vtProp.userType() <= 0x0000FFFF); - Q_ASSERT(idx <= 0x0000FFFF); + object = currentObject; + core = *property; + valueTypeData.setFlags(QQmlPropertyData::flagsForProperty(vtProp)); + valueTypeData.setPropType(vtProp.userType()); + valueTypeData.setCoreIndex(idx); - object = currentObject; - core = *property; - valueTypeData.setFlags(QQmlPropertyData::flagsForProperty(vtProp)); - valueTypeData.setPropType(vtProp.userType()); - valueTypeData.setCoreIndex(idx); + return; + } else { + if (!property->isQObject()) + return; // Not an object property - return; - } else { - if (!property->isQObject()) - return; // Not an object property + property->readProperty(currentObject, ¤tObject); + if (!currentObject) return; // No value - property->readProperty(currentObject, ¤tObject); - if (!currentObject) return; // No value + } } + terminal = path.last(); } - const QStringRef &terminal = path.last(); - if (terminal.count() >= 3 && terminal.at(0) == QLatin1Char('o') && terminal.at(1) == QLatin1Char('n') && -- cgit v1.2.3 From 95892bd7b20a881c9a50791d9c1a9309f2f01d28 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 17 Jan 2018 15:54:02 +0100 Subject: Allow for currentQmlContext to be inlined Change-Id: Ic2a98a3a4b4362036222df05a92c0bed633c1d1c Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlobjectcreator.cpp | 7 ++----- src/qml/qml/qqmlobjectcreator_p.h | 11 ++++++++++- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index f85d9ee639..ad9687574f 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -1103,12 +1103,9 @@ void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::O context->setIdProperty(object->id, instance); } -QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext() +void QQmlObjectCreator::createQmlContext() { - if (!_qmlContext->isManaged()) - _qmlContext->setM(QV4::QmlContext::create(v4->rootContext(), context, _scopeObject)); - - return _qmlContext->d(); + _qmlContext->setM(QV4::QmlContext::create(v4->rootContext(), context, _scopeObject)); } QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject) diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 4536b2e1af..82fe22af72 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -123,7 +123,8 @@ private: void registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const; - QV4::Heap::QmlContext *currentQmlContext(); + inline QV4::Heap::QmlContext *currentQmlContext(); + Q_NEVER_INLINE void createQmlContext(); enum Phase { Startup, @@ -173,6 +174,14 @@ private: QRecursionWatcher watcher; }; +QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext() +{ + if (Q_UNLIKELY(!_qmlContext->isManaged())) + createQmlContext(); // less common slow path + + return _qmlContext->d(); +} + QT_END_NAMESPACE #endif // QQMLOBJECTCREATOR_P_H -- cgit v1.2.3 From 706a6647db695cdeb854ef1bf956ded56b498f78 Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Thu, 18 Jan 2018 14:38:19 +0100 Subject: Fix QQmlDelegateModel::object documentation It is talking about item() but such a method doesn't exist anymore. Change-Id: I1935d8b9e88b27a9db1122545a2a82a42d827671 Reviewed-by: Michael Brasser --- src/qml/types/qqmldelegatemodel.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/qml') diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index f1b5759a7d..2badef4268 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -1019,11 +1019,11 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ /* If asynchronous is true or the component is being loaded asynchronously due - to an ancestor being loaded asynchronously, item() may return 0. In this - case createdItem() will be emitted when the item is available. The item - at this stage does not have any references, so item() must be called again - 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. + to an ancestor being loaded asynchronously, object() may return 0. In this + case createdItem() will be emitted when the object is available. The object + at this stage does not have any references, so object() must be called again + to ensure a reference is held. Any call to object() which returns a valid object + must be matched by a call to release() in order to destroy the object. */ QObject *QQmlDelegateModel::object(int index, QQmlIncubator::IncubationMode incubationMode) { -- cgit v1.2.3