aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorMorten Johan Sørvig <morten.sorvig@qt.io>2018-05-11 10:24:18 +0200
committerMorten Johan Sørvig <morten.sorvig@qt.io>2018-05-11 11:13:04 +0200
commit809d305f938177cfb8488dc7fbfc28bc8eef9d20 (patch)
treed43688a9a3ef61af95c91bae3de8b00e6466c817 /src/qml
parentb742bf9415b42c6e34fab91d2f407eb23dc8e0da (diff)
parent1e82f11629e5572783e5bfc36f24ad10c235ca53 (diff)
Merge remote-tracking branch 'origin/5.11.0' into wip/webassembly
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/compiler/compiler.pri2
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp10
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator.cpp2
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h19
-rw-r--r--src/qml/compiler/qv4codegen.cpp22
-rw-r--r--src/qml/compiler/qv4codegen_p.h2
-rw-r--r--src/qml/compiler/qv4compilationunitmapper.cpp32
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_p.h2
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_unix.cpp2
-rw-r--r--src/qml/compiler/qv4compilationunitmapper_win.cpp2
-rw-r--r--src/qml/compiler/qv4compileddata.cpp83
-rw-r--r--src/qml/compiler/qv4compileddata_p.h10
-rw-r--r--src/qml/compiler/qv4compiler.cpp8
-rw-r--r--src/qml/compiler/qv4compilercontext.cpp2
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h44
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp49
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions_p.h7
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp4
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h6
-rw-r--r--src/qml/configure.json9
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h2
-rw-r--r--src/qml/doc/images/cpp-qml-integration-flowchart.odgbin0 -> 16080 bytes
-rw-r--r--src/qml/doc/images/cpp-qml-integration-flowchart.pngbin0 -> 113781 bytes
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc2
-rw-r--r--src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc19
-rw-r--r--src/qml/doc/src/cppintegration/topic.qdoc6
-rw-r--r--src/qml/doc/src/external-resources.qdoc28
-rw-r--r--src/qml/doc/src/javascript/hostenvironment.qdoc18
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc85
-rw-r--r--src/qml/doc/src/qmltypereference.qdoc8
-rw-r--r--src/qml/doc/src/qtqml.qdoc2
-rw-r--r--src/qml/doc/src/statemachine.qdoc2
-rw-r--r--src/qml/jit/qv4assembler.cpp51
-rw-r--r--src/qml/jit/qv4jit.cpp11
-rw-r--r--src/qml/jit/qv4jit_p.h1
-rw-r--r--src/qml/jsruntime/qv4arraybuffer.cpp3
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp9
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h8
-rw-r--r--src/qml/jsruntime/qv4engine.cpp21
-rw-r--r--src/qml/jsruntime/qv4engine_p.h1
-rw-r--r--src/qml/jsruntime/qv4function_p.h7
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp49
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4global_p.h5
-rw-r--r--src/qml/jsruntime/qv4include.cpp10
-rw-r--r--src/qml/jsruntime/qv4include_p.h3
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4object.cpp4
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp5
-rw-r--r--src/qml/jsruntime/qv4regexp.cpp2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp11
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h1
-rw-r--r--src/qml/jsruntime/qv4script.cpp30
-rw-r--r--src/qml/jsruntime/qv4script_p.h4
-rw-r--r--src/qml/jsruntime/qv4value_p.h2
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp4
-rw-r--r--src/qml/memory/qv4mmdefs_p.h28
-rw-r--r--src/qml/qml.pro3
-rw-r--r--src/qml/qml/ftw/qqmlthread.cpp6
-rw-r--r--src/qml/qml/ftw/qqmlthread_p.h2
-rw-r--r--src/qml/qml/qqmlbinding.cpp62
-rw-r--r--src/qml/qml/qqmlbinding_p.h15
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp12
-rw-r--r--src/qml/qml/qqmlcomponent.cpp3
-rw-r--r--src/qml/qml/qqmlcontext.cpp8
-rw-r--r--src/qml/qml/qqmlcontext_p.h1
-rw-r--r--src/qml/qml/qqmldata_p.h57
-rw-r--r--src/qml/qml/qqmldirparser_p.h2
-rw-r--r--src/qml/qml/qqmlengine.cpp104
-rw-r--r--src/qml/qml/qqmlengine_p.h2
-rw-r--r--src/qml/qml/qqmlexpression.cpp5
-rw-r--r--src/qml/qml/qqmlimport.cpp62
-rw-r--r--src/qml/qml/qqmlimport_p.h2
-rw-r--r--src/qml/qml/qqmlincubator.cpp12
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp28
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h20
-rw-r--r--src/qml/qml/qqmlmetatype.cpp35
-rw-r--r--src/qml/qml/qqmlmetatype_p.h12
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp147
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h3
-rw-r--r--src/qml/qml/qqmlproperty.cpp1
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h19
-rw-r--r--src/qml/qml/qqmltypeloader.cpp109
-rw-r--r--src/qml/qml/qqmltypeloader_p.h19
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp1
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp8
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp62
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp9
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h8
-rw-r--r--src/qml/types/qqmlconnections.cpp7
-rw-r--r--src/qml/types/qqmldelegatemodel_p.h2
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h2
-rw-r--r--src/qml/types/qqmlinstantiator.cpp27
-rw-r--r--src/qml/types/qqmlinstantiator_p_p.h4
-rw-r--r--src/qml/types/qqmllistmodel.cpp23
-rw-r--r--src/qml/types/qqmlmodelsmodule.cpp4
-rw-r--r--src/qml/types/qquickworkerscript.cpp6
-rw-r--r--src/qml/types/types.pri12
-rw-r--r--src/qml/util/qqmladaptormodel_p.h2
-rw-r--r--src/qml/util/util.pri10
100 files changed, 1082 insertions, 625 deletions
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index 2ca0c39acc..95096db51d 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -40,8 +40,6 @@ SOURCES += \
unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp
else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp
-
-qtConfig(private_tests):qtConfig(dlopen): QMAKE_USE_PRIVATE += libdl
}
gcc {
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 237cd9bf3b..4a1b27d7aa 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1809,8 +1809,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
QVector<int> runtimeFunctionIndices(functions.size());
QV4::Compiler::ScanFunctions scan(this, sourceCode, QV4::Compiler::GlobalCode);
- scan.enterEnvironment(nullptr, QV4::Compiler::QmlBinding);
- scan.enterQmlScope(qmlRoot, QStringLiteral("context scope"));
+ scan.enterGlobalEnvironment(QV4::Compiler::QmlBinding);
for (const CompiledFunctionOrExpression &f : functions) {
Q_ASSERT(f.node != qmlRoot);
QQmlJS::AST::FunctionDeclaration *function = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(f.node);
@@ -1824,7 +1823,6 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
scan.leaveEnvironment();
}
scan.leaveEnvironment();
- scan.leaveEnvironment();
_context = nullptr;
@@ -2213,12 +2211,6 @@ QV4::Compiler::Codegen::Reference JSCodeGen::fallbackNameLookup(const QString &n
Reference imports = Reference::fromStackSlot(this, _importedScriptsSlot);
return Reference::fromSubscript(imports, Reference::fromConst(this, QV4::Encode(r.scriptIndex)));
} else if (r.type.isValid()) {
- if (r.type.isCompositeSingleton()) {
- Instruction::LoadQmlSingleton load;
- load.name = registerString(name);
- bytecodeGenerator->addInstruction(load);
- return Reference::fromAccumulator(this);
- }
return Reference::fromName(this, name);
} else {
Q_ASSERT(r.importNamespace);
diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp
index 00bb694ef4..ffd3b5975a 100644
--- a/src/qml/compiler/qqmlpropertyvalidator.cpp
+++ b/src/qml/compiler/qqmlpropertyvalidator.cpp
@@ -653,7 +653,7 @@ QQmlCompileError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *
// Can only check at instantiation time if the created sub-object successfully casts to the
// target interface.
return noError;
- } else if (property->propType() == QMetaType::QVariant) {
+ } else if (property->propType() == QMetaType::QVariant || property->propType() == qMetaTypeId<QJSValue>()) {
// We can convert everything to QVariant :)
return noError;
} else if (property->isQList()) {
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index 3b3c766bfe..e69f2cd310 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -102,14 +102,19 @@ public:
Jump(BytecodeGenerator *generator, int instruction)
: generator(generator),
index(instruction)
- {}
+ { Q_ASSERT(generator && index != -1); }
+
~Jump() {
- Q_ASSERT(generator->instructions[index].linkedLabel != -1);
+ Q_ASSERT(index == -1 || generator->instructions[index].linkedLabel != -1); // make sure link() got called
}
+ Jump(Jump &&j) {
+ std::swap(generator, j.generator);
+ std::swap(index, j.index);
+ }
- BytecodeGenerator *generator;
- int index;
+ BytecodeGenerator *generator = nullptr;
+ int index = -1;
void link() {
link(generator->label());
@@ -119,6 +124,12 @@ public:
Q_ASSERT(generator->instructions[index].linkedLabel == -1);
generator->instructions[index].linkedLabel = l.index;
}
+
+ private:
+ // make this type move-only:
+ Q_DISABLE_COPY(Jump)
+ // we never move-assign this type anywhere, so disable it:
+ Jump &operator=(Jump &&) = delete;
};
struct ExceptionHandler : public Label {
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index bc4ca5d6f4..c281275da1 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -784,9 +784,10 @@ bool Codegen::visit(BinaryExpression *ast)
left = left.asLValue();
if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation()))
return false;
- expression(ast->right).loadInAccumulator();
+ Reference r = expression(ast->right);
if (hasError)
return false;
+ r.loadInAccumulator();
if (_expr.accept(nx))
_expr.setResult(left.storeConsumeAccumulator());
else
@@ -2075,6 +2076,14 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
_context->hasDirectEval |= (_context->compilationMode == EvalCode || _context->compilationMode == GlobalCode || _module->debugMode); // Conditional breakpoints are like eval in the function
+ // When a user writes the following QML signal binding:
+ // onSignal: function() { doSomethingUsefull }
+ // we will generate a binding function that just returns the closure. However, that's not useful
+ // at all, because if the onSignal is a signal handler, the user is actually making it explicit
+ // that the binding is a function, so we should execute that. However, we don't know that during
+ // AOT compilation, so mark the surrounding function as only-returning-a-closure.
+ _context->returnsClosure = cast<ExpressionStatement *>(ast) && cast<FunctionExpression *>(cast<ExpressionStatement *>(ast)->expression);
+
BytecodeGenerator bytecode(_context->line, _module->debugMode);
BytecodeGenerator *savedBytecodeGenerator;
savedBytecodeGenerator = bytecodeGenerator;
@@ -2095,9 +2104,14 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
_context->addLocalVar(QStringLiteral("arguments"), Context::VariableDeclaration, AST::VariableDeclaration::FunctionScope);
bool allVarsEscape = _context->hasWith || _context->hasTry || _context->hasDirectEval;
- if (_context->compilationMode == QmlBinding // we don't really need this for bindings, but we do for signal handlers, and we don't know if the code is a signal handler or not.
- || (!_context->canUseSimpleCall() && _context->compilationMode != GlobalCode &&
- (_context->compilationMode != EvalCode || _context->isStrict))) {
+ bool needsCallContext = false;
+ const QLatin1String exprForOn("expression for on");
+ if (!_context->canUseSimpleCall() && _context->compilationMode != GlobalCode && (_context->compilationMode != EvalCode || _context->isStrict))
+ needsCallContext = true;
+ else if (_context->compilationMode == QmlBinding && name.length() > exprForOn.size() && name.startsWith(exprForOn) && name.at(exprForOn.size()).isUpper())
+ // we don't really need this for bindings, but we do for signal handlers, and we don't know if the code is a signal handler or not.
+ needsCallContext = true;
+ if (needsCallContext) {
Instruction::CreateCallContext createContext;
bytecodeGenerator->addInstruction(createContext);
}
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index a46d47cb67..d51dc29517 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -188,7 +188,7 @@ public:
Const
} type = Invalid;
- bool isLValue() const { return !isReadonly; }
+ bool isLValue() const { return !isReadonly && type > Accumulator; }
Reference(Codegen *cg, Type type = Invalid) : type(type), codegen(cg) {}
Reference() {}
diff --git a/src/qml/compiler/qv4compilationunitmapper.cpp b/src/qml/compiler/qv4compilationunitmapper.cpp
index d94f7ac238..350f6f9485 100644
--- a/src/qml/compiler/qv4compilationunitmapper.cpp
+++ b/src/qml/compiler/qv4compilationunitmapper.cpp
@@ -59,36 +59,4 @@ CompilationUnitMapper::~CompilationUnitMapper()
close();
}
-bool CompilationUnitMapper::verifyHeader(const CompiledData::Unit *header, QDateTime sourceTimeStamp, QString *errorString)
-{
- if (strncmp(header->magic, CompiledData::magic_str, sizeof(header->magic))) {
- *errorString = QStringLiteral("Magic bytes in the header do not match");
- return false;
- }
-
- if (header->version != quint32(QV4_DATA_STRUCTURE_VERSION)) {
- *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2").arg(header->version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16);
- return false;
- }
-
- if (header->qtVersion != quint32(QT_VERSION)) {
- *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2").arg(header->qtVersion, 0, 16).arg(QT_VERSION, 0, 16);
- return false;
- }
-
- if (header->sourceTimeStamp) {
- // Files from the resource system do not have any time stamps, so fall back to the application
- // executable.
- if (!sourceTimeStamp.isValid())
- sourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified();
-
- if (sourceTimeStamp.isValid() && sourceTimeStamp.toMSecsSinceEpoch() != header->sourceTimeStamp) {
- *errorString = QStringLiteral("QML source file has a different time stamp than cached file.");
- return false;
- }
- }
-
- return true;
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4compilationunitmapper_p.h b/src/qml/compiler/qv4compilationunitmapper_p.h
index b24f98df7c..80f914c141 100644
--- a/src/qml/compiler/qv4compilationunitmapper_p.h
+++ b/src/qml/compiler/qv4compilationunitmapper_p.h
@@ -72,8 +72,6 @@ public:
void close();
private:
- static bool verifyHeader(const QV4::CompiledData::Unit *header, QDateTime sourceTimeStamp, QString *errorString);
-
#if defined(Q_OS_UNIX)
size_t length;
#endif
diff --git a/src/qml/compiler/qv4compilationunitmapper_unix.cpp b/src/qml/compiler/qv4compilationunitmapper_unix.cpp
index 38dabc41cf..8348613888 100644
--- a/src/qml/compiler/qv4compilationunitmapper_unix.cpp
+++ b/src/qml/compiler/qv4compilationunitmapper_unix.cpp
@@ -73,7 +73,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
return nullptr;
}
- if (!verifyHeader(&header, sourceTimeStamp, errorString))
+ if (!header.verifyHeader(sourceTimeStamp, errorString))
return nullptr;
// Data structure and qt version matched, so now we can access the rest of the file safely.
diff --git a/src/qml/compiler/qv4compilationunitmapper_win.cpp b/src/qml/compiler/qv4compilationunitmapper_win.cpp
index d7a93ae233..8b000021f8 100644
--- a/src/qml/compiler/qv4compilationunitmapper_win.cpp
+++ b/src/qml/compiler/qv4compilationunitmapper_win.cpp
@@ -87,7 +87,7 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
return nullptr;
}
- if (!verifyHeader(&header, sourceTimeStamp, errorString))
+ if (!header.verifyHeader(sourceTimeStamp, errorString))
return nullptr;
const uint mappingFlags = header.flags & QV4::CompiledData::Unit::ContainsMachineCode
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index cc11b250f3..8dcc068a06 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -70,18 +70,14 @@
#include <algorithm>
-#if defined(QT_BUILD_INTERNAL)
-#if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST)
-#include <dlfcn.h>
-#endif
-#endif
-
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace CompiledData {
+static_assert(sizeof(Unit::libraryVersionHash) >= QML_COMPILE_HASH_LENGTH + 1, "Compile hash length exceeds reserved size in data structure. Please adjust and bump the format version");
+
#if !defined(V4_BOOTSTRAP)
static QString cacheFilePath(const QUrl &url)
{
@@ -686,32 +682,6 @@ void ResolvedTypeReference::doDynamicTypeCheck()
isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo);
}
-static QByteArray ownLibraryChecksum()
-{
- static QByteArray libraryChecksum;
- static bool checksumInitialized = false;
- if (checksumInitialized)
- return libraryChecksum;
- checksumInitialized = true;
-#if defined(QT_BUILD_INTERNAL) && !defined(QT_NO_DYNAMIC_CAST) && QT_CONFIG(dlopen)
- // This is a bit of a hack to make development easier. When hacking on the code generator
- // 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<void *>(&ownLibraryChecksum), &libInfo) != 0) {
- QFile library(QFile::decodeName(libInfo.dli_fname));
- if (library.open(QIODevice::ReadOnly)) {
- QCryptographicHash hash(QCryptographicHash::Md5);
- hash.addData(&library);
- libraryChecksum = hash.result();
- }
- }
-#else
- libraryChecksum = QByteArray(QML_COMPILE_HASH);
-#endif
- return libraryChecksum;
-}
-
bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *engine) const
{
for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
@@ -719,8 +689,6 @@ bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *e
return false;
}
- hash->addData(ownLibraryChecksum());
-
return true;
}
@@ -755,6 +723,53 @@ void Unit::generateChecksum()
#endif
}
+bool Unit::verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const
+{
+#ifndef V4_BOOTSTRAP
+ if (strncmp(magic, CompiledData::magic_str, sizeof(magic))) {
+ *errorString = QStringLiteral("Magic bytes in the header do not match");
+ return false;
+ }
+
+ if (version != quint32(QV4_DATA_STRUCTURE_VERSION)) {
+ *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2").arg(version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16);
+ return false;
+ }
+
+ if (qtVersion != quint32(QT_VERSION)) {
+ *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2").arg(qtVersion, 0, 16).arg(QT_VERSION, 0, 16);
+ return false;
+ }
+
+ if (sourceTimeStamp) {
+ // Files from the resource system do not have any time stamps, so fall back to the application
+ // executable.
+ if (!expectedSourceTimeStamp.isValid())
+ expectedSourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified();
+
+ if (expectedSourceTimeStamp.isValid() && expectedSourceTimeStamp.toMSecsSinceEpoch() != sourceTimeStamp) {
+ *errorString = QStringLiteral("QML source file has a different time stamp than cached file.");
+ return false;
+ }
+ }
+
+#if defined(QML_COMPILE_HASH)
+ if (qstrcmp(QML_COMPILE_HASH, libraryVersionHash) != 0) {
+ *errorString = QStringLiteral("QML library version mismatch. Expected compile hash does not match");
+ return false;
+ }
+#else
+#error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files"
+#endif
+
+ return true;
+#else
+ Q_UNUSED(expectedSourceTimeStamp)
+ Q_UNUSED(errorString)
+ return false;
+#endif
+}
+
}
}
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 2c0320f7f1..1df9d6794f 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 0x17
+#define QV4_DATA_STRUCTURE_VERSION 0x19
class QIODevice;
class QQmlPropertyCache;
@@ -225,7 +225,7 @@ struct Function
quint32_le localsOffset;
quint32_le nLineNumbers;
quint32_le lineNumberOffset;
- quint32_le nInnerFunctions;
+ quint32_le nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers
quint32_le nRegisters;
Location location;
@@ -688,6 +688,8 @@ struct Unit
quint32_le unitSize; // Size of the Unit and any depending data.
// END DO NOT CHANGE THESE FIELDS EVER
+ char libraryVersionHash[48];
+
char md5Checksum[16]; // checksum of all bytes following this field.
void generateChecksum();
@@ -727,6 +729,8 @@ struct Unit
quint32_le padding;
+ bool verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const;
+
const Import *importAt(int idx) const {
return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
}
@@ -791,7 +795,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) == 192, "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
{
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index f2e1f4a0de..c9e535c93f 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -48,6 +48,9 @@
#include <wtf/MathExtras.h>
#include <QCryptographicHash>
+// generated by qmake:
+#include "qml_compile_hash_p.h"
+
QV4::Compiler::StringTableGenerator::StringTableGenerator()
{
clear();
@@ -305,6 +308,9 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->flags |= CompiledData::Function::IsStrict;
if (irFunction->hasTry || irFunction->hasWith)
function->flags |= CompiledData::Function::HasCatchOrWith;
+ function->nestedFunctionIndex =
+ irFunction->returnsClosure ? quint32(module->functions.indexOf(irFunction->nestedContexts.first()))
+ : std::numeric_limits<uint32_t>::max();
function->nFormals = irFunction->arguments.size();
function->formalsOffset = currentOffset;
currentOffset += function->nFormals * sizeof(quint32);
@@ -317,7 +323,6 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->lineNumberOffset = currentOffset;
currentOffset += function->nLineNumbers * sizeof(CompiledData::CodeOffsetToLine);
- function->nInnerFunctions = irFunction->nestedContexts.size();
function->nRegisters = irFunction->registerCount;
@@ -394,6 +399,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.flags |= module->unitFlags;
unit.version = QV4_DATA_STRUCTURE_VERSION;
unit.qtVersion = QT_VERSION;
+ qstrcpy(unit.libraryVersionHash, QML_COMPILE_HASH);
memset(unit.md5Checksum, 0, sizeof(unit.md5Checksum));
memset(unit.dependencyMD5Checksum, 0, sizeof(unit.dependencyMD5Checksum));
diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp
index 3293dc53c8..0a9d3d8efe 100644
--- a/src/qml/compiler/qv4compilercontext.cpp
+++ b/src/qml/compiler/qv4compilercontext.cpp
@@ -49,6 +49,8 @@ QT_BEGIN_NAMESPACE
Context *Module::newContext(Node *node, Context *parent, CompilationMode compilationMode)
{
+ Q_ASSERT(!contextMap.contains(node));
+
Context *c = new Context(parent, compilationMode);
if (node) {
SourceLocation loc = node->firstSourceLocation();
diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h
index a78a66db52..455a76c729 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -144,6 +144,7 @@ struct Context {
bool usesThis = false;
bool hasTry = false;
bool hasWith = false;
+ bool returnsClosure = false;
mutable bool argumentsCanEscape = false;
enum UsesArgumentsObject {
@@ -256,29 +257,32 @@ struct Context {
usedVariables.insert(name);
}
- void addLocalVar(const QString &name, MemberType type, QQmlJS::AST::VariableDeclaration::VariableScope scope, QQmlJS::AST::FunctionExpression *function = nullptr)
+ bool addLocalVar(const QString &name, MemberType type, QQmlJS::AST::VariableDeclaration::VariableScope scope, QQmlJS::AST::FunctionExpression *function = nullptr)
{
- if (! name.isEmpty()) {
- if (type != FunctionDefinition) {
- for (QQmlJS::AST::FormalParameterList *it = formals; it; it = it->next)
- if (it->name == name)
- return;
- }
- MemberMap::iterator it = members.find(name);
- if (it == members.end()) {
- Member m;
- m.type = type;
- m.function = function;
- m.scope = scope;
- members.insert(name, m);
- } else {
- Q_ASSERT(scope == (*it).scope);
- if ((*it).type <= type) {
- (*it).type = type;
- (*it).function = function;
- }
+ if (name.isEmpty())
+ return true;
+
+ if (type != FunctionDefinition) {
+ for (QQmlJS::AST::FormalParameterList *it = formals; it; it = it->next)
+ if (it->name == name)
+ return (scope == QQmlJS::AST::VariableDeclaration::FunctionScope);
+ }
+ MemberMap::iterator it = members.find(name);
+ if (it != members.end()) {
+ if (scope != QQmlJS::AST::VariableDeclaration::FunctionScope || (*it).scope != QQmlJS::AST::VariableDeclaration::FunctionScope)
+ return false;
+ if ((*it).type <= type) {
+ (*it).type = type;
+ (*it).function = function;
}
+ return true;
}
+ Member m;
+ m.type = type;
+ m.function = function;
+ m.scope = scope;
+ members.insert(name, m);
+ return true;
}
};
diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp
index 89f602b409..84ee452332 100644
--- a/src/qml/compiler/qv4compilerscanfunctions.cpp
+++ b/src/qml/compiler/qv4compilerscanfunctions.cpp
@@ -73,13 +73,20 @@ void ScanFunctions::operator()(Node *node)
calcEscapingVariables();
}
+void ScanFunctions::enterGlobalEnvironment(CompilationMode compilationMode)
+{
+ enterEnvironment(astNodeForGlobalEnvironment, compilationMode);
+}
+
void ScanFunctions::enterEnvironment(Node *node, CompilationMode compilationMode)
{
- Context *e = _cg->_module->newContext(node, _context, compilationMode);
- if (!e->isStrict)
- e->isStrict = _cg->_strictMode;
- _contextStack.append(e);
- _context = e;
+ Context *c = _cg->_module->contextMap.value(node);
+ if (!c)
+ c = _cg->_module->newContext(node, _context, compilationMode);
+ if (!c->isStrict)
+ c->isStrict = _cg->_strictMode;
+ _contextStack.append(c);
+ _context = c;
}
void ScanFunctions::leaveEnvironment()
@@ -208,14 +215,10 @@ bool ScanFunctions::visit(VariableDeclaration *ast)
return false;
}
QString name = ast->name.toString();
- const Context::Member *m = nullptr;
- if (_context->memberInfo(name, &m)) {
- if (m->isLexicallyScoped() || ast->isLexicallyScoped()) {
- _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name));
- return false;
- }
+ if (!_context->addLocalVar(ast->name.toString(), ast->expression ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope)) {
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name));
+ return false;
}
- _context->addLocalVar(ast->name.toString(), ast->expression ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope);
return true;
}
@@ -390,16 +393,22 @@ bool ScanFunctions::visit(Block *ast) {
void ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParameterList *formals, FunctionBody *body, FunctionExpression *expr)
{
- if (_context) {
- _context->hasNestedFunctions = true;
+ Context *outerContext = _context;
+ enterEnvironment(ast, FunctionCode);
+
+ if (outerContext) {
+ outerContext->hasNestedFunctions = true;
// The identifier of a function expression cannot be referenced from the enclosing environment.
- if (expr)
- _context->addLocalVar(name, Context::FunctionDefinition, AST::VariableDeclaration::FunctionScope, expr);
+ if (expr) {
+ if (!outerContext->addLocalVar(name, Context::FunctionDefinition, AST::VariableDeclaration::FunctionScope, expr)) {
+ _cg->throwSyntaxError(ast->firstSourceLocation(), QStringLiteral("Identifier %1 has already been declared").arg(name));
+ return;
+ }
+ }
if (name == QLatin1String("arguments"))
- _context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
+ outerContext->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
}
- enterEnvironment(ast, FunctionCode);
if (formalsContainName(formals, QStringLiteral("arguments")))
_context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
@@ -440,7 +449,7 @@ void ScanFunctions::calcEscapingVariables()
{
Module *m = _cg->_module;
- for (Context *inner : m->contextMap) {
+ for (Context *inner : qAsConst(m->contextMap)) {
for (const QString &var : qAsConst(inner->usedVariables)) {
Context *c = inner;
while (c) {
@@ -468,7 +477,7 @@ void ScanFunctions::calcEscapingVariables()
static const bool showEscapingVars = qEnvironmentVariableIsSet("QV4_SHOW_ESCAPING_VARS");
if (showEscapingVars) {
qDebug() << "==== escaping variables ====";
- for (Context *c : m->contextMap) {
+ for (Context *c : qAsConst(m->contextMap)) {
qDebug() << "Context" << c->name << ":";
qDebug() << " Arguments escape" << c->argumentsCanEscape;
for (auto it = c->members.constBegin(); it != c->members.constEnd(); ++it) {
diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h
index 745e9f8a73..87b7210879 100644
--- a/src/qml/compiler/qv4compilerscanfunctions_p.h
+++ b/src/qml/compiler/qv4compilerscanfunctions_p.h
@@ -84,12 +84,10 @@ public:
ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode);
void operator()(AST::Node *node);
+ void enterGlobalEnvironment(CompilationMode compilationMode);
void enterEnvironment(AST::Node *node, CompilationMode compilationMode);
void leaveEnvironment();
- void enterQmlScope(AST::Node *ast, const QString &name)
- { enterFunction(ast, name, /*formals*/nullptr, /*body*/nullptr, /*expr*/nullptr); }
-
void enterQmlFunction(AST::FunctionDeclaration *ast)
{ enterFunction(ast, false); }
@@ -149,6 +147,9 @@ protected:
bool _allowFuncDecls;
CompilationMode defaultProgramMode;
+
+private:
+ static constexpr AST::Node *astNodeForGlobalEnvironment = nullptr;
};
}
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index 34953d52ce..450fa50528 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -634,10 +634,6 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_BEGIN_INSTR(LoadQmlImportedScripts)
d << dumpRegister(result, nFormals);
MOTH_END_INSTR(LoadQmlImportedScripts)
-
- MOTH_BEGIN_INSTR(LoadQmlSingleton)
- d << name;
- MOTH_END_INSTR(LoadQmlSingleton)
}
}
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 2d1428bd19..7dd639c94c 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -174,7 +174,6 @@ QT_BEGIN_NAMESPACE
#define INSTR_Sub(op) INSTRUCTION(op, Sub, 1, lhs)
#define INSTR_LoadQmlContext(op) INSTRUCTION(op, LoadQmlContext, 1, result)
#define INSTR_LoadQmlImportedScripts(op) INSTRUCTION(op, LoadQmlImportedScripts, 1, result)
-#define INSTR_LoadQmlSingleton(op) INSTRUCTION(op, LoadQmlSingleton, 1, name)
#define FOR_EACH_MOTH_INSTR(F) \
@@ -290,9 +289,8 @@ QT_BEGIN_NAMESPACE
F(Mod) \
F(Sub) \
F(LoadQmlContext) \
- F(LoadQmlImportedScripts) \
- F(LoadQmlSingleton)
-#define MOTH_NUM_INSTRUCTIONS() (static_cast<int>(Moth::Instr::Type::LoadQmlSingleton) + 1)
+ F(LoadQmlImportedScripts)
+#define MOTH_NUM_INSTRUCTIONS() (static_cast<int>(Moth::Instr::Type::LoadQmlImportedScripts) + 1)
#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL)
// icc before version 1200 doesn't support computed goto, and at least up to version 18.0.0 the
diff --git a/src/qml/configure.json b/src/qml/configure.json
index b744ea6948..681cecea99 100644
--- a/src/qml/configure.json
+++ b/src/qml/configure.json
@@ -39,6 +39,12 @@
"features.xmlstreamwriter"
],
"output": [ "privateFeature" ]
+ },
+ "qml-delegate-model": {
+ "label": "QML delegate model",
+ "purpose": "Provides the DelegateModel QML type.",
+ "section": "QML",
+ "output": [ "privateFeature" ]
}
},
@@ -47,7 +53,8 @@
"section": "Qt QML",
"entries": [
"qml-network",
- "qml-debug"
+ "qml-debug",
+ "qml-delegate-model"
]
}
]
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index deb4d107d6..287c53ea05 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -190,7 +190,7 @@ public:
}
RefLocation(QQmlDataBlob *ref)
- : Location(QQmlSourceLocation()), locationType(Compiling), sent(false)
+ : Location(QQmlSourceLocation(), ref->url()), locationType(Compiling), sent(false)
{
blob = ref;
blob->addref();
diff --git a/src/qml/doc/images/cpp-qml-integration-flowchart.odg b/src/qml/doc/images/cpp-qml-integration-flowchart.odg
new file mode 100644
index 0000000000..8482bd4bf4
--- /dev/null
+++ b/src/qml/doc/images/cpp-qml-integration-flowchart.odg
Binary files differ
diff --git a/src/qml/doc/images/cpp-qml-integration-flowchart.png b/src/qml/doc/images/cpp-qml-integration-flowchart.png
new file mode 100644
index 0000000000..56a33205fd
--- /dev/null
+++ b/src/qml/doc/images/cpp-qml-integration-flowchart.png
Binary files differ
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index 027e4b9923..7f3ff416a1 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -297,6 +297,8 @@ qmlRegisterRevision<BaseType,1>("MyTypes", 1, 1);
This is useful when deriving from base classes provided by other authors,
e.g. when extending classes from the Qt Quick module.
+\note The QML engine does not support revisions for properties or signals of
+grouped and attached property objects.
\section2 Registering Extension Objects
diff --git a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
index 7c2ff703c6..9c33979f40 100644
--- a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
+++ b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
@@ -75,11 +75,26 @@ component, which is accessible via QQuickView::rootObject():
\endtable
This \c object is the instance of the \c MyItem.qml component that has been
-created. You can now modify the item's properties using QObject::setProperty()
-or QQmlProperty:
+created. You can now modify the item's properties using
+\l QObject::setProperty() or \l QQmlProperty::write():
\snippet qml/qtbinding/loading/main.cpp properties
+The difference between \c QObject::setProperty() and \c QQmlProperty::write()
+is that the latter will also remove the binding in addition to setting the
+property value. For example, suppose the \c width assignment above had been a
+binding to \c height:
+
+\code
+ width: height
+\endcode
+
+If the \c height of the \c Item changed after the
+\c {object->setProperty("width", 500)} call, the \c width would be updated
+again, as the binding remains active. However, if the \c height changes after the
+\c {QQmlProperty(object, "width").write(500)} call, the \c width will not be
+changed, as the binding does not exist anymore.
+
Alternatively, you can cast the object to its actual type and call methods with
compile-time safety. In this case the base object of \c MyItem.qml is an
\l Item, which is defined by the QQuickItem class:
diff --git a/src/qml/doc/src/cppintegration/topic.qdoc b/src/qml/doc/src/cppintegration/topic.qdoc
index 6b6e308edf..fbb654378d 100644
--- a/src/qml/doc/src/cppintegration/topic.qdoc
+++ b/src/qml/doc/src/cppintegration/topic.qdoc
@@ -143,6 +143,12 @@ with a QML module that can then be imported and used by QML code in other applic
\l{qtqml-modules-cppplugins.html}{Providing Types and Functionality in a C++ Plugin} for more
information.
+\section1 Choosing the Correct Integration Method Between C++ and QML
+
+To quickly determine which integration method is appropriate for your situation, the following
+flowchart can be used:
+
+\image cpp-qml-integration-flowchart
\section1 Exposing Attributes of C++ Classes to QML
diff --git a/src/qml/doc/src/external-resources.qdoc b/src/qml/doc/src/external-resources.qdoc
index 717e983517..d26288ee6e 100644
--- a/src/qml/doc/src/external-resources.qdoc
+++ b/src/qml/doc/src/external-resources.qdoc
@@ -44,3 +44,31 @@
\externalpage https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
\title Mozilla Developer Network Date Reference
*/
+/*!
+ \externalpage hhttps://www.froglogic.com/squish/gui-testing
+ \title Squish
+*/
+/*!
+ \externalpage http://doc.qt.io/GammaRay
+ \title GammaRay
+*/
+/*!
+ \externalpage http://doc.qt.io/QtQmlLive
+ \title QmlLive
+*/
+/*!
+ \externalpage http://doc.qt.io/qtcreator/creator-debugging-qml.html
+ \title QML Debugger
+*/
+/*!
+ \externalpage http://doc.qt.io/qtcreator/creator-qml-performance-monitor.html
+ \title QML Profiler
+*/
+/*!
+ \externalpage http://doc.qt.io/qtcreator/index.html
+ \title Qt Creator Manual
+*/
+/*!
+ \externalpage https://fontawesome.com/
+ \title Font Awesome
+*/
diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc
index d11e96df2b..eb40f10065 100644
--- a/src/qml/doc/src/javascript/hostenvironment.qdoc
+++ b/src/qml/doc/src/javascript/hostenvironment.qdoc
@@ -154,10 +154,11 @@ This restriction exists as the QML environment is not yet fully established.
To run code after the environment setup has completed, see
\l {JavaScript in Application Startup Code}.
-\li The value of \c this is currently undefined in QML in the majority of contexts.
+\li The value of \c this is undefined in QML in the majority of contexts.
The \c this keyword is supported when binding properties from JavaScript.
-In all other situations, the value of
+In QML binding expressions, QML signal handlers, and QML declared functions,
+\c this refers to the scope object. In all other situations, the value of
\c this is undefined in QML.
To refer to a specific object, provide an \c id. For example:
@@ -168,20 +169,17 @@ Item {
function mouseAreaClicked(area) {
console.log("Clicked in area at: " + area.x + ", " + area.y);
}
- // This will not work because this is undefined
+ // This will pass area to the function
MouseArea {
- height: 50; width: 200
- onClicked: mouseAreaClicked(this)
- }
- // This will pass area2 to the function
- MouseArea {
- id: area2
+ id: area
y: 50; height: 50; width: 200
- onClicked: mouseAreaClicked(area2)
+ onClicked: mouseAreaClicked(area)
}
}
\endqml
+\sa {Scope and Naming Resolution}
+
\endlist
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index ede213b84a..55ca040af6 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -105,6 +105,8 @@
than the actual version of the library. Indeed, it is normal for the new library to allow
QML written to previous versions to continue to work, even if more advanced versions of
some of its types are available.
+
+ \sa {Choosing the Correct Integration Method Between C++ and QML}
*/
/*!
@@ -141,7 +143,8 @@
Returns the QML type id.
- \sa qmlRegisterTypeNotAvailable()
+ \sa qmlRegisterTypeNotAvailable(),
+ {Choosing the Correct Integration Method Between C++ and QML}
*/
/*!
@@ -266,7 +269,8 @@
Without this, a generic "Game is not a type" message would be given.
- \sa qmlRegisterUncreatableType()
+ \sa qmlRegisterUncreatableType(),
+ {Choosing the Correct Integration Method Between C++ and QML}
*/
/*!
@@ -278,7 +282,77 @@
system. Instances of this type cannot be created from the QML
system.
+ This function should be used when the type will not be referenced by name.
+ Specifically, it has to be used for C++ types that are used as the left-hand
+ side of a property binding.
+
+ For example, consider the following two classes:
+
+ \code
+ class Bar : public QObject
+ {
+ Q_OBJECT
+ Q_PROPERTY(QString baz READ baz WRITE setBaz NOTIFY bazChanged)
+
+ public:
+ Bar() {}
+
+ QString baz() const { return mBaz; }
+
+ void setBaz(const QString &baz)
+ {
+ if (baz == mBaz)
+ return;
+
+ mBaz = baz;
+ emit bazChanged();
+ }
+
+ signals:
+ void bazChanged();
+
+ private:
+ QString mBaz;
+ };
+
+ class Foo : public QObject
+ {
+ Q_OBJECT
+ Q_PROPERTY(Bar *bar READ bar CONSTANT FINAL)
+
+ public:
+ Foo() {}
+
+ Bar *bar() { return &mBar; }
+
+ private:
+ Bar mBar;
+ };
+ \endcode
+
+ In QML, we assign a string to the \c baz property of \c bar:
+
+ \code
+ Foo {
+ bar.baz: "abc"
+ Component.onCompleted: print(bar.baz)
+ }
+ \endcode
+
+ For the QML engine to know that the \c Bar type has a \c baz property,
+ we have to make \c Bar known:
+
+ \code
+ qmlRegisterType<Foo>("App", 1, 0, "Foo");
+ qmlRegisterType<Bar>();
+ \endcode
+
+ As the \c Foo type is instantiated in QML, it must be registered
+ with the version of \l qmlRegisterType() that takes an import URI.
+
Returns the QML type id.
+
+ \sa {Choosing the Correct Integration Method Between C++ and QML}
*/
/*!
@@ -346,7 +420,9 @@
property int someValue: ExampleApi.MyApi.someProperty
}
\endqml
- */
+
+ \sa {Choosing the Correct Integration Method Between C++ and QML}
+*/
/*!
\fn template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *attachee, bool create = true)
@@ -486,7 +562,8 @@
}
\endcode
- */
+ \sa {Choosing the Correct Integration Method Between C++ and QML}
+*/
/*!
\fn int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName)
diff --git a/src/qml/doc/src/qmltypereference.qdoc b/src/qml/doc/src/qmltypereference.qdoc
index cfd4d55a24..960ea116c9 100644
--- a/src/qml/doc/src/qmltypereference.qdoc
+++ b/src/qml/doc/src/qmltypereference.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
-\qmlmodule QtQml 2.2
+\qmlmodule QtQml 2.11
\title Qt QML QML Types
\ingroup qmlmodules
\brief List of QML types provided by the Qt QML module
@@ -43,11 +43,11 @@ The types provided by the \c QtQml module are only available in a QML document
if that document imports the \c QtQml namespace (or if the document imports the
\c QtQuick namespace, as noted below).
-The current version of the \c QtQml module is version 2.2, and thus it may be
+The current version of the \c QtQml module is version 2.11, and thus it may be
imported via the following statement:
\qml
-import QtQml 2.2
+import QtQml 2.11
\endqml
Most clients will never need to use the \c QtQml import, as all of the types
@@ -55,7 +55,7 @@ are also provided by the \c QtQuick namespace which may be imported as
follows:
\qml
-import QtQuick 2.7
+import QtQuick 2.11
\endqml
See the \l{Qt Quick} module documentation for more information about the \c
diff --git a/src/qml/doc/src/qtqml.qdoc b/src/qml/doc/src/qtqml.qdoc
index a9f8e2a960..b4bc9a0774 100644
--- a/src/qml/doc/src/qtqml.qdoc
+++ b/src/qml/doc/src/qtqml.qdoc
@@ -58,7 +58,7 @@ following directive:
The QML types in Qt QML are available through the \c QtQML import. To use the
types, add the following import statement to your .qml file:
\code
-import QtQml 2.0
+import QtQml 2.11
\endcode
diff --git a/src/qml/doc/src/statemachine.qdoc b/src/qml/doc/src/statemachine.qdoc
index 0cd19d2a68..59170a223f 100644
--- a/src/qml/doc/src/statemachine.qdoc
+++ b/src/qml/doc/src/statemachine.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
- \qmlmodule QtQml.StateMachine 1.0
+ \qmlmodule QtQml.StateMachine 1.11
\title Declarative State Machine QML Types
\brief Provides QML types to create and execute state graphs.
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index 186e5952da..c3e16c4093 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include <QBuffer>
+#include <QFile>
#include "qv4engine_p.h"
#include "qv4assembler_p.h"
@@ -275,12 +276,16 @@ struct PlatformAssembler_X86_All : JSC::MacroAssembler<JSC::MacroAssemblerX86>
push(JSStackFrameRegister);
push(CppStackFrameRegister);
push(EngineRegister);
+ // Ensure the stack is 16-byte aligned in order for compiler generated aligned SSE2
+ // instructions to be able to target the stack.
+ subPtr(TrustedImm32(8), StackPointerRegister);
loadPtr(Address(FramePointerRegister, 2 * PointerSize), CppStackFrameRegister);
loadPtr(Address(FramePointerRegister, 3 * PointerSize), EngineRegister);
}
void generatePlatformFunctionExit()
{
+ addPtr(TrustedImm32(8), StackPointerRegister);
pop(EngineRegister);
pop(CppStackFrameRegister);
pop(JSStackFrameRegister);
@@ -1367,6 +1372,17 @@ static void printDisassembledOutputWithCalls(QByteArray processedOutput,
qDebug("%s", processedOutput.constData());
}
+static QByteArray functionName(Function *function)
+{
+ QByteArray name = function->name()->toQString().toUtf8();
+ if (name.isEmpty()) {
+ name = QByteArray::number(reinterpret_cast<quintptr>(function), 16);
+ name.prepend("QV4::Function(0x");
+ name.append(')');
+ }
+ return name;
+}
+
void Assembler::link(Function *function)
{
for (const auto &jumpTarget : pasm()->patches)
@@ -1388,12 +1404,7 @@ void Assembler::link(Function *function)
buf.open(QIODevice::WriteOnly);
WTF::setDataFile(new QIODevicePrintStream(&buf));
- QByteArray name = function->name()->toQString().toUtf8();
- if (name.isEmpty()) {
- name = QByteArray::number(quintptr(function), 16);
- name.prepend("QV4::Function(0x");
- name.append(')');
- }
+ QByteArray name = functionName(function);
codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data());
WTF::setDataFile(stderr);
@@ -1404,6 +1415,34 @@ void Assembler::link(Function *function)
function->codeRef = new JSC::MacroAssemblerCodeRef(codeRef);
function->jittedCode = reinterpret_cast<Function::JittedCode>(function->codeRef->code().executableAddress());
+
+#if defined(Q_OS_LINUX)
+ // This implements writing of JIT'd addresses so that perf can find the
+ // symbol names.
+ //
+ // Perf expects the mapping to be in a certain place and have certain
+ // content, for more information, see:
+ // https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt
+ static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP");
+ if (doProfile) {
+ static QFile perfMapFile(QString::fromLatin1("/tmp/perf-%1.map")
+ .arg(QCoreApplication::applicationPid()));
+ static const bool isOpen = perfMapFile.open(QIODevice::WriteOnly);
+ if (!isOpen) {
+ qWarning("QV4::JIT::Assembler: Cannot write perf map file.");
+ doProfile = false;
+ } else {
+ perfMapFile.write(QByteArray::number(reinterpret_cast<quintptr>(
+ codeRef.code().executableAddress()), 16));
+ perfMapFile.putChar(' ');
+ perfMapFile.write(QByteArray::number(static_cast<qsizetype>(codeRef.size()), 16));
+ perfMapFile.putChar(' ');
+ perfMapFile.write(functionName(function));
+ perfMapFile.putChar('\n');
+ perfMapFile.flush();
+ }
+ }
+#endif
}
void Assembler::addLabel(int offset)
diff --git a/src/qml/jit/qv4jit.cpp b/src/qml/jit/qv4jit.cpp
index 5dc98a591a..bc46c0ca1d 100644
--- a/src/qml/jit/qv4jit.cpp
+++ b/src/qml/jit/qv4jit.cpp
@@ -917,14 +917,6 @@ void BaselineJIT::generate_LoadQmlImportedScripts(int result)
as->storeReg(result);
}
-void BaselineJIT::generate_LoadQmlSingleton(int name)
-{
- as->prepareCallWithArgCount(2);
- as->passInt32AsArg(name, 1);
- as->passEngineAsArg(0);
- JIT_GENERATE_RUNTIME_CALL(Runtime::method_loadQmlSingleton, Assembler::ResultInAccumulator);
-}
-
void BaselineJIT::startInstruction(Instr::Type /*instr*/)
{
if (hasLabel())
@@ -1328,9 +1320,6 @@ void BaselineJIT::collectLabelsInBytecode()
MOTH_BEGIN_INSTR(LoadQmlImportedScripts)
MOTH_END_INSTR(LoadQmlImportedScripts)
-
- MOTH_BEGIN_INSTR(LoadQmlSingleton)
- MOTH_END_INSTR(LoadQmlSingleton)
}
}
#undef MOTH_BEGIN_INSTR
diff --git a/src/qml/jit/qv4jit_p.h b/src/qml/jit/qv4jit_p.h
index c17ab4ff6e..5aebf78a8d 100644
--- a/src/qml/jit/qv4jit_p.h
+++ b/src/qml/jit/qv4jit_p.h
@@ -240,7 +240,6 @@ public:
void generate_Sub(int lhs) override;
void generate_LoadQmlContext(int result) override;
void generate_LoadQmlImportedScripts(int result) override;
- void generate_LoadQmlSingleton(int name) override;
void startInstruction(Moth::Instr::Type instr) override;
void endInstruction(Moth::Instr::Type instr) override;
diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp
index c4eddb6b2a..59a2b9d913 100644
--- a/src/qml/jsruntime/qv4arraybuffer.cpp
+++ b/src/qml/jsruntime/qv4arraybuffer.cpp
@@ -96,7 +96,6 @@ void Heap::ArrayBuffer::init(size_t length)
Object::init();
data = QTypedArrayData<char>::allocate(length + 1);
if (!data) {
- data = nullptr;
internalClass->engine->throwRangeError(QStringLiteral("ArrayBuffer: out of memory"));
return;
}
@@ -113,7 +112,7 @@ void Heap::ArrayBuffer::init(const QByteArray& array)
void Heap::ArrayBuffer::destroy()
{
- if (!data->ref.deref())
+ if (data && !data->ref.deref())
QTypedArrayData<char>::deallocate(data);
Object::destroy();
}
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index 30c8527f21..b33b34ee08 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -617,7 +617,7 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n)
uint toCopy = n;
uint chunk = toCopy;
if (chunk > os->values.alloc - os->offset)
- chunk -= os->values.alloc - os->offset;
+ chunk = os->values.alloc - os->offset;
obj->arrayPut(oldSize, os->values.data() + os->offset, chunk);
toCopy -= chunk;
if (toCopy)
@@ -662,14 +662,13 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor)
class ArrayElementLessThan
{
public:
- inline ArrayElementLessThan(ExecutionEngine *engine, Object *thisObject, const Value &comparefn)
- : m_engine(engine), thisObject(thisObject), m_comparefn(comparefn) {}
+ inline ArrayElementLessThan(ExecutionEngine *engine, const Value &comparefn)
+ : m_engine(engine), m_comparefn(comparefn) {}
bool operator()(Value v1, Value v2) const;
private:
ExecutionEngine *m_engine;
- Object *thisObject;
const Value &m_comparefn;
};
@@ -842,7 +841,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
}
- ArrayElementLessThan lessThan(engine, thisObject, static_cast<const FunctionObject &>(comparefn));
+ ArrayElementLessThan lessThan(engine, static_cast<const FunctionObject &>(comparefn));
Value *begin = thisObject->arrayData()->values.values;
sortHelper(begin, begin + len, *begin, lessThan);
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
index 9356670b6d..b2573b4491 100644
--- a/src/qml/jsruntime/qv4arraydata_p.h
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -304,9 +304,11 @@ bool ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs)
}
*attrs = attributes(index);
- p->value = *(Index{ this, mapped });
- if (attrs->isAccessor())
- p->set = *(Index{ this, mapped + 1 /*Object::SetterOffset*/ });
+ if (p) {
+ p->value = *(Index{ this, mapped });
+ if (attrs->isAccessor())
+ p->set = *(Index{ this, mapped + 1 /*Object::SetterOffset*/ });
+ }
return true;
}
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 5f59e1e809..5521633db7 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -758,27 +758,6 @@ QObject *ExecutionEngine::qmlScopeObject() const
return ctx->qml()->scopeObject;
}
-ReturnedValue ExecutionEngine::qmlSingletonWrapper(String *name)
-{
- QQmlContextData *ctx = callingQmlContext();
- if (!ctx->imports)
- return Encode::undefined();
- // Search for attached properties, enums and imported scripts
- QQmlTypeNameCache::Result r = ctx->imports->query(name);
-
- Q_ASSERT(r.isValid());
- Q_ASSERT(r.type.isValid());
- Q_ASSERT(r.type.isSingleton());
-
- QQmlType::SingletonInstanceInfo *siinfo = r.type.singletonInstanceInfo();
- QQmlEngine *e = qmlEngine();
- siinfo->init(e);
-
- if (QObject *qobjectSingleton = siinfo->qobjectApi(e))
- return QV4::QObjectWrapper::wrap(this, qobjectSingleton);
- return QJSValuePrivate::convertedToValue(this, siinfo->scriptApi(e));
-}
-
QQmlContextData *ExecutionEngine::callingQmlContext() const
{
Heap::QmlContext *ctx = qmlContext();
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 5edf89f720..c7fb743088 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -441,7 +441,6 @@ public:
Heap::QmlContext *qmlContext() const;
QObject *qmlScopeObject() const;
- ReturnedValue qmlSingletonWrapper(String *name);
QQmlContextData *callingQmlContext() const;
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 4c8c790ca7..59a94e5dde 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -105,6 +105,13 @@ struct Q_QML_EXPORT Function {
{
return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column);
}
+
+ Function *nestedFunction() const
+ {
+ if (compiledFunction->nestedFunctionIndex == std::numeric_limits<uint32_t>::max())
+ return nullptr;
+ return compilationUnit->runtimeFunctions[compiledFunction->nestedFunctionIndex];
+ }
};
}
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index a8c1640767..83608070ec 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -75,7 +75,6 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name,
jsConstruct = QV4::FunctionObject::callAsConstructor;
Object::init();
- function = nullptr;
this->scope.set(scope->engine(), scope->d());
Scope s(scope->engine());
ScopedFunctionObject f(s, this);
@@ -88,7 +87,6 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name,
jsConstruct = reinterpret_cast<const ObjectVTable *>(vtable())->callAsConstructor;
Object::init();
- function = nullptr;
this->scope.set(scope->engine(), scope->d());
Scope s(scope->engine());
ScopedFunctionObject f(s, this);
@@ -101,8 +99,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function
jsConstruct = reinterpret_cast<const ObjectVTable *>(vtable())->callAsConstructor;
Object::init();
- this->function = function;
- function->compilationUnit->addref();
+ setFunction(function);
this->scope.set(scope->engine(), scope->d());
Scope s(scope->engine());
ScopedString name(s, function->name());
@@ -123,13 +120,18 @@ void Heap::FunctionObject::init()
jsConstruct = reinterpret_cast<const ObjectVTable *>(vtable())->callAsConstructor;
Object::init();
- function = nullptr;
this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d());
Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()) == Index_Prototype);
setProperty(internalClass->engine, Index_Prototype, Primitive::undefinedValue());
}
-
+void Heap::FunctionObject::setFunction(Function *f)
+{
+ if (f) {
+ function = f;
+ function->compilationUnit->addref();
+ }
+}
void Heap::FunctionObject::destroy()
{
if (function)
@@ -347,20 +349,38 @@ ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Valu
{
QV4::Scope scope(b);
ScopedFunctionObject target(scope, thisObject);
- if (!target)
+ if (!target || target->isBinding())
return scope.engine->throwTypeError();
ScopedValue boundThis(scope, argc ? argv[0] : Primitive::undefinedValue());
Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)nullptr);
- if (argc > 1) {
- boundArgs = MemberData::allocate(scope.engine, argc - 1);
- boundArgs->d()->values.size = argc - 1;
- for (uint i = 0, ei = static_cast<uint>(argc - 1); i < ei; ++i)
+
+ int nArgs = (argc - 1 >= 0) ? argc - 1 : 0;
+ if (target->isBoundFunction()) {
+ BoundFunction *bound = static_cast<BoundFunction *>(target.getPointer());
+ Scoped<MemberData> oldArgs(scope, bound->boundArgs());
+ boundThis = bound->boundThis();
+ int oldSize = !oldArgs ? 0 : oldArgs->size();
+ if (oldSize + nArgs) {
+ boundArgs = MemberData::allocate(scope.engine, oldSize + nArgs);
+ boundArgs->d()->values.size = oldSize + nArgs;
+ for (uint i = 0; i < static_cast<uint>(oldSize); ++i)
+ boundArgs->set(scope.engine, i, oldArgs->data()[i]);
+ for (uint i = 0; i < static_cast<uint>(nArgs); ++i)
+ boundArgs->set(scope.engine, oldSize + i, argv[i + 1]);
+ }
+ target = bound->target();
+ } else if (nArgs) {
+ boundArgs = MemberData::allocate(scope.engine, nArgs);
+ boundArgs->d()->values.size = nArgs;
+ for (uint i = 0, ei = static_cast<uint>(nArgs); i < ei; ++i)
boundArgs->set(scope.engine, i, argv[i + 1]);
}
- ExecutionContext *global = scope.engine->rootContext();
- return BoundFunction::create(global, target, boundThis, boundArgs)->asReturnedValue();
+ ScopedContext ctx(scope, target->scope());
+ Heap::BoundFunction *bound = BoundFunction::create(ctx, target, boundThis, boundArgs);
+ bound->setFunction(target->function());
+ return bound->asReturnedValue();
}
DEFINE_OBJECT_VTABLE(ScriptFunction);
@@ -393,8 +413,7 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function
FunctionObject::init();
this->scope.set(scope->engine(), scope->d());
- this->function = function;
- function->compilationUnit->addref();
+ setFunction(function);
Q_ASSERT(function);
Q_ASSERT(function->code);
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index d6066ec648..32e71a175b 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -90,6 +90,8 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) {
void init();
void destroy();
+ void setFunction(Function *f);
+
unsigned int formalParameterCount() { return function ? function->nFormals : 0; }
unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; }
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 7f82a02ae0..9b13d4e341 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -108,6 +108,11 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
//# define V4_ENABLE_JIT
#endif
+// check FPU with double precision on ARM platform
+#if (defined(Q_PROCESSOR_ARM_64) || defined(Q_PROCESSOR_ARM_32)) && defined(V4_ENABLE_JIT) && defined(__ARM_FP) && (__ARM_FP <= 0x04)
+# undef V4_ENABLE_JIT
+#endif
+
// Black list some platforms
#if defined(V4_ENABLE_JIT)
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index aaf5e3b857..d0d66c9b9a 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -92,7 +92,8 @@ QV4Include::~QV4Include()
#endif
}
-QV4::ReturnedValue QV4Include::resultValue(QV4::ExecutionEngine *v4, Status status)
+QV4::ReturnedValue QV4Include::resultValue(QV4::ExecutionEngine *v4, Status status,
+ const QString &statusText)
{
QV4::Scope scope(v4);
@@ -105,6 +106,8 @@ QV4::ReturnedValue QV4Include::resultValue(QV4::ExecutionEngine *v4, Status stat
o->put((s = v4->newString(QStringLiteral("NETWORK_ERROR"))), (v = QV4::Primitive::fromInt32(NetworkError)));
o->put((s = v4->newString(QStringLiteral("EXCEPTION"))), (v = QV4::Primitive::fromInt32(Exception)));
o->put((s = v4->newString(QStringLiteral("status"))), (v = QV4::Primitive::fromInt32(status)));
+ if (!statusText.isEmpty())
+ o->put((s = v4->newString(QStringLiteral("statusText"))), (v = v4->newString(statusText)));
return o.asReturnedValue();
}
@@ -227,7 +230,8 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, cons
} else {
QScopedPointer<QV4::Script> script;
- script.reset(QV4::Script::createFromFileOrCache(scope.engine, qmlcontext, localFile, url));
+ QString error;
+ script.reset(QV4::Script::createFromFileOrCache(scope.engine, qmlcontext, localFile, url, &error));
if (!script.isNull()) {
script->parse();
@@ -242,7 +246,7 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, cons
result = resultValue(scope.engine, Ok);
}
} else {
- result = resultValue(scope.engine, NetworkError);
+ result = resultValue(scope.engine, NetworkError, error);
}
callback(callbackFunction, result);
diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h
index 8015722afc..70ccfbf223 100644
--- a/src/qml/jsruntime/qv4include_p.h
+++ b/src/qml/jsruntime/qv4include_p.h
@@ -88,7 +88,8 @@ private:
QV4::ReturnedValue result();
- static QV4::ReturnedValue resultValue(QV4::ExecutionEngine *v4, Status status = Loading);
+ static QV4::ReturnedValue resultValue(QV4::ExecutionEngine *v4, Status status = Loading,
+ const QString &statusText = QString());
static void callback(const QV4::Value &callback, const QV4::Value &status);
QV4::ExecutionEngine *v4;
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 99666806be..c3569c29d2 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -637,7 +637,7 @@ struct Stringify
Stringify(ExecutionEngine *e) : v4(e), replacerFunction(nullptr), propertyList(nullptr), propertyListSize(0) {}
QString Str(const QString &key, const Value &v);
- QString JA(ArrayObject *a);
+ QString JA(Object *a);
QString JO(Object *o);
QString makeMember(const QString &key, const Value &v);
@@ -743,8 +743,8 @@ QString Stringify::Str(const QString &key, const Value &v)
o = value->asReturnedValue();
if (o) {
if (!o->as<FunctionObject>()) {
- if (o->as<ArrayObject>()) {
- return JA(static_cast<ArrayObject *>(o.getPointer()));
+ if (o->as<ArrayObject>() || o->isListType()) {
+ return JA(o.getPointer());
} else {
return JO(o);
}
@@ -827,7 +827,7 @@ QString Stringify::JO(Object *o)
return result;
}
-QString Stringify::JA(ArrayObject *a)
+QString Stringify::JA(Object *a)
{
if (stackContains(a)) {
v4->throwTypeError();
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 8e9bf794a9..bcbe475c2c 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -1091,9 +1091,7 @@ bool Object::setArrayLength(uint newLen)
uint oldLen = getLength();
bool ok = true;
if (newLen < oldLen) {
- if (!arrayData()) {
- Q_ASSERT(!newLen);
- } else {
+ if (arrayData()) {
uint l = arrayData()->vtable()->truncate(this, newLen);
if (l != newLen)
ok = false;
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index c1bbe2a330..816c259b9b 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -460,9 +460,12 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
+ QV4::ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
QV4::ScopedContext ctx(scope, bindingFunction->scope());
- newBinding = QQmlBinding::create(property, bindingFunction->function(), object, callingQmlContext, ctx);
+ newBinding = QQmlBinding::create(property, f->function(), object, callingQmlContext, ctx);
newBinding->setSourceLocation(bindingFunction->currentLocation());
+ if (f->isBoundFunction())
+ newBinding->setBoundFunction(static_cast<QV4::BoundFunction *>(f.getPointer()));
newBinding->setTarget(object, *property, nullptr);
}
}
diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp
index d99536829b..e10493b879 100644
--- a/src/qml/jsruntime/qv4regexp.cpp
+++ b/src/qml/jsruntime/qv4regexp.cpp
@@ -111,6 +111,8 @@ void Heap::RegExp::init(ExecutionEngine *engine, const QString &pattern, bool ig
JSC::JSGlobalData dummy(internalClass->engine->regExpAllocator);
JSC::Yarr::jitCompile(yarrPattern, JSC::Yarr::Char16, &dummy, *jitCode);
}
+#else
+ Q_UNUSED(engine)
#endif
if (hasValidJITCode()) {
valid = true;
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 04cad8ddb7..0211ad1011 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1271,7 +1271,9 @@ QV4::ReturnedValue Runtime::method_createUnmappedArgumentsObject(ExecutionEngine
ReturnedValue Runtime::method_loadQmlContext(NoThrowEngine *engine)
{
- return engine->qmlContext()->asReturnedValue();
+ Heap::QmlContext *ctx = engine->qmlContext();
+ Q_ASSERT(ctx);
+ return ctx->asReturnedValue();
}
ReturnedValue Runtime::method_regexpLiteral(ExecutionEngine *engine, int id)
@@ -1326,13 +1328,6 @@ ReturnedValue Runtime::method_loadQmlImportedScripts(NoThrowEngine *engine)
return context->importedScripts.value();
}
-QV4::ReturnedValue Runtime::method_loadQmlSingleton(QV4::NoThrowEngine *engine, int nameIndex)
-{
- Scope scope(engine);
- ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- return engine->qmlSingletonWrapper(name);
-}
-
ReturnedValue Runtime::method_uMinus(const Value &value)
{
TRACE1(value);
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index 2956a4a463..91232256a9 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -184,7 +184,6 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
/* qml */ \
F(ReturnedValue, loadQmlContext, (NoThrowEngine *engine)) \
F(ReturnedValue, loadQmlImportedScripts, (NoThrowEngine *engine)) \
- F(ReturnedValue, loadQmlSingleton, (NoThrowEngine *engine, int nameIndex)) \
F(ReturnedValue, loadQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \
F(ReturnedValue, loadQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \
F(ReturnedValue, loadQmlIdObject, (ExecutionEngine *engine, const Value &context, uint index)) \
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index bb6608bec0..afa7d2ed52 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -90,6 +90,12 @@ void Script::parse()
Module module(v4->debugger() != nullptr);
+ if (sourceCode.startsWith(QLatin1String("function("))) {
+ qWarning() << "Warning: Using function expressions as statements in scripts in not compliant with the ECMAScript specification at\n"
+ << (sourceCode.leftRef(70) + QLatin1String("..."))
+ << "\nThis will throw a syntax error in Qt 5.12. If you want a function expression, surround it by parentheses.";
+ }
+
Engine ee, *engine = &ee;
Lexer lexer(engine);
lexer.setCode(sourceCode, line, parseAsBinding);
@@ -136,7 +142,7 @@ void Script::parse()
}
}
-ReturnedValue Script::run()
+ReturnedValue Script::run(const QV4::Value *thisObject)
{
if (!parsed)
parse();
@@ -149,10 +155,11 @@ ReturnedValue Script::run()
if (qmlContext.isUndefined()) {
TemporaryAssignment<Function*> savedGlobalCode(engine->globalCode, vmFunction);
- return vmFunction->call(engine->globalObject, nullptr, 0, context);
+ return vmFunction->call(thisObject ? thisObject : engine->globalObject, nullptr, 0,
+ context);
} else {
Scoped<QmlContext> qml(valueScope, qmlContext.value());
- return vmFunction->call(nullptr, nullptr, 0, qml);
+ return vmFunction->call(thisObject, nullptr, 0, qml);
}
}
@@ -222,17 +229,28 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compi
return cg.generateCompilationUnit(/*generate unit data*/false);
}
-Script *Script::createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlContext, const QString &fileName, const QUrl &originalUrl)
+Script *Script::createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlContext, const QString &fileName, const QUrl &originalUrl, QString *error)
{
- if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(originalUrl)) {
+ if (error)
+ error->clear();
+
+ QQmlMetaType::CachedUnitLookupError cacheError = QQmlMetaType::CachedUnitLookupError::NoError;
+ if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(originalUrl, &cacheError)) {
QQmlRefPointer<QV4::CompiledData::CompilationUnit> jsUnit;
jsUnit.adopt(new QV4::CompiledData::CompilationUnit(cachedUnit));
return new QV4::Script(engine, qmlContext, jsUnit);
}
QFile f(fileName);
- if (!f.open(QIODevice::ReadOnly))
+ if (!f.open(QIODevice::ReadOnly)) {
+ if (error) {
+ if (cacheError == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
+ *error = originalUrl.toString() + QString::fromUtf8(" was compiled ahead of time with an incompatible version of Qt and the original source code cannot be found. Please recompile");
+ else
+ *error = QString::fromUtf8("Error opening source file %1: %2").arg(originalUrl.toString()).arg(f.errorString());
+ }
return nullptr;
+ }
QByteArray data = f.readAll();
QString sourceCode = QString::fromUtf8(data);
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index 24291b9aa6..b4ac150044 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -93,7 +93,7 @@ struct Q_QML_EXPORT Script {
bool parseAsBinding;
void parse();
- ReturnedValue run();
+ ReturnedValue run(const QV4::Value *thisObject = nullptr);
Function *function();
@@ -101,7 +101,7 @@ struct Q_QML_EXPORT Script {
QV4::Compiler::Module *module, Compiler::JSUnitGenerator *unitGenerator,
const QString &fileName, const QString &finalUrl, const QString &source,
QList<QQmlError> *reportedErrors = nullptr, QQmlJS::Directives *directivesCollector = nullptr);
- static Script *createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlContext, const QString &fileName, const QUrl &originalUrl);
+ static Script *createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlContext, const QString &fileName, const QUrl &originalUrl, QString *error);
static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext);
};
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 97ed13cd91..a5ee6b5373 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -339,7 +339,7 @@ public:
if (isDouble()) {
double d = doubleValue();
int i = (int)d;
- if (i == d) {
+ if (i == d && !(d == 0 && std::signbit(d))) {
setInt_32(i);
return true;
}
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index de86a3be5e..6adb25f964 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -1369,10 +1369,6 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const Value *thisObject,
STACK_VALUE(result) = Runtime::method_loadQmlImportedScripts(static_cast<QV4::NoThrowEngine*>(engine));
MOTH_END_INSTR(LoadQmlImportedScripts)
- MOTH_BEGIN_INSTR(LoadQmlSingleton)
- acc = Runtime::method_loadQmlSingleton(static_cast<QV4::NoThrowEngine*>(engine), name);
- MOTH_END_INSTR(LoadQmlSingleton)
-
catchException:
Q_ASSERT(engine->hasException);
if (!exceptionHandler) {
diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h
index 3e2bae46c2..8a53492822 100644
--- a/src/qml/memory/qv4mmdefs_p.h
+++ b/src/qml/memory/qv4mmdefs_p.h
@@ -323,23 +323,23 @@ struct MarkStack {
#define DECLARE_HEAP_OBJECT_BASE(name, base) \
-struct name##OffsetStruct { \
- name##Members(name, HEAP_OBJECT_OFFSET_MEMBER_EXPANSION) \
-}; \
-struct name##SizeStruct : base, name##OffsetStruct {}; \
-struct name##Data { \
- typedef base SuperClass; \
- static Q_CONSTEXPR size_t baseOffset = sizeof(name##SizeStruct) - sizeof(name##OffsetStruct); \
- name##Members(name, HEAP_OBJECT_MEMBER_EXPANSION) \
-}; \
-Q_STATIC_ASSERT(sizeof(name##SizeStruct) == sizeof(name##Data) + name##Data::baseOffset); \
+ struct name##OffsetStruct { \
+ name##Members(name, HEAP_OBJECT_OFFSET_MEMBER_EXPANSION) \
+ }; \
+ struct name##SizeStruct : base, name##OffsetStruct {}; \
+ struct name##Data { \
+ typedef base SuperClass; \
+ static Q_CONSTEXPR size_t baseOffset = sizeof(name##SizeStruct) - sizeof(name##OffsetStruct); \
+ name##Members(name, HEAP_OBJECT_MEMBER_EXPANSION) \
+ }; \
+ Q_STATIC_ASSERT(sizeof(name##SizeStruct) == sizeof(name##Data) + name##Data::baseOffset); \
#define DECLARE_HEAP_OBJECT(name, base) \
-DECLARE_HEAP_OBJECT_BASE(name, base) \
-struct name : base, name##Data
+ DECLARE_HEAP_OBJECT_BASE(name, base) \
+ struct name : base, name##Data
#define DECLARE_EXPORTED_HEAP_OBJECT(name, base) \
-DECLARE_HEAP_OBJECT_BASE(name, base) \
-struct Q_QML_EXPORT name : base, name##Data
+ DECLARE_HEAP_OBJECT_BASE(name, base) \
+ struct Q_QML_EXPORT name : base, name##Data
#define DECLARE_MARKOBJECTS(class) \
static void markObjects(Heap::Base *b, MarkStack *stack) { \
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index f75bfa0313..2137877427 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -36,7 +36,8 @@ DEFINES += QT_NO_FOREACH
}
compile_hash_contents = \
"// Generated file, DO NOT EDIT" \
- "$${LITERAL_HASH}define QML_COMPILE_HASH \"$$QML_COMPILE_HASH\""
+ "$${LITERAL_HASH}define QML_COMPILE_HASH \"$$QML_COMPILE_HASH\"" \
+ "$${LITERAL_HASH}define QML_COMPILE_HASH_LENGTH $$str_size($$QML_COMPILE_HASH)"
write_file("$$OUT_PWD/qml_compile_hash_p.h", compile_hash_contents)|error()
}
diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp
index a36a599f24..9c44e18b87 100644
--- a/src/qml/qml/ftw/qqmlthread.cpp
+++ b/src/qml/qml/ftw/qqmlthread.cpp
@@ -57,6 +57,7 @@ public:
void run() override;
+ inline QMutex &mutex() { return _mutex; }
inline void lock() { _mutex.lock(); }
inline void unlock() { _mutex.unlock(); }
inline void wait() { _wait.wait(&_mutex); }
@@ -269,6 +270,11 @@ bool QQmlThread::isShutdown() const
return d->m_shutdown;
}
+QMutex &QQmlThread::mutex()
+{
+ return d->mutex();
+}
+
void QQmlThread::lock()
{
d->lock();
diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h
index 0ed12a2972..b5c580fe8b 100644
--- a/src/qml/qml/ftw/qqmlthread_p.h
+++ b/src/qml/qml/ftw/qqmlthread_p.h
@@ -59,6 +59,7 @@
QT_BEGIN_NAMESPACE
class QThread;
+class QMutex;
class QQmlThreadPrivate;
class QQmlThread
@@ -71,6 +72,7 @@ public:
void shutdown();
bool isShutdown() const;
+ QMutex &mutex();
void lock();
void unlock();
void wakeOne();
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index ca3bff43a4..30a18440a8 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -51,6 +51,7 @@
#include <private/qqmlvaluetypewrapper_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4variantobject_p.h>
+#include <private/qv4jscall_p.h>
#include <QVariant>
#include <QtCore/qdebug.h>
@@ -97,6 +98,21 @@ QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QQmlScr
return b;
}
+QQmlSourceLocation QQmlBinding::sourceLocation() const
+{
+ if (m_sourceLocation)
+ return *m_sourceLocation;
+ return QQmlJavaScriptExpression::sourceLocation();
+}
+
+void QQmlBinding::setSourceLocation(const QQmlSourceLocation &location)
+{
+ if (m_sourceLocation)
+ delete m_sourceLocation;
+ m_sourceLocation = new QQmlSourceLocation(location);
+}
+
+
QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj,
QQmlContextData *ctxt, const QString &url, quint16 lineNumber)
{
@@ -128,6 +144,7 @@ QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, QV4::Function
QQmlBinding::~QQmlBinding()
{
+ delete m_sourceLocation;
}
void QQmlBinding::setNotifyOnValueChanged(bool v)
@@ -171,6 +188,28 @@ void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
setUpdatingFlag(false);
}
+QV4::ReturnedValue QQmlBinding::evaluate(bool *isUndefined)
+{
+ QV4::ExecutionEngine *v4 = context()->engine->handle();
+ int argc = 0;
+ const QV4::Value *argv = nullptr;
+ const QV4::Value *thisObject = nullptr;
+ QV4::BoundFunction *b = nullptr;
+ if ((b = static_cast<QV4::BoundFunction *>(m_boundFunction.valueRef()))) {
+ QV4::Heap::MemberData *args = b->boundArgs();
+ if (args) {
+ argc = args->values.size;
+ argv = args->values.data();
+ }
+ thisObject = &b->d()->boundThis;
+ }
+ QV4::Scope scope(v4);
+ QV4::JSCallData jsCall(scope, argc, argv, thisObject);
+
+ return QQmlJavaScriptExpression::evaluate(jsCall.callData(), isUndefined);
+}
+
+
// QQmlBindingBinding is for target properties which are of type "binding" (instead of, say, int or
// double). The reason for being is that GenericBinding::fastWrite needs a compile-time constant
// expression for the switch for the compiler to generate the optimal code, but
@@ -203,7 +242,7 @@ protected:
bool isUndefined = false;
- QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined));
+ QV4::ScopedValue result(scope, evaluate(&isUndefined));
bool error = false;
if (!watcher.wasDeleted() && isAddedToObject() && !hasError())
@@ -302,9 +341,14 @@ public:
{
setCompilationUnit(compilationUnit);
m_binding = binding;
- setSourceLocation(QQmlSourceLocation(compilationUnit->fileName(), binding->valueLocation.line, binding->valueLocation.column));
}
+ QQmlSourceLocation sourceLocation() const override final
+ {
+ return QQmlSourceLocation(m_compilationUnit->fileName(), m_binding->valueLocation.line, m_binding->valueLocation.column);
+ }
+
+
void doUpdate(const DeleteWatcher &watcher,
QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) override final
{
@@ -490,6 +534,7 @@ void QQmlBinding::refresh()
void QQmlBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
{
+ const bool wasEnabled = enabledFlag();
setEnabledFlag(e);
setNotifyOnValueChanged(e);
@@ -499,7 +544,7 @@ void QQmlBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
m_nextBinding.clearFlag2();
}
- if (e)
+ if (e && !wasEnabled)
update(flags);
}
@@ -514,13 +559,13 @@ void QQmlBinding::setTarget(const QQmlProperty &prop)
setTarget(prop.object(), pd->core, &pd->valueTypeData);
}
-void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const QQmlPropertyData *valueType)
+bool QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const QQmlPropertyData *valueType)
{
m_target = object;
if (!object) {
m_targetIndex = QQmlPropertyIndex();
- return;
+ return false;
}
int coreIndex = core.coreIndex();
@@ -530,9 +575,10 @@ void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const
int aValueTypeIndex;
if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) {
+ // can't resolve id (yet)
m_target = nullptr;
m_targetIndex = QQmlPropertyIndex();
- return;
+ return false;
}
if (valueTypeIndex == -1)
valueTypeIndex = aValueTypeIndex;
@@ -541,7 +587,7 @@ void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const
if (!data || !data->propertyCache) {
m_target = nullptr;
m_targetIndex = QQmlPropertyIndex();
- return;
+ return false;
}
QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
Q_ASSERT(propertyData);
@@ -557,6 +603,8 @@ void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const
data->propertyCache = QQmlEnginePrivate::get(context()->engine)->cache(m_target->metaObject());
data->propertyCache->addref();
}
+
+ return true;
}
void QQmlBinding::getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index 19ec3f5d4f..a1295bd0ac 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -72,6 +72,8 @@ class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlJavaScriptExpression,
{
friend class QQmlAbstractBinding;
public:
+ typedef QExplicitlySharedDataPointer<QQmlBinding> Ptr;
+
static QQmlBinding *create(const QQmlPropertyData *, const QQmlScriptString &, QObject *, QQmlContext *);
static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContextData *,
const QString &url = QString(), quint16 lineNumber = 0);
@@ -82,7 +84,7 @@ public:
~QQmlBinding() override;
void setTarget(const QQmlProperty &);
- void setTarget(QObject *, const QQmlPropertyData &, const QQmlPropertyData *valueType);
+ bool setTarget(QObject *, const QQmlPropertyData &, const QQmlPropertyData *valueType);
void setNotifyOnValueChanged(bool);
@@ -102,6 +104,12 @@ public:
QString expressionIdentifier() const override;
void expressionChanged() override;
+ QQmlSourceLocation sourceLocation() const override;
+ void setSourceLocation(const QQmlSourceLocation &location);
+ void setBoundFunction(QV4::BoundFunction *boundFunction) {
+ m_boundFunction.set(boundFunction->engine(), *boundFunction);
+ }
+
/**
* This method returns a snapshot of the currently tracked dependencies of
* this binding. The dependencies can change upon reevaluation. This method is
@@ -121,6 +129,8 @@ protected:
bool slowWrite(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData,
const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags);
+ QV4::ReturnedValue evaluate(bool *isUndefined);
+
private:
inline bool updatingFlag() const;
inline void setUpdatingFlag(bool);
@@ -128,6 +138,9 @@ private:
inline void setEnabledFlag(bool);
static QQmlBinding *newBinding(QQmlEnginePrivate *engine, const QQmlPropertyData *property);
+
+ QQmlSourceLocation *m_sourceLocation = nullptr; // used for Qt.binding() created functions
+ QV4::PersistentValue m_boundFunction; // used for Qt.binding() that are created from a bound function object
};
bool QQmlBinding::updatingFlag() const
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 060706ac50..d5117c8cec 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -110,6 +110,12 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
m_index(index),
m_target(target)
{
+ // If the function is marked as having a nested function, then the user wrote:
+ // onSomeSignal: function() { /*....*/ }
+ // So take that nested function:
+ if (auto closure = function->nestedFunction())
+ function = closure;
+
setupFunction(scope, function);
init(ctxt, scopeObject);
}
@@ -122,6 +128,12 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
// It's important to call init first, because m_index gets remapped in case of cloned signals.
init(ctxt, scope);
+ // If the function is marked as having a nested function, then the user wrote:
+ // onSomeSignal: function() { /*....*/ }
+ // So take that nested function:
+ if (auto closure = runtimeFunction->nestedFunction())
+ runtimeFunction = closure;
+
QV4::ExecutionEngine *engine = ctxt->engine->handle();
QList<QByteArray> signalParameters = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).parameterNames();
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 3174bbecd3..fe4768db15 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -929,8 +929,7 @@ void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionS
if (0 == enginePriv->inProgressCreations) {
while (enginePriv->erroredBindings) {
- enginePriv->warning(enginePriv->erroredBindings);
- enginePriv->erroredBindings->removeError();
+ enginePriv->warning(enginePriv->erroredBindings->removeError());
}
}
}
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 6e43bc735f..5dd3278b4c 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -593,6 +593,14 @@ void QQmlContextData::invalidate()
parent = nullptr;
}
+void QQmlContextData::clearContextRecursively()
+{
+ clearContext();
+
+ for (auto ctxIt = childContexts; ctxIt; ctxIt = ctxIt->nextChild)
+ ctxIt->clearContextRecursively();
+}
+
void QQmlContextData::clearContext()
{
emitDestruction();
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
index ff36d6c9a8..5dfee48848 100644
--- a/src/qml/qml/qqmlcontext_p.h
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -115,6 +115,7 @@ public:
QQmlContextData(QQmlContext *);
void emitDestruction();
void clearContext();
+ void clearContextRecursively();
void invalidate();
inline bool isValid() const {
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 20b96d2c4b..59fefde893 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -208,12 +208,12 @@ public:
QQmlData**prevContextObject;
inline bool hasBindingBit(int) const;
- void clearBindingBit(int);
- void setBindingBit(QObject *obj, int);
+ inline void setBindingBit(QObject *obj, int);
+ inline void clearBindingBit(int);
inline bool hasPendingBindingBit(int index) const;
- void setPendingBindingBit(QObject *obj, int);
- void clearPendingBindingBit(int);
+ inline void setPendingBindingBit(QObject *obj, int);
+ inline void clearPendingBindingBit(int);
quint16 lineNumber;
quint16 columnNumber;
@@ -304,6 +304,27 @@ private:
const BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
return bits[offset] & bitFlagForBit(bit);
}
+
+ Q_ALWAYS_INLINE void clearBit(int bit)
+ {
+ uint offset = QQmlData::offsetForBit(bit);
+ if (bindingBitsArraySize > offset) {
+ BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
+ bits[offset] &= ~QQmlData::bitFlagForBit(bit);
+ }
+ }
+
+ Q_ALWAYS_INLINE void setBit(QObject *obj, int bit)
+ {
+ uint offset = QQmlData::offsetForBit(bit);
+ BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
+ if (Q_UNLIKELY(bindingBitsArraySize <= offset))
+ bits = growBits(obj, bit);
+ bits[offset] |= QQmlData::bitFlagForBit(bit);
+ }
+
+ Q_NEVER_INLINE BindingBitsType *growBits(QObject *obj, int bit);
+
Q_DISABLE_COPY(QQmlData);
};
@@ -356,6 +377,20 @@ bool QQmlData::hasBindingBit(int coreIndex) const
return hasBitSet(coreIndex * 2);
}
+void QQmlData::setBindingBit(QObject *obj, int coreIndex)
+{
+ Q_ASSERT(coreIndex >= 0);
+ Q_ASSERT(coreIndex <= 0xffff);
+ setBit(obj, coreIndex * 2);
+}
+
+void QQmlData::clearBindingBit(int coreIndex)
+{
+ Q_ASSERT(coreIndex >= 0);
+ Q_ASSERT(coreIndex <= 0xffff);
+ clearBit(coreIndex * 2);
+}
+
bool QQmlData::hasPendingBindingBit(int coreIndex) const
{
Q_ASSERT(coreIndex >= 0);
@@ -364,6 +399,20 @@ bool QQmlData::hasPendingBindingBit(int coreIndex) const
return hasBitSet(coreIndex * 2 + 1);
}
+void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex)
+{
+ Q_ASSERT(coreIndex >= 0);
+ Q_ASSERT(coreIndex <= 0xffff);
+ setBit(obj, coreIndex * 2 + 1);
+}
+
+void QQmlData::clearPendingBindingBit(int coreIndex)
+{
+ Q_ASSERT(coreIndex >= 0);
+ Q_ASSERT(coreIndex <= 0xffff);
+ clearBit(coreIndex * 2 + 1);
+}
+
void QQmlData::flushPendingBinding(QObject *o, QQmlPropertyIndex propertyIndex)
{
QQmlData *data = QQmlData::get(o, false);
diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qml/qqmldirparser_p.h
index 95370398ad..820c40238d 100644
--- a/src/qml/qml/qqmldirparser_p.h
+++ b/src/qml/qml/qqmldirparser_p.h
@@ -63,8 +63,6 @@ class QQmlError;
class QQmlEngine;
class Q_QML_PRIVATE_EXPORT QQmlDirParser
{
- Q_DISABLE_COPY(QQmlDirParser)
-
public:
QQmlDirParser();
~QQmlDirParser();
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 4054d2f0be..7e11177caa 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -88,7 +88,9 @@
#include <private/qqmllistmodel_p.h>
#include <private/qqmlplatform_p.h>
#include <private/qquickpackage_p.h>
+#if QT_CONFIG(qml_delegate_model)
#include <private/qqmldelegatemodel_p.h>
+#endif
#include <private/qqmlobjectmodel_p.h>
#include <private/qquickworkerscript_p.h>
#include <private/qqmlinstantiator_p.h>
@@ -109,12 +111,6 @@ Q_DECLARE_METATYPE(QQmlProperty)
QT_BEGIN_NAMESPACE
-typedef QQmlData::BindingBitsType BindingBitsType;
-enum {
- BitsPerType = QQmlData::BitsPerType,
- InlineBindingArraySize = QQmlData::InlineBindingArraySize
-};
-
void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor)
{
QQmlEnginePrivate::registerBaseTypes(uri, versionMajor, versionMinor);
@@ -240,8 +236,10 @@ void QQmlEnginePrivate::registerQtQuick2Types(const char *uri, int versionMajor,
qmlRegisterCustomType<QQmlListModel>(uri, versionMajor, versionMinor, "ListModel", new QQmlListModelParser); // Now in QtQml.Models, here for compatibility
qmlRegisterType<QQuickWorkerScript>(uri, versionMajor, versionMinor, "WorkerScript");
qmlRegisterType<QQuickPackage>(uri, versionMajor, versionMinor, "Package");
+#if QT_CONFIG(qml_delegate_model)
qmlRegisterType<QQmlDelegateModel>(uri, versionMajor, versionMinor, "VisualDataModel");
qmlRegisterType<QQmlDelegateModelGroup>(uri, versionMajor, versionMinor, "VisualDataGroup");
+#endif
qmlRegisterType<QQmlObjectModel>(uri, versionMajor, versionMinor, "VisualItemModel");
}
@@ -253,6 +251,9 @@ void QQmlEnginePrivate::defineQtQuick2Module()
// register the QtQuick2 types which are implemented in the QtQml module.
registerQtQuick2Types("QtQuick",2,0);
qmlRegisterUncreatableType<QQmlLocale>("QtQuick", 2, 0, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
+
+ // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward
+ qmlRegisterModule("QtQuick", 2, QT_VERSION_MINOR);
}
bool QQmlEnginePrivate::designerMode()
@@ -952,6 +953,9 @@ void QQmlEnginePrivate::init()
registerBaseTypes("QtQml", 2, 0); // import which provides language building blocks.
qmlRegisterUncreatableType<QQmlLocale>("QtQml", 2, 2, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()"));
+ // Auto-increment the import to stay in sync with ALL future QtQml minor versions from 5.11 onward
+ qmlRegisterModule("QtQml", 2, QT_VERSION_MINOR);
+
QQmlData::init();
baseModulesUninitialized = false;
}
@@ -1104,7 +1108,9 @@ QQmlEngine::~QQmlEngine()
void QQmlEngine::clearComponentCache()
{
Q_D(QQmlEngine);
+ d->typeLoader.lock();
d->typeLoader.clearCache();
+ d->typeLoader.unlock();
}
/*!
@@ -1884,66 +1890,27 @@ void QQmlData::parentChanged(QObject *object, QObject *parent)
}
}
-static void QQmlData_setBit(QQmlData *data, QObject *obj, int bit)
+QQmlData::BindingBitsType *QQmlData::growBits(QObject *obj, int 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);
-
- uint arraySize = (2 * static_cast<uint>(props) + BitsPerType - 1) / BitsPerType;
- Q_ASSERT(arraySize > InlineBindingArraySize && arraySize > data->bindingBitsArraySize);
+ BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
+ int props = QQmlMetaObject(obj).propertyCount();
+ Q_ASSERT(bit < 2 * props);
+ Q_UNUSED(bit); // .. for Q_NO_DEBUG mode when the assert above expands to empty
- BindingBitsType *newBits = static_cast<BindingBitsType *>(malloc(arraySize*sizeof(BindingBitsType)));
- memcpy(newBits, bits, data->bindingBitsArraySize * sizeof(BindingBitsType));
- memset(newBits + data->bindingBitsArraySize, 0, sizeof(BindingBitsType) * (arraySize - data->bindingBitsArraySize));
+ uint arraySize = (2 * static_cast<uint>(props) + BitsPerType - 1) / BitsPerType;
+ Q_ASSERT(arraySize > 1);
+ Q_ASSERT(arraySize <= 0xffff); // max for bindingBitsArraySize
- if (data->bindingBitsArraySize > InlineBindingArraySize)
- free(bits);
- data->bindingBits = newBits;
- bits = newBits;
- data->bindingBitsArraySize = arraySize;
- }
- Q_ASSERT(offset < data->bindingBitsArraySize);
- bits[offset] |= QQmlData::bitFlagForBit(bit);
-}
+ BindingBitsType *newBits = static_cast<BindingBitsType *>(malloc(arraySize*sizeof(BindingBitsType)));
+ memcpy(newBits, bits, bindingBitsArraySize * sizeof(BindingBitsType));
+ memset(newBits + bindingBitsArraySize, 0, sizeof(BindingBitsType) * (arraySize - bindingBitsArraySize));
-static void QQmlData_clearBit(QQmlData *data, int bit)
-{
- uint offset = QQmlData::offsetForBit(bit);
- if (data->bindingBitsArraySize > offset) {
- BindingBitsType *bits = (data->bindingBitsArraySize == InlineBindingArraySize) ? data->bindingBitsValue : data->bindingBits;
- bits[offset] &= ~QQmlData::bitFlagForBit(bit);
- }
-}
-
-void QQmlData::clearBindingBit(int coreIndex)
-{
- Q_ASSERT(coreIndex >= 0);
- Q_ASSERT(coreIndex <= 0xffff);
- QQmlData_clearBit(this, coreIndex * 2);
-}
-
-void QQmlData::setBindingBit(QObject *obj, int coreIndex)
-{
- Q_ASSERT(coreIndex >= 0);
- Q_ASSERT(coreIndex <= 0xffff);
- QQmlData_setBit(this, obj, coreIndex * 2);
-}
-
-void QQmlData::clearPendingBindingBit(int coreIndex)
-{
- Q_ASSERT(coreIndex >= 0);
- Q_ASSERT(coreIndex <= 0xffff);
- QQmlData_clearBit(this, coreIndex * 2 + 1);
-}
-
-void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex)
-{
- Q_ASSERT(coreIndex >= 0);
- Q_ASSERT(coreIndex <= 0xffff);
- QQmlData_setBit(this, obj, coreIndex * 2 + 1);
+ if (bindingBitsArraySize > InlineBindingArraySize)
+ free(bits);
+ bindingBits = newBits;
+ bits = newBits;
+ bindingBitsArraySize = arraySize;
+ return bits;
}
QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv)
@@ -2029,11 +1996,6 @@ void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
dumpwarning(errors);
}
-void QQmlEnginePrivate::warning(QQmlDelayedError *error)
-{
- warning(error->error());
-}
-
void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error)
{
if (engine)
@@ -2050,14 +2012,6 @@ void QQmlEnginePrivate::warning(QQmlEngine *engine, const QList<QQmlError> &erro
dumpwarning(error);
}
-void QQmlEnginePrivate::warning(QQmlEngine *engine, QQmlDelayedError *error)
-{
- if (engine)
- QQmlEnginePrivate::get(engine)->warning(error);
- else
- dumpwarning(error->error());
-}
-
void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error)
{
if (engine)
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index d6110c6699..da52e01793 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -231,10 +231,8 @@ public:
void sendExit(int retCode = 0);
void warning(const QQmlError &);
void warning(const QList<QQmlError> &);
- void warning(QQmlDelayedError *);
static void warning(QQmlEngine *, const QQmlError &);
static void warning(QQmlEngine *, const QList<QQmlError> &);
- static void warning(QQmlEngine *, QQmlDelayedError *);
static void warning(QQmlEnginePrivate *, const QQmlError &);
static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index 59cc9bb09f..27d3acb9b7 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -252,6 +252,11 @@ QV4::ReturnedValue QQmlExpressionPrivate::v4value(bool *isUndefined)
if (!expressionFunctionValid) {
createQmlBinding(context(), scopeObject(), expression, url, line);
expressionFunctionValid = true;
+ if (hasError()) {
+ if (isUndefined)
+ *isUndefined = true;
+ return QV4::Encode::undefined();
+ }
}
return evaluate(isUndefined);
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 92cecf9f0d..fe7e5d5a33 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -318,17 +318,17 @@ public:
QQmlImportDatabase *database,
QString *outQmldirFilePath, QString *outUrl);
- static bool validateQmldirVersion(const QQmlTypeLoaderQmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
+ static bool validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, int vmaj, int vmin,
QList<QQmlError> *errors);
bool importExtension(const QString &absoluteFilePath, const QString &uri,
int vmaj, int vmin,
QQmlImportDatabase *database,
- const QQmlTypeLoaderQmldirContent *qmldir,
+ const QQmlTypeLoaderQmldirContent &qmldir,
QList<QQmlError> *errors);
bool getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
- const QQmlTypeLoaderQmldirContent **qmldir, QList<QQmlError> *errors);
+ QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors);
QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database);
@@ -668,14 +668,14 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
return false;
}
-bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent *qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
+bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent &qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
{
Q_ASSERT(resolvedUrl.endsWith(Slash));
url = resolvedUrl;
- qmlDirComponents = qmldir->components();
+ qmlDirComponents = qmldir.components();
- const QQmlDirScripts &scripts = qmldir->scripts();
+ const QQmlDirScripts &scripts = qmldir.scripts();
if (!scripts.isEmpty()) {
// Verify that we haven't imported these scripts already
for (QList<QQmlImportInstance *>::const_iterator it = nameSpace->imports.constBegin();
@@ -1068,26 +1068,26 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
const QString &uri,
int vmaj, int vmin,
QQmlImportDatabase *database,
- const QQmlTypeLoaderQmldirContent *qmldir,
+ const QQmlTypeLoaderQmldirContent &qmldir,
QList<QQmlError> *errors)
{
- Q_ASSERT(qmldir);
+ Q_ASSERT(qmldir.hasContent());
if (qmlImportTrace())
qDebug().nospace() << "QQmlImports(" << qPrintable(base) << ")::importExtension: "
<< "loaded " << qmldirFilePath;
- if (designerSupportRequired && !qmldir->designerSupported()) {
+ if (designerSupportRequired && !qmldir.designerSupported()) {
if (errors) {
QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("module does not support the designer \"%1\"").arg(qmldir->typeNamespace()));
+ error.setDescription(QQmlImportDatabase::tr("module does not support the designer \"%1\"").arg(qmldir.typeNamespace()));
error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
errors->prepend(error);
}
return false;
}
- int qmldirPluginCount = qmldir->plugins().count();
+ int qmldirPluginCount = qmldir.plugins().count();
if (qmldirPluginCount == 0)
return true;
@@ -1098,7 +1098,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
// listed plugin inside qmldir. And for this reason, mixing dynamic and static plugins inside a
// single module is not recommended.
- QString typeNamespace = qmldir->typeNamespace();
+ QString typeNamespace = qmldir.typeNamespace();
QString qmldirPath = qmldirFilePath;
int slash = qmldirPath.lastIndexOf(Slash);
if (slash > 0)
@@ -1108,7 +1108,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
int staticPluginsFound = 0;
#if defined(QT_SHARED)
- const auto qmldirPlugins = qmldir->plugins();
+ const auto qmldirPlugins = qmldir.plugins();
for (const QQmlDirParser::Plugin &plugin : qmldirPlugins) {
QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name);
if (!resolvedFilePath.isEmpty()) {
@@ -1174,7 +1174,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
if (qmldirPluginCount > 1 && staticPluginsFound > 0)
error.setDescription(QQmlImportDatabase::tr("could not resolve all plugins for module \"%1\"").arg(uri));
else
- error.setDescription(QQmlImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(qmldir->plugins()[dynamicPluginsFound].name));
+ error.setDescription(QQmlImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(qmldir.plugins()[dynamicPluginsFound].name));
error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
errors->prepend(error);
}
@@ -1187,17 +1187,17 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
}
bool QQmlImportsPrivate::getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
- const QQmlTypeLoaderQmldirContent **qmldir, QList<QQmlError> *errors)
+ QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors)
{
Q_ASSERT(errors);
Q_ASSERT(qmldir);
*qmldir = typeLoader->qmldirContent(qmldirIdentifier);
- if (*qmldir) {
+ if ((*qmldir).hasContent()) {
// Ensure that parsing was successful
- if ((*qmldir)->hasError()) {
+ if ((*qmldir).hasError()) {
QUrl url = QUrl::fromLocalFile(qmldirIdentifier);
- const QList<QQmlError> qmldirErrors = (*qmldir)->errors(uri);
+ const QList<QQmlError> qmldirErrors = (*qmldir).errors(uri);
for (int i = 0; i < qmldirErrors.size(); ++i) {
QQmlError error = qmldirErrors.at(i);
error.setUrl(url);
@@ -1322,14 +1322,14 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ
return false;
}
-bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
+bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, int vmaj, int vmin,
QList<QQmlError> *errors)
{
int lowest_min = INT_MAX;
int highest_min = INT_MIN;
typedef QQmlDirComponents::const_iterator ConstIterator;
- const QQmlDirComponents &components = qmldir->components();
+ const QQmlDirComponents &components = qmldir.components();
ConstIterator cend = components.constEnd();
for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) {
@@ -1353,7 +1353,7 @@ bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent
}
typedef QList<QQmlDirParser::Script>::const_iterator SConstIterator;
- const QQmlDirScripts &scripts = qmldir->scripts();
+ const QQmlDirScripts &scripts = qmldir.scripts();
SConstIterator send = scripts.constEnd();
for (SConstIterator sit = scripts.constBegin(); sit != send; ++sit) {
@@ -1445,14 +1445,14 @@ bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &pre
Q_ASSERT(inserted);
if (!incomplete) {
- const QQmlTypeLoaderQmldirContent *qmldir = nullptr;
+ QQmlTypeLoaderQmldirContent qmldir;
if (!qmldirIdentifier.isEmpty()) {
if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
return false;
- if (qmldir) {
- if (!importExtension(qmldir->pluginLocation(), uri, vmaj, vmin, database, qmldir, errors))
+ if (qmldir.hasContent()) {
+ if (!importExtension(qmldir.pluginLocation(), uri, vmaj, vmin, database, qmldir, errors))
return false;
if (!inserted->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors))
@@ -1470,7 +1470,7 @@ bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &pre
error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri));
errors->prepend(error);
return false;
- } else if ((vmaj >= 0) && (vmin >= 0) && qmldir) {
+ } else if ((vmaj >= 0) && (vmin >= 0) && qmldir.hasContent()) {
// Verify that the qmldir content is valid for this version
if (!validateQmldirVersion(qmldir, uri, vmaj, vmin, errors))
return false;
@@ -1564,12 +1564,12 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
Q_ASSERT(inserted);
if (!incomplete && !qmldirIdentifier.isEmpty()) {
- const QQmlTypeLoaderQmldirContent *qmldir = nullptr;
+ QQmlTypeLoaderQmldirContent qmldir;
if (!getQmldirContent(qmldirIdentifier, importUri, &qmldir, errors))
return false;
- if (qmldir) {
- if (!importExtension(qmldir->pluginLocation(), importUri, vmaj, vmin, database, qmldir, errors))
+ if (qmldir.hasContent()) {
+ if (!importExtension(qmldir.pluginLocation(), importUri, vmaj, vmin, database, qmldir, errors))
return false;
if (!inserted->setQmldirContent(url, qmldir, nameSpace, errors))
@@ -1588,14 +1588,14 @@ bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString &
Q_ASSERT(nameSpace);
if (QQmlImportInstance *import = nameSpace->findImport(uri)) {
- const QQmlTypeLoaderQmldirContent *qmldir = nullptr;
+ QQmlTypeLoaderQmldirContent qmldir;
if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
return false;
- if (qmldir) {
+ if (qmldir.hasContent()) {
int vmaj = import->majversion;
int vmin = import->minversion;
- if (!importExtension(qmldir->pluginLocation(), uri, vmaj, vmin, database, qmldir, errors))
+ if (!importExtension(qmldir.pluginLocation(), uri, vmaj, vmin, database, qmldir, errors))
return false;
if (import->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors)) {
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index b70bb5253c..2437979ef8 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -85,7 +85,7 @@ struct QQmlImportInstance
QQmlDirComponents qmlDirComponents; // a copy of the components listed in the qmldir
QQmlDirScripts qmlDirScripts; // a copy of the scripts in the qmldir
- bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent *qmldir,
+ bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent &qmldir,
QQmlImportNamespace *nameSpace, QList<QQmlError> *errors);
static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin);
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index 4546a4423f..df168960c6 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -367,10 +367,8 @@ finishIncubate:
enginePriv->inProgressCreations--;
if (0 == enginePriv->inProgressCreations) {
- while (enginePriv->erroredBindings) {
- enginePriv->warning(enginePriv->erroredBindings);
- enginePriv->erroredBindings->removeError();
- }
+ while (enginePriv->erroredBindings)
+ enginePriv->warning(enginePriv->erroredBindings->removeError());
}
} else if (!creator.isNull()) {
vmeGuard.guard(creator.data());
@@ -575,10 +573,8 @@ void QQmlIncubator::clear()
enginePriv->inProgressCreations--;
if (0 == enginePriv->inProgressCreations) {
- while (enginePriv->erroredBindings) {
- enginePriv->warning(enginePriv->erroredBindings);
- enginePriv->erroredBindings->removeError();
- }
+ while (enginePriv->erroredBindings)
+ enginePriv->warning(enginePriv->erroredBindings->removeError());
}
}
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 74148e3ca4..93ec9421ed 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -97,8 +97,7 @@ QQmlJavaScriptExpression::QQmlJavaScriptExpression()
m_context(nullptr),
m_prevExpression(nullptr),
m_nextExpression(nullptr),
- m_v4Function(nullptr),
- m_sourceLocation(nullptr)
+ m_v4Function(nullptr)
{
}
@@ -115,8 +114,6 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
clearError();
if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion.
m_scopeObject.asT2()->_s = nullptr;
-
- delete m_sourceLocation;
}
void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v)
@@ -137,20 +134,11 @@ void QQmlJavaScriptExpression::resetNotifyOnValueChanged()
QQmlSourceLocation QQmlJavaScriptExpression::sourceLocation() const
{
- if (m_sourceLocation)
- return *m_sourceLocation;
if (m_v4Function)
return m_v4Function->sourceLocation();
return QQmlSourceLocation();
}
-void QQmlJavaScriptExpression::setSourceLocation(const QQmlSourceLocation &location)
-{
- if (m_sourceLocation)
- delete m_sourceLocation;
- m_sourceLocation = new QQmlSourceLocation(location);
-}
-
void QQmlJavaScriptExpression::setContext(QQmlContextData *context)
{
if (m_prevExpression) {
@@ -451,15 +439,11 @@ void QQmlJavaScriptExpression::createQmlBinding(QQmlContextData *ctxt, QObject *
QV4::Script script(v4, qmlContext, code, filename, line);
script.parse();
if (v4->hasException) {
- QQmlError error = v4->catchExceptionAsQmlError();
- if (error.description().isEmpty())
- error.setDescription(QLatin1String("Exception occurred during function evaluation"));
- if (error.line() == -1)
- error.setLine(line);
- if (error.url().isEmpty())
- error.setUrl(QUrl::fromLocalFile(filename));
- error.setObject(qmlScope);
- ep->warning(error);
+ QQmlDelayedError *error = delayedError();
+ error->catchJavaScriptException(v4);
+ error->setErrorObject(qmlScope);
+ if (!error->addError(ep))
+ ep->warning(error->error());
return;
}
setupFunction(qmlContext, script.vmFunction);
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index a028850074..01af3b89ca 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -63,16 +63,18 @@ class QQmlDelayedError
{
public:
inline QQmlDelayedError() : nextError(nullptr), prevError(nullptr) {}
- inline ~QQmlDelayedError() { removeError(); }
+ inline ~QQmlDelayedError() { (void)removeError(); }
bool addError(QQmlEnginePrivate *);
- inline void removeError() {
- if (!prevError) return;
- if (nextError) nextError->prevError = prevError;
- *prevError = nextError;
- nextError = nullptr;
- prevError = nullptr;
+ Q_REQUIRED_RESULT inline QQmlError removeError() {
+ if (prevError) {
+ if (nextError) nextError->prevError = prevError;
+ *prevError = nextError;
+ nextError = nullptr;
+ prevError = nullptr;
+ }
+ return m_error;
}
inline bool isValid() const { return m_error.isValid(); }
@@ -114,8 +116,7 @@ public:
inline QObject *scopeObject() const;
inline void setScopeObject(QObject *v);
- QQmlSourceLocation sourceLocation() const;
- void setSourceLocation(const QQmlSourceLocation &location);
+ virtual QQmlSourceLocation sourceLocation() const;
bool isValid() const { return context() != nullptr; }
@@ -186,7 +187,6 @@ private:
QV4::PersistentValue m_qmlScope;
QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compilationUnit;
QV4::Function *m_v4Function;
- QQmlSourceLocation *m_sourceLocation; // used for Qt.binding() created functions
};
class QQmlPropertyCapture
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 7754f0fddc..8fda7f6f77 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -51,6 +51,7 @@
#include <QtCore/qbitarray.h>
#include <QtCore/qreadwritelock.h>
#include <QtCore/private/qmetaobject_p.h>
+#include <QtCore/qloggingcategory.h>
#include <qmetatype.h>
#include <qobjectdefs.h>
@@ -63,6 +64,8 @@
#include <ctype.h>
#include "qqmlcomponent.h"
+Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
+
QT_BEGIN_NAMESPACE
struct QQmlMetaTypeData
@@ -2539,18 +2542,46 @@ QList<QQmlType> QQmlMetaType::qmlSingletonTypes()
return retn;
}
-const QV4::CompiledData::Unit *QQmlMetaType::findCachedCompilationUnit(const QUrl &uri)
+const QV4::CompiledData::Unit *QQmlMetaType::findCachedCompilationUnit(const QUrl &uri, CachedUnitLookupError *status)
{
QMutexLocker lock(metaTypeDataLock());
QQmlMetaTypeData *data = metaTypeData();
for (const auto lookup : qAsConst(data->lookupCachedQmlUnit)) {
- if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri))
+ if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri)) {
+ QString error;
+ if (!unit->qmlData->verifyHeader(QDateTime(), &error)) {
+ qCDebug(DBG_DISK_CACHE) << "Error loading pre-compiled file " << uri << ":" << error;
+ if (status)
+ *status = CachedUnitLookupError::VersionMismatch;
+ return nullptr;
+ }
+ if (status)
+ *status = CachedUnitLookupError::NoError;
return unit->qmlData;
+ }
}
+
+ if (status)
+ *status = CachedUnitLookupError::NoUnitFound;
+
return nullptr;
}
+void QQmlMetaType::prependCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler)
+{
+ QMutexLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ data->lookupCachedQmlUnit.prepend(handler);
+}
+
+void QQmlMetaType::removeCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler)
+{
+ QMutexLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ data->lookupCachedQmlUnit.removeAll(handler);
+}
+
/*!
Returns the pretty QML type name (e.g. 'Item' instead of 'QtQuickItem') for the given object.
*/
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 07bef526ba..cd7afc8a01 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -133,7 +133,17 @@ public:
static QList<QQmlPrivate::AutoParentFunction> parentFunctions();
- static const QV4::CompiledData::Unit *findCachedCompilationUnit(const QUrl &uri);
+ enum class CachedUnitLookupError {
+ NoError,
+ NoUnitFound,
+ VersionMismatch
+ };
+
+ static const QV4::CompiledData::Unit *findCachedCompilationUnit(const QUrl &uri, CachedUnitLookupError *status);
+
+ // used by tst_qqmlcachegen.cpp
+ static void prependCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler);
+ static void removeCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler);
static bool namespaceContainsRegistrations(const QString &, int majorVersion);
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 36e56a01f8..7051fb51da 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -55,6 +55,7 @@
#include <private/qqmlvaluetypeproxybinding_p.h>
#include <private/qqmldebugconnector_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
+#include <private/qjsvalue_p.h>
QT_USE_NAMESPACE
@@ -780,7 +781,7 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
qSwap(_currentList, savedList);
}
-bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
+bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProperty, const QV4::CompiledData::Binding *binding)
{
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
@@ -802,7 +803,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
}
// ### resolve this at compile time
- if (property && property->propType() == qMetaTypeId<QQmlScriptString>()) {
+ if (bindingProperty && bindingProperty->propType() == qMetaTypeId<QQmlScriptString>()) {
QQmlScriptString ss(binding->valueAsScriptString(qmlUnit), context->asQQmlContext(), _scopeObject);
ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid;
ss.d.data()->lineNumber = binding->location.line;
@@ -815,7 +816,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
QQmlPropertyData::RemoveBindingOnAliasWrite;
int propertyWriteStatus = -1;
void *argv[] = { &ss, nullptr, &propertyWriteStatus, &propertyWriteFlags };
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
return true;
}
@@ -826,7 +827,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
return false;
}
- if (!property) // ### error
+ if (!bindingProperty) // ### error
return true;
if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
@@ -838,20 +839,20 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
const QQmlPropertyData *valueTypeProperty = nullptr;
QObject *bindingTarget = _bindingTarget;
- if (QQmlValueTypeFactory::isValueType(property->propType())) {
- valueType = QQmlValueTypeFactory::valueType(property->propType());
+ if (QQmlValueTypeFactory::isValueType(bindingProperty->propType())) {
+ valueType = QQmlValueTypeFactory::valueType(bindingProperty->propType());
if (!valueType) {
recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
return false;
}
- valueType->read(_qobject, property->coreIndex());
+ valueType->read(_qobject, bindingProperty->coreIndex());
groupObject = valueType;
- valueTypeProperty = property;
+ valueTypeProperty = bindingProperty;
} else {
void *argv[1] = { &groupObject };
- QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex(), argv);
+ QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, bindingProperty->coreIndex(), argv);
if (!groupObject) {
recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
return false;
@@ -864,21 +865,21 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
return false;
if (valueType)
- valueType->write(_qobject, property->coreIndex(), QQmlPropertyData::BypassInterceptor);
+ valueType->write(_qobject, bindingProperty->coreIndex(), QQmlPropertyData::BypassInterceptor);
return true;
}
}
- if (_ddata->hasBindingBit(property->coreIndex()) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+ if (_ddata->hasBindingBit(bindingProperty->coreIndex()) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
&& !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
&& !_valueTypeProperty)
- QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(property->coreIndex()));
+ QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex()));
if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->containsTranslations()) {
if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) {
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
- int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex());
+ int signalIndex = _propertyCache->methodIndexToSignalIndex(bindingProperty->coreIndex());
QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine);
QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_bindingTarget, signalIndex,
context, _scopeObject, runtimeFunction, currentQmlContext());
@@ -890,34 +891,44 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
// the point property (_qobjectForBindings) and after evaluating the expression,
// the result is written to a value type virtual property, that contains the sub-index
// of the "x" property.
- QQmlBinding *qmlBinding;
- const QQmlPropertyData *prop = property;
+ QQmlBinding::Ptr qmlBinding;
+ const QQmlPropertyData *targetProperty = bindingProperty;
const QQmlPropertyData *subprop = nullptr;
if (_valueTypeProperty) {
- prop = _valueTypeProperty;
- subprop = property;
+ targetProperty = _valueTypeProperty;
+ subprop = bindingProperty;
}
if (binding->containsTranslations()) {
qmlBinding = QQmlBinding::createTranslationBinding(compilationUnit, binding, _scopeObject, context);
} else {
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
- qmlBinding = QQmlBinding::create(prop, runtimeFunction, _scopeObject, context, currentQmlContext());
+ qmlBinding = QQmlBinding::create(targetProperty, runtimeFunction, _scopeObject, context, currentQmlContext());
}
- qmlBinding->setTarget(_bindingTarget, *prop, subprop);
- sharedState->allCreatedBindings.push(QQmlAbstractBinding::Ptr(qmlBinding));
+ auto bindingTarget = _bindingTarget;
+ auto valueTypeProperty = _valueTypeProperty;
+ auto assignBinding = [qmlBinding, bindingTarget, targetProperty, subprop, bindingProperty, valueTypeProperty](QQmlObjectCreatorSharedState *sharedState) -> bool {
+ if (!qmlBinding->setTarget(bindingTarget, *targetProperty, subprop) && targetProperty->isAlias())
+ return false;
- if (property->isAlias()) {
- QQmlPropertyPrivate::setBinding(qmlBinding, QQmlPropertyPrivate::DontEnable);
- } else {
- qmlBinding->addToObject();
+ sharedState->allCreatedBindings.push(qmlBinding);
+
+ if (bindingProperty->isAlias()) {
+ QQmlPropertyPrivate::setBinding(qmlBinding.data(), QQmlPropertyPrivate::DontEnable);
+ } else {
+ qmlBinding->addToObject();
- if (!_valueTypeProperty) {
- QQmlData *targetDeclarativeData = QQmlData::get(_bindingTarget);
- Q_ASSERT(targetDeclarativeData);
- targetDeclarativeData->setPendingBindingBit(_bindingTarget, property->coreIndex());
+ if (!valueTypeProperty) {
+ QQmlData *targetDeclarativeData = QQmlData::get(bindingTarget);
+ Q_ASSERT(targetDeclarativeData);
+ targetDeclarativeData->setPendingBindingBit(bindingTarget, bindingProperty->coreIndex());
+ }
}
- }
+
+ return true;
+ };
+ if (!assignBinding(sharedState.data()))
+ pendingAliasBindings.push_back(assignBinding);
}
return true;
}
@@ -934,9 +945,9 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
QObject *target = createdSubObject->parent();
QQmlProperty prop;
if (_valueTypeProperty)
- prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, property, context);
+ prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, bindingProperty, context);
else
- prop = QQmlPropertyPrivate::restore(target, *property, nullptr, context);
+ prop = QQmlPropertyPrivate::restore(target, *bindingProperty, nullptr, context);
vs->setTarget(prop);
return true;
}
@@ -946,8 +957,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
QObject *target = createdSubObject->parent();
QQmlPropertyIndex propertyIndex;
- if (property->isAlias()) {
- QQmlPropertyIndex originalIndex(property->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
+ if (bindingProperty->isAlias()) {
+ QQmlPropertyIndex originalIndex(bindingProperty->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
QQmlPropertyIndex propIndex;
QQmlPropertyPrivate::findAliasTarget(target, originalIndex, &target, &propIndex);
QQmlData *data = QQmlData::get(target);
@@ -964,9 +975,9 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
} else {
QQmlProperty prop;
if (_valueTypeProperty)
- prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, property, context);
+ prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, bindingProperty, context);
else
- prop = QQmlPropertyPrivate::restore(target, *property, nullptr, context);
+ prop = QQmlPropertyPrivate::restore(target, *bindingProperty, nullptr, context);
vi->setTarget(prop);
propertyIndex = QQmlPropertyPrivate::propertyIndex(prop);
}
@@ -982,8 +993,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
// Assigning object to signal property?
if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
- if (!property->isFunction()) {
- recordError(binding->valueLocation, tr("Cannot assign an object to signal property %1").arg(property->name(_qobject)));
+ if (!bindingProperty->isFunction()) {
+ recordError(binding->valueLocation, tr("Cannot assign an object to signal property %1").arg(bindingProperty->name(_qobject)));
return false;
}
QMetaMethod method = QQmlMetaType::defaultMethod(createdSubObject);
@@ -992,7 +1003,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
return false;
}
- QMetaMethod signalMethod = _qobject->metaObject()->method(property->coreIndex());
+ QMetaMethod signalMethod = _qobject->metaObject()->method(bindingProperty->coreIndex());
if (!QMetaObject::checkConnectArgs(signalMethod, method)) {
recordError(binding->valueLocation,
tr("Cannot connect mismatched signal/slot %1 %vs. %2")
@@ -1001,7 +1012,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
return false;
}
- QQmlPropertyPrivate::connect(_qobject, property->coreIndex(), createdSubObject, method.methodIndex());
+ QQmlPropertyPrivate::connect(_qobject, bindingProperty->coreIndex(), createdSubObject, method.methodIndex());
return true;
}
@@ -1010,32 +1021,43 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
int propertyWriteStatus = -1;
void *argv[] = { nullptr, nullptr, &propertyWriteStatus, &propertyWriteFlags };
- if (const char *iid = QQmlMetaType::interfaceIId(property->propType())) {
+ if (const char *iid = QQmlMetaType::interfaceIId(bindingProperty->propType())) {
void *ptr = createdSubObject->qt_metacast(iid);
if (ptr) {
argv[0] = &ptr;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
} else {
recordError(binding->location, tr("Cannot assign object to interface property"));
return false;
}
- } else if (property->propType() == QMetaType::QVariant) {
- if (property->isVarProperty()) {
+ } else if (bindingProperty->propType() == QMetaType::QVariant) {
+ if (bindingProperty->isVarProperty()) {
QV4::Scope scope(v4);
QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(engine->handle(), createdSubObject));
- _vmeMetaObject->setVMEProperty(property->coreIndex(), wrappedObject);
+ _vmeMetaObject->setVMEProperty(bindingProperty->coreIndex(), wrappedObject);
} else {
QVariant value = QVariant::fromValue(createdSubObject);
argv[0] = &value;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
}
- } else if (property->isQList()) {
+ } else if (bindingProperty->propType() == qMetaTypeId<QJSValue>()) {
+ QV4::Scope scope(v4);
+ QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(engine->handle(), createdSubObject));
+ if (bindingProperty->isVarProperty()) {
+ _vmeMetaObject->setVMEProperty(bindingProperty->coreIndex(), wrappedObject);
+ } else {
+ QJSValue value;
+ QJSValuePrivate::setValue(&value, v4, wrappedObject);
+ argv[0] = &value;
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
+ }
+ } else if (bindingProperty->isQList()) {
Q_ASSERT(_currentList.object);
void *itemToAdd = createdSubObject;
const char *iid = nullptr;
- int listItemType = QQmlEnginePrivate::get(engine)->listType(property->propType());
+ int listItemType = QQmlEnginePrivate::get(engine)->listType(bindingProperty->propType());
if (listItemType != -1)
iid = QQmlMetaType::interfaceIId(listItemType);
if (iid)
@@ -1051,17 +1073,17 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
} else {
// pointer compatibility was tested in QQmlPropertyValidator at type compile time
argv[0] = &createdSubObject;
- QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv);
+ QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
}
return true;
}
- if (property->isQList()) {
+ if (bindingProperty->isQList()) {
recordError(binding->location, tr("Cannot assign primitives to lists"));
return false;
}
- setPropertyValue(property, binding);
+ setPropertyValue(bindingProperty, binding);
return true;
}
@@ -1274,12 +1296,33 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
qSwap(_qmlContext, qmlContext);
- bool result = populateInstance(index, instance, /*binding target*/instance, /*value type property*/nullptr);
+ bool ok = populateInstance(index, instance, /*binding target*/instance, /*value type property*/nullptr);
+ if (ok) {
+ if (isContextObject && !pendingAliasBindings.empty()) {
+ bool processedAtLeastOneBinding = false;
+ do {
+ processedAtLeastOneBinding = false;
+ for (std::vector<PendingAliasBinding>::iterator it = pendingAliasBindings.begin();
+ it != pendingAliasBindings.end(); ) {
+ if ((*it)(sharedState.data())) {
+ it = pendingAliasBindings.erase(it);
+ processedAtLeastOneBinding = true;
+ } else {
+ ++it;
+ }
+ }
+ } while (processedAtLeastOneBinding && pendingAliasBindings.empty());
+ Q_ASSERT(pendingAliasBindings.empty());
+ }
+ } else {
+ // an error occurred, so we can't setup the pending alias bindings
+ pendingAliasBindings.clear();
+ }
qSwap(_qmlContext, qmlContext);
qSwap(_scopeObject, scopeObject);
- return result ? instance : nullptr;
+ return ok ? instance : nullptr;
}
QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 399a5f6d4a..67a5bdd827 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -161,6 +161,9 @@ private:
QV4::QmlContext *_qmlContext;
friend struct QQmlObjectCreatorRecursionWatcher;
+
+ typedef std::function<bool(QQmlObjectCreatorSharedState *sharedState)> PendingAliasBinding;
+ std::vector<PendingAliasBinding> pendingAliasBindings;
};
struct QQmlObjectCreatorRecursionWatcher
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index ebf296b29d..c4487f91a3 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -877,6 +877,7 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, QQmlPropertyIndex bin
void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, QQmlPropertyData::WriteFlags writeFlags)
{
Q_ASSERT(binding);
+ Q_ASSERT(binding->targetObject());
QObject *object = binding->targetObject();
const QQmlPropertyIndex index = binding->targetPropertyIndex();
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index 51a191a41f..b78a2ddd20 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -81,6 +81,7 @@ template <typename T> class QQmlPropertyCacheAliasCreator;
// We have this somewhat awful split between RawData and Data so that RawData can be
// used in unions. In normal code, you should always use Data which initializes RawData
// to an invalid state on construction.
+// ### We should be able to remove this split nowadays
class QQmlPropertyRawData
{
public:
@@ -273,20 +274,20 @@ public:
private:
Flags _flags;
- qint16 _coreIndex;
- quint16 _propType;
+ qint16 _coreIndex = 0;
+ quint16 _propType = 0;
// The notify index is in the range returned by QObjectPrivate::signalIndex().
// This is different from QMetaMethod::methodIndex().
- qint16 _notifyIndex;
- qint16 _overrideIndex;
+ qint16 _notifyIndex = 0;
+ qint16 _overrideIndex = 0;
- quint8 _revision;
- quint8 _typeMinorVersion;
- qint16 _metaObjectOffset;
+ quint8 _revision = 0;
+ quint8 _typeMinorVersion = 0;
+ qint16 _metaObjectOffset = 0;
- QQmlPropertyCacheMethodArguments *_arguments;
- StaticMetaCallFunction _staticMetaCallFunction;
+ QQmlPropertyCacheMethodArguments *_arguments = nullptr;
+ StaticMetaCallFunction _staticMetaCallFunction = nullptr;
friend class QQmlPropertyData;
friend class QQmlPropertyCache;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 81bda2c3bb..ed742c3681 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -984,16 +984,6 @@ void QQmlTypeLoader::setProfiler(QQmlProfiler *profiler)
}
#endif
-void QQmlTypeLoader::lock()
-{
- m_thread->lock();
-}
-
-void QQmlTypeLoader::unlock()
-{
- m_thread->unlock();
-}
-
struct PlainLoader {
void loadThread(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
{
@@ -1276,6 +1266,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data)
QML_MEMORY_SCOPE_URL(blob->url());
QQmlDataBlob::SourceCodeData d;
d.inlineSourceCode = QString::fromUtf8(data);
+ d.hasInlineSourceCode = true;
setData(blob, d);
}
@@ -1387,8 +1378,8 @@ bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::Compile
if (!importQualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
- const QQmlTypeLoaderQmldirContent *qmldir = typeLoader()->qmldirContent(qmldirIdentifier);
- const auto qmldirScripts = qmldir->scripts();
+ const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirIdentifier);
+ const auto qmldirScripts = qmldir.scripts();
for (const QQmlDirParser::Script &script : qmldirScripts) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
@@ -1435,8 +1426,8 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
if (!importQualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
- const QQmlTypeLoaderQmldirContent *qmldir = typeLoader()->qmldirContent(qmldirFilePath);
- const auto qmldirScripts = qmldir->scripts();
+ const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirFilePath);
+ const auto qmldirScripts = qmldir.scripts();
for (const QQmlDirParser::Script &script : qmldirScripts) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl);
@@ -1601,6 +1592,7 @@ QString QQmlTypeLoaderQmldirContent::typeNamespace() const
void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QString &content)
{
+ m_hasContent = true;
m_location = location;
m_parser.parse(content);
}
@@ -1639,8 +1631,10 @@ bool QQmlTypeLoaderQmldirContent::designerSupported() const
Constructs a new type loader that uses the given \a engine.
*/
QQmlTypeLoader::QQmlTypeLoader(QQmlEngine *engine)
- : m_engine(engine), m_thread(new QQmlTypeLoaderThread(this)),
- m_typeCacheTrimThreshold(TYPELOADER_MINIMUM_TRIM_THRESHOLD)
+ : m_engine(engine)
+ , m_thread(new QQmlTypeLoaderThread(this))
+ , m_mutex(m_thread->mutex())
+ , m_typeCacheTrimThreshold(TYPELOADER_MINIMUM_TRIM_THRESHOLD)
{
}
@@ -1684,9 +1678,11 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode)
typeData = new QQmlTypeData(url, this);
// TODO: if (compiledData == 0), is it safe to omit this insertion?
m_typeCache.insert(url, typeData);
- if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(typeData->url())) {
+ QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
+ if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(typeData->url(), &error)) {
QQmlTypeLoader::loadWithCachedUnit(typeData, cachedUnit, mode);
} else {
+ typeData->setCachedUnitStatus(error);
QQmlTypeLoader::load(typeData, mode);
}
} else if ((mode == PreferSynchronous || mode == Synchronous) && QQmlFile::isSynchronous(url)) {
@@ -1745,9 +1741,11 @@ QQmlScriptBlob *QQmlTypeLoader::getScript(const QUrl &url)
scriptBlob = new QQmlScriptBlob(url, this);
m_scriptCache.insert(url, scriptBlob);
- if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(scriptBlob->url())) {
+ QQmlMetaType::CachedUnitLookupError error;
+ if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(scriptBlob->url(), &error)) {
QQmlTypeLoader::loadWithCachedUnit(scriptBlob, cachedUnit);
} else {
+ scriptBlob->setCachedUnitStatus(error);
QQmlTypeLoader::load(scriptBlob);
}
}
@@ -1831,6 +1829,7 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path)
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
QString dirPath(path.left(lastSlash));
+ LockHolder<QQmlTypeLoader> holder(this);
if (!m_importDirCache.contains(dirPath)) {
bool exists = QDir(dirPath).exists();
QCache<QString, bool> *entry = exists ? new QCache<QString, bool> : nullptr;
@@ -1894,6 +1893,7 @@ bool QQmlTypeLoader::directoryExists(const QString &path)
--length;
QString dirPath(path.left(length));
+ LockHolder<QQmlTypeLoader> holder(this);
if (!m_importDirCache.contains(dirPath)) {
bool exists = QDir(dirPath).exists();
QCache<QString, bool> *files = exists ? new QCache<QString, bool> : nullptr;
@@ -1912,8 +1912,10 @@ Return a QQmlTypeLoaderQmldirContent for absoluteFilePath. The QQmlTypeLoaderQm
It can also be a remote path for a remote directory import, but it will have been cached by now in this case.
*/
-const QQmlTypeLoaderQmldirContent *QQmlTypeLoader::qmldirContent(const QString &filePathIn)
+const QQmlTypeLoaderQmldirContent QQmlTypeLoader::qmldirContent(const QString &filePathIn)
{
+ LockHolder<QQmlTypeLoader> holder(this);
+
QString filePath;
// Try to guess if filePathIn is already a URL. This is necessarily fragile, because
@@ -1927,39 +1929,39 @@ const QQmlTypeLoaderQmldirContent *QQmlTypeLoader::qmldirContent(const QString &
filePath = filePathIn;
} else {
filePath = QQmlFile::urlToLocalFileOrQrc(url);
- if (filePath.isEmpty()) // Can't load the remote here, but should be cached
- return *(m_importQmlDirCache.value(filePathIn));
+ if (filePath.isEmpty()) { // Can't load the remote here, but should be cached
+ if (auto entry = m_importQmlDirCache.value(filePathIn))
+ return **entry;
+ else
+ return QQmlTypeLoaderQmldirContent();
+ }
}
- QQmlTypeLoaderQmldirContent *qmldir;
QQmlTypeLoaderQmldirContent **val = m_importQmlDirCache.value(filePath);
- if (!val) {
- qmldir = new QQmlTypeLoaderQmldirContent;
+ if (val)
+ return **val;
+ QQmlTypeLoaderQmldirContent *qmldir = new QQmlTypeLoaderQmldirContent;
#define ERROR(description) { QQmlError e; e.setDescription(description); qmldir->setError(e); }
#define NOT_READABLE_ERROR QString(QLatin1String("module \"$$URI$$\" definition \"%1\" not readable"))
#define CASE_MISMATCH_ERROR QString(QLatin1String("cannot load module \"$$URI$$\": File name case mismatch for \"%1\""))
- QFile file(filePath);
- if (!QQml_isFileCaseCorrect(filePath)) {
- ERROR(CASE_MISMATCH_ERROR.arg(filePath));
- } else if (file.open(QFile::ReadOnly)) {
- QByteArray data = file.readAll();
- qmldir->setContent(filePath, QString::fromUtf8(data));
- } else {
- ERROR(NOT_READABLE_ERROR.arg(filePath));
- }
+ QFile file(filePath);
+ if (!QQml_isFileCaseCorrect(filePath)) {
+ ERROR(CASE_MISMATCH_ERROR.arg(filePath));
+ } else if (file.open(QFile::ReadOnly)) {
+ QByteArray data = file.readAll();
+ qmldir->setContent(filePath, QString::fromUtf8(data));
+ } else {
+ ERROR(NOT_READABLE_ERROR.arg(filePath));
+ }
#undef ERROR
#undef NOT_READABLE_ERROR
#undef CASE_MISMATCH_ERROR
- m_importQmlDirCache.insert(filePath, qmldir);
- } else {
- qmldir = *val;
- }
-
- return qmldir;
+ m_importQmlDirCache.insert(filePath, qmldir);
+ return *qmldir;
}
void QQmlTypeLoader::setQmldirContent(const QString &url, const QString &content)
@@ -2446,8 +2448,13 @@ void QQmlTypeData::dataReceived(const SourceCodeData &data)
if (isError())
return;
- if (!m_backupSourceCode.exists()) {
- setError(QQmlTypeLoader::tr("No such file or directory"));
+ if (!m_backupSourceCode.exists() || m_backupSourceCode.isEmpty()) {
+ if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
+ setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
+ else if (!m_backupSourceCode.exists())
+ setError(QQmlTypeLoader::tr("No such file or directory"));
+ else
+ setError(QQmlTypeLoader::tr("File is empty"));
return;
}
@@ -2999,6 +3006,13 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
}
}
+ if (!data.exists()) {
+ if (m_cachedUnitStatus == QQmlMetaType::CachedUnitLookupError::VersionMismatch)
+ setError(QQmlTypeLoader::tr("File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile"));
+ else
+ setError(QQmlTypeLoader::tr("No such file or directory"));
+ return;
+ }
QmlIR::Document irUnit(isDebugging());
@@ -3196,7 +3210,7 @@ void QQmlQmldirData::initializeFromCachedUnit(const QV4::CompiledData::Unit *)
QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const
{
error->clear();
- if (!inlineSourceCode.isEmpty())
+ if (hasInlineSourceCode)
return inlineSourceCode;
QFile f(fileInfo.absoluteFilePath());
@@ -3223,7 +3237,7 @@ QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const
QDateTime QQmlDataBlob::SourceCodeData::sourceTimeStamp() const
{
- if (!inlineSourceCode.isEmpty())
+ if (hasInlineSourceCode)
return QDateTime();
QDateTime timeStamp = fileInfo.lastModified();
@@ -3238,11 +3252,18 @@ QDateTime QQmlDataBlob::SourceCodeData::sourceTimeStamp() const
bool QQmlDataBlob::SourceCodeData::exists() const
{
- if (!inlineSourceCode.isEmpty())
+ if (hasInlineSourceCode)
return true;
return fileInfo.exists();
}
+bool QQmlDataBlob::SourceCodeData::isEmpty() const
+{
+ if (hasInlineSourceCode)
+ return inlineSourceCode.isEmpty();
+ return fileInfo.size() == 0;
+}
+
QT_END_NAMESPACE
#include "qqmltypeloader.moc"
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 713f707387..5988632547 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -140,11 +140,13 @@ public:
QString readAll(QString *error) const;
QDateTime sourceTimeStamp() const;
bool exists() const;
+ bool isEmpty() const;
private:
friend class QQmlDataBlob;
friend class QQmlTypeLoader;
QString inlineSourceCode;
QFileInfo fileInfo;
+ bool hasInlineSourceCode = false;
};
protected:
@@ -228,12 +230,16 @@ class QQmlTypeLoaderQmldirContent
{
private:
friend class QQmlTypeLoader;
- QQmlTypeLoaderQmldirContent();
void setContent(const QString &location, const QString &content);
void setError(const QQmlError &);
public:
+ QQmlTypeLoaderQmldirContent();
+ QQmlTypeLoaderQmldirContent(const QQmlTypeLoaderQmldirContent &) = default;
+ QQmlTypeLoaderQmldirContent &operator=(const QQmlTypeLoaderQmldirContent &) = default;
+
+ bool hasContent() const { return m_hasContent; }
bool hasError() const;
QList<QQmlError> errors(const QString &uri) const;
@@ -250,6 +256,7 @@ public:
private:
QQmlDirParser m_parser;
QString m_location;
+ bool m_hasContent = false;
};
class Q_QML_PRIVATE_EXPORT QQmlTypeLoader
@@ -266,6 +273,8 @@ public:
const QQmlImports &imports() const { return m_importCache; }
+ void setCachedUnitStatus(QQmlMetaType::CachedUnitLookupError status) { m_cachedUnitStatus = status; }
+
protected:
bool addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors);
@@ -288,6 +297,7 @@ public:
QQmlImports m_importCache;
QHash<const QV4::CompiledData::Import*, int> m_unresolvedImports;
QList<QQmlQmldirData *> m_qmldirs;
+ QQmlMetaType::CachedUnitLookupError m_cachedUnitStatus = QQmlMetaType::CachedUnitLookupError::NoError;
};
QQmlTypeLoader(QQmlEngine *);
@@ -304,7 +314,7 @@ public:
QString absoluteFilePath(const QString &path);
bool directoryExists(const QString &path);
- const QQmlTypeLoaderQmldirContent *qmldirContent(const QString &filePath);
+ const QQmlTypeLoaderQmldirContent qmldirContent(const QString &filePath);
void setQmldirContent(const QString &filePath, const QString &content);
void clearCache();
@@ -313,8 +323,8 @@ public:
bool isTypeLoaded(const QUrl &url) const;
bool isScriptLoaded(const QUrl &url) const;
- void lock();
- void unlock();
+ void lock() { m_mutex.lock(); }
+ void unlock() { m_mutex.unlock(); }
void load(QQmlDataBlob *, Mode = PreferSynchronous);
void loadWithStaticData(QQmlDataBlob *, const QByteArray &, Mode = PreferSynchronous);
@@ -381,6 +391,7 @@ private:
QQmlEngine *m_engine;
QQmlTypeLoaderThread *m_thread;
+ QMutex &m_mutex;
#if QT_CONFIG(qml_debug)
QScopedPointer<QQmlProfiler> m_profiler;
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 6dbf6ad8c1..ce35e966aa 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -388,6 +388,7 @@ ReturnedValue QQmlTypeWrapper::instanceOf(const Object *typeObject, const Value
QQmlTypeData *td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
CompiledData::CompilationUnit *cu = td->compilationUnit();
myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
+ td->release();
} else {
myQmlType = qenginepriv->metaObjectForType(myTypeId);
}
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index a28115d192..6196a09d94 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -463,8 +463,12 @@ bool QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
- QV4::ScopedContext ctx(scope, bindingFunction->scope());
- QQmlBinding *newBinding = QQmlBinding::create(&cacheData, bindingFunction->function(), referenceObject, context, ctx);
+ QV4::ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
+ QV4::ScopedContext ctx(scope, f->scope());
+ QQmlBinding *newBinding = QQmlBinding::create(&cacheData, f->function(), referenceObject, context, ctx);
+ newBinding->setSourceLocation(bindingFunction->currentLocation());
+ if (f->isBoundFunction())
+ newBinding->setBoundFunction(static_cast<QV4::BoundFunction *>(f.getPointer()));
newBinding->setSourceLocation(bindingFunction->currentLocation());
newBinding->setTarget(referenceObject, cacheData, pd);
QQmlPropertyPrivate::setBinding(newBinding);
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 5673acec89..567d83f3ee 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1019,7 +1019,7 @@ public:
Opened = 1, HeadersReceived = 2,
Loading = 3, Done = 4 };
- QQmlXMLHttpRequest(QNetworkAccessManager *manager);
+ QQmlXMLHttpRequest(QNetworkAccessManager *manager, QV4::ExecutionEngine *v4);
virtual ~QQmlXMLHttpRequest();
bool sendFlag() const;
@@ -1028,9 +1028,9 @@ public:
int replyStatus() const;
QString replyStatusText() const;
- ReturnedValue open(Object *thisObject, QQmlContextData *context, const QString &, const QUrl &, LoadType);
+ ReturnedValue open(Object *thisObject, const QString &, const QUrl &, LoadType);
ReturnedValue send(Object *thisObject, QQmlContextData *context, const QByteArray &);
- ReturnedValue abort(Object *thisObject, QQmlContextData *context);
+ ReturnedValue abort(Object *thisObject);
void addHeader(const QString &, const QString &);
QString header(const QString &name) const;
@@ -1078,9 +1078,10 @@ private:
PersistentValue m_thisObject;
QQmlContextDataRef m_qmlContext;
+ bool m_wasConstructedWithQmlContext = true;
- static void dispatchCallback(Object *thisObj, QQmlContextData *context);
- void dispatchCallback();
+ static void dispatchCallbackNow(Object *thisObj);
+ void dispatchCallbackSafely();
int m_status;
QString m_statusText;
@@ -1096,12 +1097,13 @@ private:
QV4::PersistentValue m_parsedDocument;
};
-QQmlXMLHttpRequest::QQmlXMLHttpRequest(QNetworkAccessManager *manager)
+QQmlXMLHttpRequest::QQmlXMLHttpRequest(QNetworkAccessManager *manager, QV4::ExecutionEngine *v4)
: m_state(Unsent), m_errorFlag(false), m_sendFlag(false)
, m_redirectCount(0), m_gotXml(false), m_textCodec(nullptr), m_network(nullptr), m_nam(manager)
, m_responseType()
, m_parsedDocument()
{
+ m_wasConstructedWithQmlContext = v4->callingQmlContext() != nullptr;
}
QQmlXMLHttpRequest::~QQmlXMLHttpRequest()
@@ -1134,7 +1136,7 @@ QString QQmlXMLHttpRequest::replyStatusText() const
return m_statusText;
}
-ReturnedValue QQmlXMLHttpRequest::open(Object *thisObject, QQmlContextData *context, const QString &method, const QUrl &url, LoadType loadType)
+ReturnedValue QQmlXMLHttpRequest::open(Object *thisObject, const QString &method, const QUrl &url, LoadType loadType)
{
destroyNetwork();
m_sendFlag = false;
@@ -1145,7 +1147,7 @@ ReturnedValue QQmlXMLHttpRequest::open(Object *thisObject, QQmlContextData *cont
m_request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, loadType == SynchronousLoad);
m_state = Opened;
m_addedHeaders.clear();
- dispatchCallback(thisObject, context);
+ dispatchCallbackNow(thisObject);
return Encode::undefined();
}
@@ -1297,7 +1299,7 @@ ReturnedValue QQmlXMLHttpRequest::send(Object *thisObject, QQmlContextData *cont
return Encode::undefined();
}
-ReturnedValue QQmlXMLHttpRequest::abort(Object *thisObject, QQmlContextData *context)
+ReturnedValue QQmlXMLHttpRequest::abort(Object *thisObject)
{
destroyNetwork();
m_responseEntityBody = QByteArray();
@@ -1310,7 +1312,7 @@ ReturnedValue QQmlXMLHttpRequest::abort(Object *thisObject, QQmlContextData *con
m_state = Done;
m_sendFlag = false;
- dispatchCallback(thisObject, context);
+ dispatchCallbackNow(thisObject);
}
m_state = Unsent;
@@ -1329,7 +1331,7 @@ void QQmlXMLHttpRequest::readyRead()
if (m_state < HeadersReceived) {
m_state = HeadersReceived;
fillHeadersList ();
- dispatchCallback();
+ dispatchCallbackSafely();
}
bool wasEmpty = m_responseEntityBody.isEmpty();
@@ -1337,7 +1339,7 @@ void QQmlXMLHttpRequest::readyRead()
if (wasEmpty && !m_responseEntityBody.isEmpty())
m_state = Loading;
- dispatchCallback();
+ dispatchCallbackSafely();
}
static const char *errorToString(QNetworkReply::NetworkError error)
@@ -1380,14 +1382,14 @@ void QQmlXMLHttpRequest::error(QNetworkReply::NetworkError error)
error == QNetworkReply::ServiceUnavailableError ||
error == QNetworkReply::UnknownServerError) {
m_state = Loading;
- dispatchCallback();
+ dispatchCallbackSafely();
} else {
m_errorFlag = true;
m_responseEntityBody = QByteArray();
}
m_state = Done;
- dispatchCallback();
+ dispatchCallbackSafely();
}
#define XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION 15
@@ -1419,7 +1421,7 @@ void QQmlXMLHttpRequest::finished()
if (m_state < HeadersReceived) {
m_state = HeadersReceived;
fillHeadersList ();
- dispatchCallback();
+ dispatchCallbackSafely();
}
m_responseEntityBody.append(m_network->readAll());
readEncoding();
@@ -1436,11 +1438,11 @@ void QQmlXMLHttpRequest::finished()
destroyNetwork();
if (m_state < Loading) {
m_state = Loading;
- dispatchCallback();
+ dispatchCallbackSafely();
}
m_state = Done;
- dispatchCallback();
+ dispatchCallbackSafely();
m_thisObject.clear();
m_qmlContext.setContextData(nullptr);
@@ -1557,17 +1559,10 @@ const QByteArray &QQmlXMLHttpRequest::rawResponseBody() const
return m_responseEntityBody;
}
-void QQmlXMLHttpRequest::dispatchCallback(Object *thisObj, QQmlContextData *context)
+void QQmlXMLHttpRequest::dispatchCallbackNow(Object *thisObj)
{
Q_ASSERT(thisObj);
- if (!context)
- // if the calling context object is no longer valid, then it has been
- // deleted explicitly (e.g., by a Loader deleting the itemContext when
- // the source is changed). We do nothing in this case, as the evaluation
- // cannot succeed.
- return;
-
QV4::Scope scope(thisObj->engine());
ScopedString s(scope, scope.engine->newString(QStringLiteral("onreadystatechange")));
ScopedFunctionObject callback(scope, thisObj->get(s));
@@ -1585,9 +1580,16 @@ void QQmlXMLHttpRequest::dispatchCallback(Object *thisObj, QQmlContextData *cont
}
}
-void QQmlXMLHttpRequest::dispatchCallback()
+void QQmlXMLHttpRequest::dispatchCallbackSafely()
{
- dispatchCallback(m_thisObject.as<Object>(), m_qmlContext.contextData());
+ if (m_wasConstructedWithQmlContext && !m_qmlContext.contextData())
+ // if the calling context object is no longer valid, then it has been
+ // deleted explicitly (e.g., by a Loader deleting the itemContext when
+ // the source is changed). We do nothing in this case, as the evaluation
+ // cannot succeed.
+ return;
+
+ dispatchCallbackNow(m_thisObject.as<Object>());
}
void QQmlXMLHttpRequest::destroyNetwork()
@@ -1640,7 +1642,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
Scope scope(f->engine());
const QQmlXMLHttpRequestCtor *ctor = static_cast<const QQmlXMLHttpRequestCtor *>(f);
- QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->v8Engine->networkAccessManager());
+ QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->v8Engine->networkAccessManager(), scope.engine);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocObject<QQmlXMLHttpRequestWrapper>(r));
ScopedObject proto(scope, ctor->d()->proto);
w->setPrototype(proto);
@@ -1778,7 +1780,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(const FunctionObject *b, const
if (!username.isNull()) url.setUserName(username);
if (!password.isNull()) url.setPassword(password);
- return r->open(w, scope.engine->callingQmlContext(), method, url, async ? QQmlXMLHttpRequest::AsynchronousLoad : QQmlXMLHttpRequest::SynchronousLoad);
+ return r->open(w, method, url, async ? QQmlXMLHttpRequest::AsynchronousLoad : QQmlXMLHttpRequest::SynchronousLoad);
}
ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
@@ -1860,7 +1862,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_abort(const FunctionObject *b, cons
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- return r->abort(w, scope.engine->callingQmlContext());
+ return r->abort(w);
}
ReturnedValue QQmlXMLHttpRequestCtor::method_getResponseHeader(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 1371f1f041..9e7c84011b 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -1344,11 +1344,12 @@ ReturnedValue QtObject::method_locale(const FunctionObject *b, const Value *, co
return QQmlLocale::locale(scope.engine, code);
}
-void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *originalFunction)
+void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *bindingFunction)
{
- Scope scope(originalFunction->engine());
- ScopedContext context(scope, originalFunction->scope());
- FunctionObject::init(context, originalFunction->function());
+ Scope scope(bindingFunction->engine());
+ ScopedContext context(scope, bindingFunction->scope());
+ FunctionObject::init(context, bindingFunction->function());
+ this->bindingFunction.set(internalClass->engine, bindingFunction->d());
}
QQmlSourceLocation QQmlBindingFunction::currentLocation() const
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
index 104dae5d79..ee3b5f7d6e 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
@@ -80,8 +80,11 @@ struct ConsoleObject : Object {
void init();
};
-struct QQmlBindingFunction : FunctionObject {
- void init(const QV4::FunctionObject *originalFunction);
+#define QQmlBindingFunctionMembers(class, Member) \
+ Member(class, Pointer, FunctionObject *, bindingFunction)
+DECLARE_HEAP_OBJECT(QQmlBindingFunction, FunctionObject) {
+ DECLARE_MARKOBJECTS(QQmlBindingFunction)
+ void init(const QV4::FunctionObject *bindingFunction);
};
}
@@ -179,6 +182,7 @@ struct QQmlBindingFunction : public QV4::FunctionObject
{
V4_OBJECT2(QQmlBindingFunction, FunctionObject)
+ Heap::FunctionObject *bindingFunction() const { return d()->bindingFunction; }
QQmlSourceLocation currentLocation() const; // from caller stack trace
};
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index a43562a7b8..2ae3df6ebb 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -288,9 +288,10 @@ void QQmlConnections::connectSignals()
new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
signal->setEnabled(d->enabled);
- QQmlBoundSignalExpression *expression = ctxtdata ?
- new QQmlBoundSignalExpression(target, signalIndex,
- ctxtdata, this, d->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : nullptr;
+ auto f = d->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
+ QQmlBoundSignalExpression *expression =
+ ctxtdata ? new QQmlBoundSignalExpression(target, signalIndex, ctxtdata, this, f)
+ : nullptr;
signal->takeExpression(expression);
d->boundsignals += signal;
} else {
diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h
index b894df8f82..b0786cd088 100644
--- a/src/qml/types/qqmldelegatemodel_p.h
+++ b/src/qml/types/qqmldelegatemodel_p.h
@@ -62,6 +62,8 @@
#include <private/qv8engine_p.h>
#include <private/qqmlglobal_p.h>
+QT_REQUIRE_CONFIG(qml_delegate_model);
+
QT_BEGIN_NAMESPACE
class QQmlChangeSet;
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index 68b987a5fa..18980cfd7c 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -60,6 +60,8 @@
// We mean it.
//
+QT_REQUIRE_CONFIG(qml_delegate_model);
+
QT_BEGIN_NAMESPACE
typedef QQmlListCompositor Compositor;
diff --git a/src/qml/types/qqmlinstantiator.cpp b/src/qml/types/qqmlinstantiator.cpp
index 213bef7879..030758fa3b 100644
--- a/src/qml/types/qqmlinstantiator.cpp
+++ b/src/qml/types/qqmlinstantiator.cpp
@@ -44,7 +44,9 @@
#include <QtQml/QQmlInfo>
#include <QtQml/QQmlError>
#include <QtQml/private/qqmlobjectmodel_p.h>
+#if QT_CONFIG(qml_delegate_model)
#include <QtQml/private/qqmldelegatemodel_p.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -53,7 +55,9 @@ QQmlInstantiatorPrivate::QQmlInstantiatorPrivate()
, effectiveReset(false)
, active(true)
, async(false)
+#if QT_CONFIG(qml_delegate_model)
, ownModel(false)
+#endif
, requestedIndex(-1)
, model(QVariant(1))
, instanceModel(nullptr)
@@ -198,6 +202,7 @@ void QQmlInstantiatorPrivate::_q_modelUpdated(const QQmlChangeSet &changeSet, bo
q->countChanged();
}
+#if QT_CONFIG(qml_delegate_model)
void QQmlInstantiatorPrivate::makeModel()
{
Q_Q(QQmlInstantiator);
@@ -209,6 +214,7 @@ void QQmlInstantiatorPrivate::makeModel()
if (componentComplete)
delegateModel->componentComplete();
}
+#endif
/*!
@@ -349,6 +355,7 @@ void QQmlInstantiator::setDelegate(QQmlComponent* c)
d->delegate = c;
emit delegateChanged();
+#if QT_CONFIG(qml_delegate_model)
if (!d->ownModel)
return;
@@ -356,6 +363,7 @@ void QQmlInstantiator::setDelegate(QQmlComponent* c)
dModel->setDelegate(c);
if (d->componentComplete)
d->regenerate();
+#endif
}
/*!
@@ -398,12 +406,15 @@ void QQmlInstantiator::setModel(const QVariant &v)
QObject *object = qvariant_cast<QObject*>(v);
QQmlInstanceModel *vim = nullptr;
if (object && (vim = qobject_cast<QQmlInstanceModel *>(object))) {
+#if QT_CONFIG(qml_delegate_model)
if (d->ownModel) {
delete d->instanceModel;
prevModel = nullptr;
d->ownModel = false;
}
+#endif
d->instanceModel = vim;
+#if QT_CONFIG(qml_delegate_model)
} else if (v != QVariant(0)){
if (!d->ownModel)
d->makeModel();
@@ -413,6 +424,7 @@ void QQmlInstantiator::setModel(const QVariant &v)
dataModel->setModel(v);
d->effectiveReset = false;
}
+#endif
}
if (d->instanceModel != prevModel) {
@@ -423,10 +435,12 @@ void QQmlInstantiator::setModel(const QVariant &v)
//disconnect(prevModel, SIGNAL(initItem(int,QObject*)), this, SLOT(initItem(int,QObject*)));
}
- connect(d->instanceModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)),
- this, SLOT(_q_modelUpdated(QQmlChangeSet,bool)));
- connect(d->instanceModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(_q_createdItem(int,QObject*)));
- //connect(d->instanceModel, SIGNAL(initItem(int,QObject*)), this, SLOT(initItem(int,QObject*)));
+ if (d->instanceModel) {
+ connect(d->instanceModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)),
+ this, SLOT(_q_modelUpdated(QQmlChangeSet,bool)));
+ connect(d->instanceModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(_q_createdItem(int,QObject*)));
+ //connect(d->instanceModel, SIGNAL(initItem(int,QObject*)), this, SLOT(initItem(int,QObject*)));
+ }
}
d->regenerate();
@@ -476,10 +490,13 @@ void QQmlInstantiator::componentComplete()
{
Q_D(QQmlInstantiator);
d->componentComplete = true;
+#if QT_CONFIG(qml_delegate_model)
if (d->ownModel) {
static_cast<QQmlDelegateModel*>(d->instanceModel)->componentComplete();
d->regenerate();
- } else {
+ } else
+#endif
+ {
QVariant realModel = d->model;
d->model = QVariant(0);
setModel(realModel); //If realModel == d->model this won't do anything, but that's fine since the model's 0
diff --git a/src/qml/types/qqmlinstantiator_p_p.h b/src/qml/types/qqmlinstantiator_p_p.h
index 9edaecf7a8..a5a4d1a32d 100644
--- a/src/qml/types/qqmlinstantiator_p_p.h
+++ b/src/qml/types/qqmlinstantiator_p_p.h
@@ -69,7 +69,9 @@ public:
void clear();
void regenerate();
+#if QT_CONFIG(qml_delegate_model)
void makeModel();
+#endif
void _q_createdItem(int, QObject *);
void _q_modelUpdated(const QQmlChangeSet &, bool);
QObject *modelObject(int index, bool async);
@@ -78,7 +80,9 @@ public:
bool effectiveReset:1;
bool active:1;
bool async:1;
+#if QT_CONFIG(qml_delegate_model)
bool ownModel:1;
+#endif
int requestedIndex;
QVariant model;
QQmlInstanceModel *instanceModel;
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index d4fc02cd3e..c4e33d572d 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -2351,21 +2351,22 @@ void QQmlListModel::append(QQmlV4Function *args)
QV4::ScopedObject argObject(scope);
int objectArrayLength = objectArray->getLength();
+ if (objectArrayLength > 0) {
+ int index = count();
+ emitItemsAboutToBeInserted(index, objectArrayLength);
- int index = count();
- emitItemsAboutToBeInserted(index, objectArrayLength);
+ for (int i=0 ; i < objectArrayLength ; ++i) {
+ argObject = objectArray->getIndexed(i);
- for (int i=0 ; i < objectArrayLength ; ++i) {
- argObject = objectArray->getIndexed(i);
-
- if (m_dynamicRoles) {
- m_modelObjects.append(DynamicRoleModelNode::create(scope.engine->variantMapFromJS(argObject), this));
- } else {
- m_listModel->append(argObject);
+ if (m_dynamicRoles) {
+ m_modelObjects.append(DynamicRoleModelNode::create(scope.engine->variantMapFromJS(argObject), this));
+ } else {
+ m_listModel->append(argObject);
+ }
}
- }
- emitItemsInserted();
+ emitItemsInserted();
+ }
} else if (argObject) {
int index;
diff --git a/src/qml/types/qqmlmodelsmodule.cpp b/src/qml/types/qqmlmodelsmodule.cpp
index c36e26a525..e217b63c6f 100644
--- a/src/qml/types/qqmlmodelsmodule.cpp
+++ b/src/qml/types/qqmlmodelsmodule.cpp
@@ -40,7 +40,9 @@
#include "qqmlmodelsmodule_p.h"
#include <QtCore/qitemselectionmodel.h>
#include <private/qqmllistmodel_p.h>
+#if QT_CONFIG(qml_delegate_model)
#include <private/qqmldelegatemodel_p.h>
+#endif
#include <private/qqmlobjectmodel_p.h>
QT_BEGIN_NAMESPACE
@@ -51,8 +53,10 @@ void QQmlModelsModule::defineModule()
qmlRegisterType<QQmlListElement>(uri, 2, 1, "ListElement");
qmlRegisterCustomType<QQmlListModel>(uri, 2, 1, "ListModel", new QQmlListModelParser);
+#if QT_CONFIG(qml_delegate_model)
qmlRegisterType<QQmlDelegateModel>(uri, 2, 1, "DelegateModel");
qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 1, "DelegateModelGroup");
+#endif
qmlRegisterType<QQmlObjectModel>(uri, 2, 1, "ObjectModel");
qmlRegisterType<QQmlObjectModel,3>(uri, 2, 3, "ObjectModel");
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index 80c2d3a4bc..ef92e4108d 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -397,9 +397,11 @@ void QQuickWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
QV4::Scoped<QV4::QmlContext> qmlContext(scope, getWorker(script));
Q_ASSERT(!!qmlContext);
- program.reset(QV4::Script::createFromFileOrCache(v4, qmlContext, fileName, url));
+ QString error;
+ program.reset(QV4::Script::createFromFileOrCache(v4, qmlContext, fileName, url, &error));
if (program.isNull()) {
- qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString();
+ if (!error.isEmpty())
+ qWarning().nospace() << error;
return;
}
diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri
index e85ab5982b..8bcbd6e544 100644
--- a/src/qml/types/types.pri
+++ b/src/qml/types/types.pri
@@ -1,7 +1,6 @@
SOURCES += \
$$PWD/qqmlbind.cpp \
$$PWD/qqmlconnections.cpp \
- $$PWD/qqmldelegatemodel.cpp \
$$PWD/qqmllistmodel.cpp \
$$PWD/qqmllistmodelworkeragent.cpp \
$$PWD/qqmlmodelsmodule.cpp \
@@ -14,8 +13,6 @@ SOURCES += \
HEADERS += \
$$PWD/qqmlbind_p.h \
$$PWD/qqmlconnections_p.h \
- $$PWD/qqmldelegatemodel_p.h \
- $$PWD/qqmldelegatemodel_p_p.h \
$$PWD/qqmllistmodel_p.h \
$$PWD/qqmllistmodel_p_p.h \
$$PWD/qqmllistmodelworkeragent_p.h \
@@ -27,6 +24,15 @@ HEADERS += \
$$PWD/qqmlinstantiator_p.h \
$$PWD/qqmlinstantiator_p_p.h
+qtConfig(qml-delegate-model) {
+ SOURCES += \
+ $$PWD/qqmldelegatemodel.cpp
+
+ HEADERS += \
+ $$PWD/qqmldelegatemodel_p.h \
+ $$PWD/qqmldelegatemodel_p_p.h
+}
+
qtConfig(animation) {
SOURCES += \
$$PWD/qqmltimer.cpp
diff --git a/src/qml/util/qqmladaptormodel_p.h b/src/qml/util/qqmladaptormodel_p.h
index 8f773efa20..b152a886a5 100644
--- a/src/qml/util/qqmladaptormodel_p.h
+++ b/src/qml/util/qqmladaptormodel_p.h
@@ -57,6 +57,8 @@
#include <private/qqmlguard_p.h>
+QT_REQUIRE_CONFIG(qml_delegate_model);
+
QT_BEGIN_NAMESPACE
class QQmlEngine;
diff --git a/src/qml/util/util.pri b/src/qml/util/util.pri
index a9c5ffe9b7..bebb271f1b 100644
--- a/src/qml/util/util.pri
+++ b/src/qml/util/util.pri
@@ -2,12 +2,18 @@ SOURCES += \
$$PWD/qqmlchangeset.cpp \
$$PWD/qqmllistaccessor.cpp \
$$PWD/qqmllistcompositor.cpp \
- $$PWD/qqmladaptormodel.cpp \
$$PWD/qqmlpropertymap.cpp
HEADERS += \
$$PWD/qqmlchangeset_p.h \
$$PWD/qqmllistaccessor_p.h \
$$PWD/qqmllistcompositor_p.h \
- $$PWD/qqmladaptormodel_p.h \
$$PWD/qqmlpropertymap.h
+
+qtConfig(qml-delegate-model) {
+ SOURCES += \
+ $$PWD/qqmladaptormodel.cpp
+
+ HEADERS += \
+ $$PWD/qqmladaptormodel_p.h
+}