aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/Qt6QmlMacros.cmake6
-rw-r--r--src/qml/compiler/qv4codegen.cpp1
-rw-r--r--src/qml/doc/src/cppintegration/data.qdoc2
-rw-r--r--src/qml/doc/src/cppintegration/exposecppattributes.qdoc6
-rw-r--r--src/qml/doc/src/javascript/hostenvironment.qdoc4
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc8
-rw-r--r--src/qml/jit/qv4assemblercommon_p.h2
-rw-r--r--src/qml/jsapi/qjsengine.cpp6
-rw-r--r--src/qml/jsapi/qjsengine.h22
-rw-r--r--src/qml/jsapi/qjsmanagedvalue.cpp13
-rw-r--r--src/qml/jsapi/qjsprimitivevalue.h6
-rw-r--r--src/qml/jsapi/qjsvalue.cpp30
-rw-r--r--src/qml/jsapi/qjsvalue_p.h2
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp1
-rw-r--r--src/qml/jsruntime/qv4engine.cpp12
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit.cpp12
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp18
-rw-r--r--src/qml/jsruntime/qv4object.cpp4
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp4
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp3
-rw-r--r--src/qml/jsruntime/qv4urlobject.cpp31
-rw-r--r--src/qml/jsruntime/qv4value_p.h3
-rw-r--r--src/qml/qml/qqml.cpp12
-rw-r--r--src/qml/qml/qqmlabstractbinding.cpp15
-rw-r--r--src/qml/qml/qqmlbinding.cpp10
-rw-r--r--src/qml/qml/qqmlcomponent.cpp12
-rw-r--r--src/qml/qml/qqmlcontextdata.cpp6
-rw-r--r--src/qml/qml/qqmlcontextdata_p.h9
-rw-r--r--src/qml/qml/qqmldelayedcallqueue.cpp3
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp2
-rw-r--r--src/qml/qml/qqmlglobal.cpp9
-rw-r--r--src/qml/qml/qqmlimport_p.h10
-rw-r--r--src/qml/qml/qqmlincubator.cpp2
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp4
-rw-r--r--src/qml/qml/qqmlproperty.cpp21
-rw-r--r--src/qml/qml/qqmlpropertybinding.cpp3
-rw-r--r--src/qml/qml/qqmlpropertycachecreator.cpp4
-rw-r--r--src/qml/qml/qqmlscriptblob.cpp2
-rw-r--r--src/qml/qml/qqmlscriptdata.cpp2
-rw-r--r--src/qml/qml/qqmlscriptdata_p.h2
-rw-r--r--src/qml/qml/qqmltypedata.cpp297
-rw-r--r--src/qml/qml/qqmltypedata_p.h24
-rw-r--r--src/qml/qml/qqmltypeloader.cpp117
-rw-r--r--src/qml/qml/qqmltypeloader_p.h3
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp12
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp6
-rw-r--r--src/qml/qmltc/supportlibrary/qqmlcpptypehelpers_p.h6
-rw-r--r--src/qml/types/qqmlbind.cpp67
48 files changed, 553 insertions, 303 deletions
diff --git a/src/qml/Qt6QmlMacros.cmake b/src/qml/Qt6QmlMacros.cmake
index 91229d8d1f..ac9165711b 100644
--- a/src/qml/Qt6QmlMacros.cmake
+++ b/src/qml/Qt6QmlMacros.cmake
@@ -3262,7 +3262,7 @@ function(qt6_generate_deploy_qml_app_script)
qt_deploy_qml_imports(TARGET ${arg_TARGET} PLUGINS_FOUND plugins_found)
if(NOT DEFINED __QT_DEPLOY_POST_BUILD)
qt_deploy_runtime_dependencies(
- EXECUTABLE $<TARGET_FILE_NAME:${arg_TARGET}>.app
+ EXECUTABLE \"$<TARGET_FILE_NAME:${arg_TARGET}>.app\"
ADDITIONAL_MODULES \${plugins_found}
${common_deploy_args})
endif()")
@@ -3290,7 +3290,7 @@ endif()")
CONTENT "
qt_deploy_qml_imports(TARGET ${arg_TARGET} PLUGINS_FOUND plugins_found)
qt_deploy_runtime_dependencies(
- EXECUTABLE $<TARGET_FILE:${arg_TARGET}>
+ EXECUTABLE \"$<TARGET_FILE:${arg_TARGET}>\"
ADDITIONAL_MODULES \${plugins_found}
GENERATE_QT_CONF
${common_deploy_args})")
@@ -3303,7 +3303,7 @@ ${common_deploy_args})")
CONTENT "
qt_deploy_qml_imports(TARGET ${arg_TARGET} PLUGINS_FOUND plugins_found)
qt_deploy_runtime_dependencies(
- EXECUTABLE $<TARGET_FILE:${arg_TARGET}>
+ EXECUTABLE \"$<TARGET_FILE:${arg_TARGET}>\"
ADDITIONAL_MODULES \${plugins_found}
GENERATE_QT_CONF
${common_deploy_args})")
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 5df9b3fa4c..b9f784a761 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1422,6 +1422,7 @@ bool Codegen::visit(BinaryExpression *ast)
return false;
} else if (ast->op == QSOperator::Assign) {
+ bytecodeGenerator->setLocation(ast->left->firstSourceLocation());
if (AST::Pattern *p = ast->left->patternCast()) {
RegisterScope scope(this);
Reference right = expression(ast->right);
diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc
index cba6a122b9..e89cca452f 100644
--- a/src/qml/doc/src/cppintegration/data.qdoc
+++ b/src/qml/doc/src/cppintegration/data.qdoc
@@ -497,7 +497,7 @@ Q_ENUM(Status)
\endcode
Enum classes are registered in QML as scoped and unscoped properties.
-The \c Ready value will be registered at \c Message.Status.Ready and \c Message.Ready .
+The \c Ready value will be registered as \c Message.Status.Ready and \c Message.Ready .
When using enum classes, there can be multiple enums using the same identifiers.
The unscoped registration will be overwriten by the last registered enum. For classes
diff --git a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
index 6031d0eebb..83b7155636 100644
--- a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
+++ b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
@@ -521,6 +521,12 @@ pragma NativeMethodBehavior: AcceptThisObject
With this line added, the example above will work as expected.
+\section2 Overriding toString()
+
+If you provide a Q_INVOKABLE method called \e{toString} (with no arguments), that
+method will be used to convert the object to a string in place of JavaScript's
+native \e{toString} implementation.
+
\section1 Exposing Signals
Any public \l{Signals & Slots}{signal} of a QObject-derived type is accessible
diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc
index c267371bbd..26705f9e19 100644
--- a/src/qml/doc/src/javascript/hostenvironment.qdoc
+++ b/src/qml/doc/src/javascript/hostenvironment.qdoc
@@ -47,6 +47,10 @@ to use from C++. See
\l {qtqml-cppintegration-interactqmlfromcpp.html}{Interacting with QML Objects from C++}
for more information.
+The exception to this rule are functions assigned to signal handlers: There, type annotations are
+forbidden to avoid a potential mismatch with the types of the signal. This does not cause issues for
+tooling, as the signal already provides the necessary information.
+
By default, type annotations are ignored by the interpreter and the JIT
compiler, but enforced by \l{qmlcachegen} and \l{qmlsc} when compiling to C++.
This can lead to differences in behavior if you either pass values that
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index ca63c9c03a..e61dfe0ae7 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -1181,11 +1181,11 @@
This returns the attached object instance that has been attached to the specified
\a attachee by the attaching type \e T.
- If \a create is true and type \e T is a valid attaching type, this creates and returns a new
- attached object instance.
+ If \a attachee is \nullptr, returns \nullptr.
- Returns 0 if type \e T is not a valid attaching type, or if \a create is false and no
- attachment object instance has previously been created for \a attachee.
+ If an existing attached object instance of type \e T exists, it will return
+ it. Otherwise, it will return a newly created instance if \a create is
+ \c true and \e T is a valid attaching type, or \nullptr if it's not.
\sa QML_ATTACHED(), {Providing Attached Properties}
*/
diff --git a/src/qml/jit/qv4assemblercommon_p.h b/src/qml/jit/qv4assemblercommon_p.h
index cccd90fab8..d02f57b42b 100644
--- a/src/qml/jit/qv4assemblercommon_p.h
+++ b/src/qml/jit/qv4assemblercommon_p.h
@@ -583,12 +583,12 @@ public:
for (Jump j : catchyJumps)
j.link(this);
+ loadUndefined();
// We don't need to check for isInterrupted here because if that is set,
// then the first checkException() in any exception handler will find another "exception"
// and jump out of the exception handler.
loadPtr(exceptionHandlerAddress(), ScratchRegister);
Jump exitFunction = branchPtr(Equal, ScratchRegister, TrustedImmPtr(0));
- loadUndefined();
jump(ScratchRegister);
exitFunction.link(this);
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index 374d170019..45990f6996 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -928,7 +928,8 @@ bool QJSEngine::convertV2(const QJSValue &value, QMetaType metaType, void *ptr)
return convertString(*string, metaType, ptr);
// Does not need scoping since QJSValue still holds on to the value.
- return QV4::ExecutionEngine::metaTypeFromJS(QJSValuePrivate::asReturnedValue(&value), metaType, ptr);
+ return QV4::ExecutionEngine::metaTypeFromJS(QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(&value)),
+ metaType, ptr);
}
bool QJSEngine::convertVariant(const QVariant &value, QMetaType metaType, void *ptr)
@@ -1155,7 +1156,8 @@ void QJSEngine::throwError(QJSValue::ErrorType errorType, const QString &message
*/
void QJSEngine::throwError(const QJSValue &error)
{
- m_v4Engine->throwError(QJSValuePrivate::asReturnedValue(&error));
+ // safe, QJSValue holds a persistent reference
+ m_v4Engine->throwError(QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(&error)));
}
/*!
diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h
index dbeecb45ae..a16ac60603 100644
--- a/src/qml/jsapi/qjsengine.h
+++ b/src/qml/jsapi/qjsengine.h
@@ -145,6 +145,18 @@ public:
}
}
+ if constexpr (std::is_same_v<T, double>) {
+ if (sourceType == QMetaType::fromType<int>())
+ return double(*static_cast<const int *>(value.constData()));
+ }
+
+ if constexpr (std::is_same_v<T, int>) {
+ if (sourceType == QMetaType::fromType<double>()) {
+ return QJSNumberCoercion::toInteger(
+ *static_cast<const double *>(value.constData()));
+ }
+ }
+
if constexpr (std::is_same_v<QObject, std::remove_const_t<std::remove_pointer_t<T>>>) {
if (sourceType.flags() & QMetaType::PointerToQObject) {
return *static_cast<QObject *const *>(value.constData());
@@ -254,6 +266,16 @@ public:
return from;
}
+ if constexpr (std::is_same_v<To, double>) {
+ if constexpr (std::is_same_v<From, int>)
+ return double(from);
+ }
+
+ if constexpr (std::is_same_v<To, int>) {
+ if constexpr (std::is_same_v<From, double>)
+ return QJSNumberCoercion::toInteger(from);
+ }
+
{
const QMetaType sourceType = QMetaType::fromType<From>();
const QMetaType targetType = QMetaType::fromType<To>();
diff --git a/src/qml/jsapi/qjsmanagedvalue.cpp b/src/qml/jsapi/qjsmanagedvalue.cpp
index a4f2f97432..b429784a96 100644
--- a/src/qml/jsapi/qjsmanagedvalue.cpp
+++ b/src/qml/jsapi/qjsmanagedvalue.cpp
@@ -787,7 +787,8 @@ void QJSManagedValue::setProperty(const QString &name, const QJSValue &value)
return;
}
QV4::ScopedPropertyKey key(scope, scope.engine->identifierTable->asPropertyKey(name));
- obj->put(key, QJSValuePrivate::convertToReturnedValue(scope.engine, value));
+ QV4::ScopedValue val(scope, QJSValuePrivate::convertToReturnedValue(scope.engine, value));
+ obj->put(key, val);
}
}
@@ -905,7 +906,10 @@ void QJSManagedValue::setProperty(quint32 arrayIndex, const QJSValue &value)
"Value was created in different engine.");
return;
}
- obj->put(arrayIndex, QJSValuePrivate::convertToReturnedValue(v4, value));
+ v4 = obj->engine(); // in case value was primitive
+ QV4::Scope scope(v4);
+ QV4::ScopedValue v(scope, QJSValuePrivate::convertToReturnedValue(v4, value));
+ obj->put(arrayIndex, v);
}
}
@@ -1120,6 +1124,8 @@ QJSManagedValue QJSManagedValue::jsMetaInstantiate(const QJSValueList &values) c
*result.d = c->engine()->newObject(c->d());
QV4::Object *o = result.d->as<QV4::Object>();
+ QV4::Scope scope(engine);
+ QV4::ScopedValue val(scope);
for (uint i = 0, end = qMin(qsizetype(c->d()->size), values.size()); i < end; ++i) {
const QJSValue &arg = values[i];
if (Q_UNLIKELY(!QJSValuePrivate::checkEngine(engine, arg))) {
@@ -1127,7 +1133,8 @@ QJSManagedValue QJSManagedValue::jsMetaInstantiate(const QJSValueList &values) c
"Argument was created in different engine.");
return QJSManagedValue();
}
- o->setProperty(i, QJSValuePrivate::convertToReturnedValue(engine, arg));
+ val = QJSValuePrivate::convertToReturnedValue(engine, arg);
+ o->setProperty(i, val);
}
return result;
diff --git a/src/qml/jsapi/qjsprimitivevalue.h b/src/qml/jsapi/qjsprimitivevalue.h
index 49a00ed180..ea65aa5610 100644
--- a/src/qml/jsapi/qjsprimitivevalue.h
+++ b/src/qml/jsapi/qjsprimitivevalue.h
@@ -777,10 +777,14 @@ private:
}
union {
- bool m_bool = false;
+ bool m_bool;
int m_int;
double m_double;
QString m_string;
+
+ // Dummy value to trigger initialization of the whole storage.
+ // We don't want to see maybe-uninitialized warnings every time we access m_string.
+ std::byte m_zeroInitialize[sizeof(QString)] = {};
};
Type m_type = Undefined;
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 8717462729..943808b322 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -902,7 +902,10 @@ QJSValue& QJSValue::operator=(const QJSValue& other)
if (const QString *string = QJSValuePrivate::asQString(&other))
QJSValuePrivate::setString(this, *string);
else
- QJSValuePrivate::setValue(this, QJSValuePrivate::asReturnedValue(&other));
+ // fomReturnedValue is safe, as the QJSValue still has a persistent reference
+ QJSValuePrivate::setValue(
+ this,
+ QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(&other)));
return *this;
}
@@ -990,17 +993,25 @@ static bool js_equal(const QString &string, const QV4::Value &value)
*/
bool QJSValue::equals(const QJSValue& other) const
{
+ // QJSValue stores heap items in persistent values, which already ensures marking
+ // therefore, fromReturnedValue below is safe
if (const QString *string = QJSValuePrivate::asQString(this)) {
if (const QString *otherString = QJSValuePrivate::asQString(&other))
return *string == *otherString;
- return js_equal(*string, QJSValuePrivate::asReturnedValue(&other));
+ return js_equal(
+ *string,
+ QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(&other)));
}
- if (const QString *otherString = QJSValuePrivate::asQString(&other))
- return js_equal(*otherString, QJSValuePrivate::asReturnedValue(this));
+ if (const QString *otherString = QJSValuePrivate::asQString(&other)) {
+ return js_equal(
+ *otherString,
+ QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(this)));
+ }
- return Runtime::CompareEqual::call(QJSValuePrivate::asReturnedValue(this),
- QJSValuePrivate::asReturnedValue(&other));
+ return Runtime::CompareEqual::call(
+ QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(this)),
+ QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(&other)));
}
/*!
@@ -1041,8 +1052,11 @@ bool QJSValue::strictlyEquals(const QJSValue& other) const
return false;
}
- return RuntimeHelpers::strictEqual(QJSValuePrivate::asReturnedValue(this),
- QJSValuePrivate::asReturnedValue(&other));
+ // QJSValue stores heap objects persistently, so we can be sure that they'll be marked
+ // thus we can safely use fromReturnedValue
+ return RuntimeHelpers::strictEqual(
+ QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(this)),
+ QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(&other)));
}
/*!
diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h
index b95e76e76e..6bc731aace 100644
--- a/src/qml/jsapi/qjsvalue_p.h
+++ b/src/qml/jsapi/qjsvalue_p.h
@@ -189,7 +189,7 @@ public:
static QJSValue fromReturnedValue(QV4::ReturnedValue d)
{
QJSValue result;
- setValue(&result, d);
+ setValue(&result, QV4::Value::fromReturnedValue(d));
return result;
}
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 05e73d0295..e4170b459e 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -576,6 +576,7 @@ ReturnedValue ArrayPrototype::method_join(const FunctionObject *functionObject,
const Value *thisObject, const Value *argv, int argc)
{
Scope scope(functionObject);
+ CHECK_STACK_LIMITS(scope.engine)
ScopedObject instance(scope, thisObject->toObject(scope.engine));
if (!instance)
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index a807cc42df..3bb140a4fd 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -2453,9 +2453,12 @@ bool convertToIterable(QMetaType metaType, void *data, Source *sequence)
return false;
const QMetaType elementMetaType = iterable.valueMetaType();
+ QV4::Scope scope(sequence->engine());
+ QV4::ScopedValue v(scope);
for (qsizetype i = 0, end = sequence->getLength(); i < end; ++i) {
QVariant element(elementMetaType);
- ExecutionEngine::metaTypeFromJS(sequence->get(i), elementMetaType, element.data());
+ v = sequence->get(i);
+ ExecutionEngine::metaTypeFromJS(v, elementMetaType, element.data());
iterable.addValue(element, QSequentialIterable::AtEnd);
}
return true;
@@ -2515,9 +2518,12 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
QByteArray result;
const qint64 length = ao->getLength();
result.reserve(length);
+ QV4::Scope scope(ao->engine());
+ QV4::ScopedValue v(scope);
for (qint64 i = 0; i < length; ++i) {
char value = 0;
- ExecutionEngine::metaTypeFromJS(ao->get(i), QMetaType::fromType<char>(), &value);
+ v = ao->get(i);
+ ExecutionEngine::metaTypeFromJS(v, QMetaType::fromType<char>(), &value);
result.push_back(value);
}
*reinterpret_cast<QByteArray*>(data) = std::move(result);
@@ -2778,7 +2784,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
*reinterpret_cast<void* *>(data) = nullptr;
return true;
} else if (metaType == QMetaType::fromType<QJSValue>()) {
- QJSValuePrivate::setValue(reinterpret_cast<QJSValue*>(data), value.asReturnedValue());
+ QJSValuePrivate::setValue(reinterpret_cast<QJSValue*>(data), value);
return true;
} else if (metaType == QMetaType::fromType<QJSPrimitiveValue>()) {
*reinterpret_cast<QJSPrimitiveValue *>(data) = createPrimitive(&value);
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp
index dc24f2d2a9..aed1a84f63 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit.cpp
+++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp
@@ -695,8 +695,10 @@ const Value *ExecutableCompilationUnit::resolveExportRecursively(
return fragment.native;
ScopedObject o(scope, dependentModule.native);
- if (o)
- return engine->registerNativeModule(request, o->get(importName));
+ if (o) {
+ ScopedValue nativeModule(scope, o->get(importName));
+ return engine->registerNativeModule(request, nativeModule);
+ }
return nullptr;
} else {
@@ -727,8 +729,10 @@ const Value *ExecutableCompilationUnit::resolveExportRecursively(
resolution = fragment.native;
} else {
ScopedObject o(scope, dependentModule.native);
- if (o)
- resolution = engine->registerNativeModule(request, o->get(exportName));
+ if (o) {
+ ScopedValue nativeModule(scope, o->get(exportName));
+ resolution = engine->registerNativeModule(request, nativeModule);
+ }
}
}
}
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 32e93cedb4..ec74fbceed 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -301,15 +301,15 @@ ReturnedValue EvalFunction::evalCall(const Value *, const Value *argv, int argc,
return Encode::undefined();
ExecutionEngine *v4 = engine();
- bool isStrict = v4->currentStackFrame->v4Function->isStrict();
+ const Function *v4Function = v4->currentStackFrame
+ ? v4->currentStackFrame->v4Function
+ : v4->globalCode;
+ const bool isStrict = v4Function && v4Function->isStrict();
Scope scope(v4);
- ScopedContext ctx(scope, v4->currentContext());
- if (!directCall) {
- // the context for eval should be the global scope
- ctx = v4->scriptContext();
- }
+ // In case of !directCall, the context for eval should be the global scope
+ ScopedContext ctx(scope, directCall ? v4->currentContext() : v4->scriptContext());
String *scode = argv[0].stringValue();
if (!scode)
@@ -330,14 +330,14 @@ ReturnedValue EvalFunction::evalCall(const Value *, const Value *argv, int argc,
return Encode::undefined();
function->kind = Function::Eval;
+ ScopedValue thisObject(scope, directCall
+ ? scope.engine->currentStackFrame->thisObject()
+ : scope.engine->globalObject->asReturnedValue());
if (function->isStrict() || isStrict) {
ScopedFunctionObject e(scope, FunctionObject::createScriptFunction(ctx, function));
- ScopedValue thisObject(scope, directCall ? scope.engine->currentStackFrame->thisObject() : scope.engine->globalObject->asReturnedValue());
return checkedResult(v4, e->call(thisObject, nullptr, 0));
}
- ScopedValue thisObject(scope, scope.engine->currentStackFrame->thisObject());
-
return checkedResult(v4, function->call(thisObject, nullptr, 0, ctx));
}
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 0851b2f5ab..2071e39520 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -42,7 +42,9 @@ void Object::setInternalClass(Heap::InternalClass *ic)
for (uint i = 0; i < ic->size; ++i) {
// Note that some members might have been deleted. The key may be invalid.
const PropertyKey key = ic->nameMap.at(i);
- newMembers->set(scope.engine, i, key.isValid() ? get(key) : Encode::undefined());
+ // fromReturnedValue is safe, we directly write it through the WriteBarrier
+ newMembers->set(scope.engine, i,
+ QV4::Value::fromReturnedValue(key.isValid() ? get(key) : Encode::undefined()));
}
p->internalClass.set(scope.engine, ic);
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index e19c57fd40..6d08764a11 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -2219,7 +2219,9 @@ bool CallArgument::fromValue(QMetaType metaType, ExecutionEngine *engine, const
default:
if (type == qMetaTypeId<QJSValue>()) {
qjsValuePtr = new (&allocData) QJSValue;
- QJSValuePrivate::setValue(qjsValuePtr, value.asReturnedValue());
+ Scope scope(engine);
+ ScopedValue v(scope, value);
+ QJSValuePrivate::setValue(qjsValuePtr, v);
return true;
}
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 1dd2654382..2cafd9a741 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -709,7 +709,8 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHin
QV4::ScopedValue v(scope);
for (quint32 i = 0; i < quint32(length); ++i) {
const QMetaType valueMetaType = priv->typeId;
- QVariant variant = ExecutionEngine::toVariant(a->get(i), valueMetaType, false);
+ QV4::ScopedValue element(scope, a->get(i));
+ QVariant variant = ExecutionEngine::toVariant(element, valueMetaType, false);
if (valueMetaType == QMetaType::fromType<QVariant>()) {
meta->addValueAtEnd(result.data(), &variant);
} else {
diff --git a/src/qml/jsruntime/qv4urlobject.cpp b/src/qml/jsruntime/qv4urlobject.cpp
index 637d033bd4..aa0d47c766 100644
--- a/src/qml/jsruntime/qv4urlobject.cpp
+++ b/src/qml/jsruntime/qv4urlobject.cpp
@@ -806,7 +806,8 @@ ReturnedValue UrlSearchParamsCtor::virtualCallAsConstructor(const FunctionObject
uint len = argArray->getLength();
for (uint i = 0; i < len; i++) {
- QV4::Value pair = argArray->get(i);
+ // safe to user fromReturnedValue: Normal array, which will ensure marking
+ QV4::Value pair = Value::fromReturnedValue(argArray->get(i));
auto *pairArrayObject = pair.as<ArrayObject>();
if (pairArrayObject == nullptr) {
@@ -895,11 +896,14 @@ void UrlSearchParamsObject::initializeParams(ScopedArrayObject& params)
for (uint i = 0; i < len; i++)
{
- QV4::Value pair = params->get(i);
+ // fromReturnedValue is safe; everything is reachable via params
+ // so the gc won't collect it; we control params, so there can't be
+ // any weird proxy magic
+ QV4::Value pair = Value::fromReturnedValue(params->get(i));
auto *pairArrayObject = pair.as<ArrayObject>();
- QV4::Value key = pairArrayObject->get(uint(0));
- QV4::Value value = pairArrayObject->get(uint(1));
+ QV4::Value key = Value::fromReturnedValue(pairArrayObject->get(uint(0)));
+ QV4::Value value = Value::fromReturnedValue(pairArrayObject->get(uint(1)));
scopedKeys->put(i, key);
scopedValues->put(i, value);
@@ -1014,11 +1018,11 @@ QList<QStringList> UrlSearchParamsObject::params() const
uint len = scopedArray->getLength();
for (uint i = 0; i < len; i++) {
- QV4::Value pair = scopedArray->get(i);
+ QV4::Value pair = Value::fromReturnedValue(scopedArray->get(i));
auto *pairArrayObject = pair.as<ArrayObject>();
- QV4::Value key = pairArrayObject->get(uint(0));
- QV4::Value value = pairArrayObject->get(uint(1));
+ QV4::Value key = Value::fromReturnedValue(pairArrayObject->get(uint(0)));
+ QV4::Value value = Value::fromReturnedValue(pairArrayObject->get(uint(1)));
result << QStringList { key.toQString(), value.toQString() };
}
@@ -1063,10 +1067,11 @@ int UrlSearchParamsObject::indexOf(QString name, int last) const
int len = scopedArray->getLength();
for (int i = last + 1; i < len; i++) {
- QV4::Value pair = scopedArray->get(i);
+ // fromReturnedValue is safe, scopedArray is a normal array and takes care of marking
+ QV4::Value pair = Value::fromReturnedValue(scopedArray->get(i));
auto *pairArrayObject = pair.as<ArrayObject>();
- QV4::Value key = pairArrayObject->get(uint(0));
+ QV4::Value key = Value::fromReturnedValue(pairArrayObject->get(uint(0)));
if (key.toQString() == name)
return i;
@@ -1084,10 +1089,10 @@ QString UrlSearchParamsObject::stringAt(int index, int pairIndex) const
if (index >= scopedArray->getLength())
return {};
- QV4::Value pair = scopedArray->get(index);
+ QV4::Value pair = Value::fromReturnedValue(scopedArray->get(index));
auto *pairArrayObject = pair.as<ArrayObject>();
- QV4::Value value = pairArrayObject->get(pairIndex);
+ QV4::Value value = Value::fromReturnedValue(pairArrayObject->get(pairIndex));
return value.toQString();
}
@@ -1101,10 +1106,10 @@ QV4::Heap::String * UrlSearchParamsObject::stringAtRaw(int index, int pairIndex)
if (index >= scopedArray->getLength())
return nullptr;
- QV4::Value pair = scopedArray->get(index);
+ QV4::Value pair = Value::fromReturnedValue(scopedArray->get(index));
auto *pairArrayObject = pair.as<ArrayObject>();
- QV4::Value value = pairArrayObject->get(pairIndex);
+ QV4::Value value = Value::fromReturnedValue(pairArrayObject->get(pairIndex));
return value.as<String>()->d();
}
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 643d6c16a9..36fe261dea 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -38,9 +38,6 @@ struct Q_QML_PRIVATE_EXPORT Value : public StaticValue
{
using ManagedPtr = Managed *;
- Value() = default;
- constexpr Value(quint64 val) : StaticValue(val) {}
-
static constexpr Value fromStaticValue(StaticValue staticValue)
{
return {staticValue._val};
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index 44e8955b7a..f6bb6d4082 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -1267,7 +1267,9 @@ void AOTCompiledContext::storeNameSloppy(uint nameIndex, void *value, QMetaType
} else {
QVariant var(propType);
QV4::ExecutionEngine *v4 = engine->handle();
- v4->metaTypeFromJS(v4->metaTypeToJS(type, value), propType, var.data());
+ QV4::Scope scope(v4);
+ QV4::ScopedValue val(scope, v4->metaTypeToJS(type, value));
+ v4->metaTypeFromJS(val, propType, var.data());
storeResult = storeObjectProperty(&l, qmlScopeObject, var.data());
}
@@ -1286,7 +1288,9 @@ void AOTCompiledContext::storeNameSloppy(uint nameIndex, void *value, QMetaType
} else {
QVariant var(propType);
QV4::ExecutionEngine *v4 = engine->handle();
- v4->metaTypeFromJS(v4->metaTypeToJS(type, value), propType, var.data());
+ QV4::Scope scope(v4);
+ QV4::ScopedValue val(scope, v4->metaTypeToJS(type, value));
+ v4->metaTypeFromJS(val, propType, var.data());
storeResult = storeFallbackProperty(&l, qmlScopeObject, var.data());
}
break;
@@ -1504,7 +1508,9 @@ void AOTCompiledContext::initCallGlobalLookup(uint index) const
bool AOTCompiledContext::loadGlobalLookup(uint index, void *target, QMetaType type) const
{
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- if (!QV4::ExecutionEngine::metaTypeFromJS(l->globalGetter(l, engine->handle()), type, target)) {
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedValue val(scope, l->globalGetter(l, engine->handle()));
+ if (!QV4::ExecutionEngine::metaTypeFromJS(val, type, target)) {
engine->handle()->throwTypeError();
return false;
}
diff --git a/src/qml/qml/qqmlabstractbinding.cpp b/src/qml/qml/qqmlabstractbinding.cpp
index 78d1d68f55..d1c0a855d1 100644
--- a/src/qml/qml/qqmlabstractbinding.cpp
+++ b/src/qml/qml/qqmlabstractbinding.cpp
@@ -49,16 +49,15 @@ void QQmlAbstractBinding::addToObject()
// Find the value type proxy (if there is one)
QQmlValueTypeProxyBinding *proxy = nullptr;
- if (data->hasBindingBit(coreIndex)) {
- QQmlAbstractBinding *b = data->bindings;
- while (b && (b->targetPropertyIndex().coreIndex() != coreIndex ||
- b->targetPropertyIndex().hasValueTypeIndex()))
- b = b->nextBinding();
- Q_ASSERT(b && b->kind() == QQmlAbstractBinding::ValueTypeProxy);
- proxy = static_cast<QQmlValueTypeProxyBinding *>(b);
+ QQmlAbstractBinding *b = data->bindings;
+ while (b && (b->targetPropertyIndex().coreIndex() != coreIndex ||
+ b->targetPropertyIndex().hasValueTypeIndex())) {
+ b = b->nextBinding();
}
- if (!proxy) {
+ if (b && b->kind() == QQmlAbstractBinding::ValueTypeProxy) {
+ proxy = static_cast<QQmlValueTypeProxyBinding *>(b);
+ } else {
proxy = new QQmlValueTypeProxyBinding(obj, QQmlPropertyIndex(coreIndex));
Q_ASSERT(proxy->targetPropertyIndex().coreIndex() == coreIndex);
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 551f55b4be..31b3c28690 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -218,7 +218,9 @@ protected:
}
// If the type didn't match, we need to do JavaScript conversion. This should be rare.
- return write(engine()->handle()->metaTypeToJS(type, result), isUndefined, flags);
+ QV4::Scope scope(engine()->handle());
+ QV4::ScopedValue value(scope, engine()->handle()->metaTypeToJS(type, result));
+ return write(value, isUndefined, flags);
}
// Returns true if successful, false if an error description was set on expression
@@ -439,8 +441,10 @@ bool QQmlBinding::slowWrite(
if (core.isVarProperty()) {
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_target.data());
Q_ASSERT(vmemo);
+ QV4::Scope scope(qmlEngine->handle());
+ QV4::ScopedValue value(scope, qmlEngine->handle()->metaTypeToJS(resultType, result));
vmemo->setVMEProperty(core.coreIndex(),
- qmlEngine->handle()->metaTypeToJS(resultType, result));
+ value);
} else if (isUndefined && core.isResettable()) {
void *args[] = { nullptr };
QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex(), args);
@@ -697,7 +701,7 @@ void QQmlBinding::doUpdate(const DeleteWatcher &watcher, QQmlPropertyData::Write
error = !write(result, returnType, isUndefined, flags);
returnType.destruct(result);
} else if (canWrite()) {
- error = !write(QV4::Encode::undefined(), true, flags);
+ error = !write(QV4::Value::undefinded(), true, flags);
}
}
} else {
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 60e5dd4c9b..9cc57eed13 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -382,7 +382,8 @@ bool QQmlComponentPrivate::setInitialProperty(
}
const QString lastProperty = properties.last();
segment = scope.engine->newString(lastProperty);
- object->put(segment, scope.engine->metaTypeToJS(value.metaType(), value.constData()));
+ QV4::ScopedValue v(scope, scope.engine->metaTypeToJS(value.metaType(), value.constData()));
+ object->put(segment, v);
if (scope.engine->hasException) {
qmlWarning(base, scope.engine->catchExceptionAsQmlError());
scope.engine->hasException = false;
@@ -927,6 +928,11 @@ QObject *QQmlComponent::create(QQmlContext *context)
there are unset required properties, the object creation fails and returns
\c nullptr, in which case \l isError() will return \c true.
+ If \a context is \nullptr (the default), it will create the instance in the
+ \l {QQmlEngine::rootContext()}{root context} of the engine.
+
+ The ownership of the returned object instance is transferred to the caller.
+
\sa QQmlComponent::create
\since 5.14
*/
@@ -1419,8 +1425,8 @@ void QQmlComponentPrivate::completeLoadFromModule(QAnyStringView uri, QAnyString
\a incubator. \a context specifies the context within which to create the object
instance.
- If \a context is \nullptr (by default), it will create the instance in the
- engine's \l {QQmlEngine::rootContext()}{root context}.
+ If \a context is \nullptr (the default), it will create the instance in the
+ \l {QQmlEngine::rootContext()}{root context} of the engine.
\a forContext specifies a context that this object creation depends upon.
If the \a forContext is being created asynchronously, and the
diff --git a/src/qml/qml/qqmlcontextdata.cpp b/src/qml/qml/qqmlcontextdata.cpp
index 8667a1ce81..22a359d93f 100644
--- a/src/qml/qml/qqmlcontextdata.cpp
+++ b/src/qml/qml/qqmlcontextdata.cpp
@@ -100,7 +100,6 @@ void QQmlContextData::invalidate()
}
m_importedScripts.clear();
-
m_engine = nullptr;
clearParent();
}
@@ -111,6 +110,8 @@ void QQmlContextData::clearContextRecursively()
for (auto ctxIt = m_childContexts; ctxIt; ctxIt = ctxIt->m_nextChild)
ctxIt->clearContextRecursively();
+
+ m_engine = nullptr;
}
void QQmlContextData::clearContext()
@@ -137,8 +138,7 @@ QQmlContextData::~QQmlContextData()
// avoid recursion
addref();
- if (m_engine)
- invalidate();
+ invalidate();
m_linkedContext.reset();
Q_ASSERT(refCount() == 1);
diff --git a/src/qml/qml/qqmlcontextdata_p.h b/src/qml/qml/qqmlcontextdata_p.h
index f5d54c8fd2..ae95123d8c 100644
--- a/src/qml/qml/qqmlcontextdata_p.h
+++ b/src/qml/qml/qqmlcontextdata_p.h
@@ -277,6 +277,15 @@ public:
QV4::PersistentValue importedScripts() const { return m_importedScripts; }
void setImportedScripts(const QV4::PersistentValue &scripts) { m_importedScripts = scripts; }
+ /*
+ we can safely pass a ReturnedValue here, as setImportedScripts will directly store
+ scripts in a persistentValue, without any intermediate allocation that could trigger
+ a gc run
+ */
+ void setImportedScripts(QV4::ExecutionEngine *engine, QV4::ReturnedValue scripts) {
+ m_importedScripts.set(engine, scripts);
+ }
+
QQmlRefPointer<QQmlContextData> linkedContext() const { return m_linkedContext; }
void setLinkedContext(const QQmlRefPointer<QQmlContextData> &context) { m_linkedContext = context; }
diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp
index 96a5679599..655264435c 100644
--- a/src/qml/qml/qqmldelayedcallqueue.cpp
+++ b/src/qml/qml/qqmldelayedcallqueue.cpp
@@ -153,7 +153,8 @@ void QQmlDelayedCallQueue::storeAnyArguments(DelayedFunctionCall &dfc, QQmlV4Fun
QV4::ScopedArrayObject array(scope, engine->newArrayObject(length));
uint i = 0;
for (int j = offset, ej = args->length(); j < ej; ++i, ++j)
- array->put(i, (*args)[j]);
+ // fromReturnedValue is safe, args should already ensure marking
+ array->put(i, QV4::Value::fromReturnedValue((*args)[j]));
dfc.m_args.set(engine, array);
}
diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp
index 441fc6200d..09f400c173 100644
--- a/src/qml/qml/qqmlextensionplugin.cpp
+++ b/src/qml/qml/qqmlextensionplugin.cpp
@@ -35,7 +35,7 @@ QT_BEGIN_NAMESPACE
The \l {Writing QML Extensions with C++} tutorial also contains a chapter
on creating QML plugins.
- \sa QQmlEngine::importPlugin(), {How to Create Qt Plugins}
+ \sa {How to Create Qt Plugins}
*/
/*!
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp
index 398011226f..3dfbe9c85a 100644
--- a/src/qml/qml/qqmlglobal.cpp
+++ b/src/qml/qml/qqmlglobal.cpp
@@ -363,7 +363,7 @@ static bool byProperties(
if (sourceMetaType == QMetaType::fromType<QJSValue>()) {
const QJSValue *val = static_cast<const QJSValue *>(source);
return byProperties(
- targetMetaObject, target, QV4::Value(QJSValuePrivate::asReturnedValue(val)));
+ targetMetaObject, target, QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(val)));
}
if (sourceMetaType == QMetaType::fromType<QVariantMap>()) {
@@ -431,7 +431,8 @@ bool QQmlValueTypeProvider::createValueType(
if (targetType.canPopulateValueType()
&& byProperties(
targetMetaObject, target,
- QV4::Value(QJSValuePrivate::asReturnedValue(&source)))) {
+ // fromReturnedValue is OK here because QJSValue holds a PersistentValue
+ QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(&source)))) {
return true;
}
@@ -440,7 +441,9 @@ bool QQmlValueTypeProvider::createValueType(
targetMetaObject, targetMetaType, target,
[&](QMetaType parameterType, auto callback) {
QVariant variant = QV4::ExecutionEngine::toVariant(
- QJSValuePrivate::asReturnedValue(&source), parameterType);
+ // fromReturnedValue is OK here because QJSValue holds a PersistentValue
+ QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(&source)),
+ parameterType);
return callback(variant.metaType(), variant.data());
})) {
return true;
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index fe8ae5295c..fbe0459343 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -389,6 +389,16 @@ QQmlImportDatabase::LocalQmldirResult QQmlImportDatabase::locateLocalQmldir(
QString qmldirAbsoluteFilePath;
for (QString qmldirPath : qmlDirPaths) {
if (hasInterceptors) {
+ // TODO:
+ // 1. This is inexact. It triggers only on the existence of interceptors, not on
+ // actual interception. If the URL was remote to begin with but no interceptor
+ // actually changes it, we still clear the qmldirPath and consider it
+ // QmldirInterceptedToRemote.
+ // 2. This misdiagnosis makes addLibraryImport do the right thing and postpone
+ // the loading of pre-registered types for any QML engine that has interceptors
+ // (even if they don't do anything in this case).
+ // Fixing this would open the door to follow-up problems but wouldn't result in any
+ // significant benefit.
const QUrl intercepted = engine->interceptUrl(
QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
QQmlAbstractUrlInterceptor::QmldirFile);
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index 90571fdf50..4fc3f1a737 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -103,6 +103,8 @@ QQmlIncubatorPrivate::~QQmlIncubatorPrivate()
void QQmlIncubatorPrivate::clear()
{
+ if (!enginePriv)
+ return;
// reset the tagged pointer
if (requiredPropertiesFromComponent)
requiredPropertiesFromComponent = decltype(requiredPropertiesFromComponent){};
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index e3c0ba19ae..497fe43a73 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -377,9 +377,11 @@ ReturnedValue PropertyListPrototype::method_splice(const FunctionObject *b, cons
ScopedArrayObject newArray(scope, scope.engine->newArrayObject());
newArray->arrayReserve(deleteCount);
ScopedValue v(scope);
+ QV4::ScopedValue wrappedObject(scope);
for (qsizetype i = 0; i < deleteCount; ++i) {
+ wrappedObject = QObjectWrapper::wrap(scope.engine, property->at(property, start + i));
newArray->arrayPut(
- i, QObjectWrapper::wrap(scope.engine, property->at(property, start + i)));
+ i, wrappedObject);
}
newArray->setArrayLengthUnchecked(deleteCount);
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index f09024d330..5caaafdc5c 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1169,10 +1169,22 @@ QVariant QQmlPropertyPrivate::readValueProperty()
}
return QVariant();
} else if (core.isQList()) {
+ auto coreMetaType = core.propType();
- QQmlListProperty<QObject> prop;
- core.readProperty(object, &prop);
- return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType()));
+ // IsQmlList is set for QQmlListPropery and list<ObjectType>
+ if (coreMetaType.flags() & QMetaType::IsQmlList) {
+ QQmlListProperty<QObject> prop;
+ core.readProperty(object, &prop);
+ return QVariant::fromValue(QQmlListReferencePrivate::init(prop, coreMetaType));
+ } else {
+ // but not for lists of value types
+ QVariant result(coreMetaType);
+ // TODO: ideally, we would not default construct and copy assign,
+ // but do a single copy-construct; we don't have API for that, though
+ coreMetaType.construct(result.data());
+ core.readProperty(object, result.data());
+ return result;
+ }
} else if (core.isQObject()) {
@@ -1504,7 +1516,8 @@ static bool tryAssignBinding(
if (!f || !f->isBinding())
return false;
- QV4::QObjectWrapper::setProperty(f->engine(), object, &property, f->asReturnedValue());
+ // fromReturnedValue is safe! f is stored in the QJSValue, so htere's already a persistent reference to it
+ QV4::QObjectWrapper::setProperty(f->engine(), object, &property, QV4::Value::fromReturnedValue(f->asReturnedValue()));
return true;
}
diff --git a/src/qml/qml/qqmlpropertybinding.cpp b/src/qml/qml/qqmlpropertybinding.cpp
index 5f646b62de..4de4ce8ccc 100644
--- a/src/qml/qml/qqmlpropertybinding.cpp
+++ b/src/qml/qml/qqmlpropertybinding.cpp
@@ -131,6 +131,9 @@ QUntypedPropertyBinding QQmlPropertyBinding::createFromBoundFunction(const QQmlP
void QQmlPropertyBindingJS::expressionChanged()
{
+ if (!hasValidContext())
+ return;
+
auto binding = asBinding();
if (!binding->propertyDataPtr)
return;
diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp
index c49ce14351..c7d187ef3a 100644
--- a/src/qml/qml/qqmlpropertycachecreator.cpp
+++ b/src/qml/qml/qqmlpropertycachecreator.cpp
@@ -140,8 +140,8 @@ void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(
if (!pendingBinding.resolveInstantiatingProperty())
continue;
- auto cache = pendingBinding.instantiatingPropertyCache();
- propertyCaches->set(groupPropertyObjectIndex, cache);
+ if (auto cache = pendingBinding.instantiatingPropertyCache())
+ propertyCaches->set(groupPropertyObjectIndex, cache);
}
}
diff --git a/src/qml/qml/qqmlscriptblob.cpp b/src/qml/qml/qqmlscriptblob.cpp
index 4ea3816ed4..1b038a34ee 100644
--- a/src/qml/qml/qqmlscriptblob.cpp
+++ b/src/qml/qml/qqmlscriptblob.cpp
@@ -150,7 +150,7 @@ void QQmlScriptBlob::done()
for (int scriptIndex = 0; scriptIndex < m_scripts.size(); ++scriptIndex) {
const ScriptReference &script = m_scripts.at(scriptIndex);
- m_scriptData->scripts.append(script.script);
+ m_scriptData->scripts.append(script.script->scriptData());
if (!script.nameSpace.isNull()) {
if (!ns.contains(script.nameSpace)) {
diff --git a/src/qml/qml/qqmlscriptdata.cpp b/src/qml/qml/qqmlscriptdata.cpp
index 1a6a8157d0..5ed9345a4f 100644
--- a/src/qml/qml/qqmlscriptdata.cpp
+++ b/src/qml/qml/qqmlscriptdata.cpp
@@ -63,7 +63,7 @@ QQmlRefPointer<QQmlContextData> QQmlScriptData::qmlContextDataForContext(
}
QV4::ScopedValue v(scope);
for (int ii = 0; ii < scripts.size(); ++ii) {
- v = scripts.at(ii)->scriptData()->scriptValueForContext(qmlContextData);
+ v = scripts.at(ii)->scriptValueForContext(qmlContextData);
scriptsArray->put(ii, v);
}
diff --git a/src/qml/qml/qqmlscriptdata_p.h b/src/qml/qml/qqmlscriptdata_p.h
index c7100861e2..208e55d13f 100644
--- a/src/qml/qml/qqmlscriptdata_p.h
+++ b/src/qml/qml/qqmlscriptdata_p.h
@@ -39,7 +39,7 @@ public:
QUrl url;
QString urlString;
QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
- QVector<QQmlRefPointer<QQmlScriptBlob>> scripts;
+ QVector<QQmlRefPointer<QQmlScriptData>> scripts;
QV4::ReturnedValue scriptValueForContext(const QQmlRefPointer<QQmlContextData> &parentCtxt);
diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp
index d3cfeb3108..e18101af2b 100644
--- a/src/qml/qml/qqmltypedata.cpp
+++ b/src/qml/qml/qqmltypedata.cpp
@@ -350,104 +350,167 @@ void QQmlTypeData::setCompileUnit(const Container &container)
}
}
-void QQmlTypeData::done()
+bool QQmlTypeData::checkScripts()
{
- auto cleanup = qScopeGuard([this]{
- m_backupSourceCode = SourceCodeData();
- m_document.reset();
- m_typeReferences.clear();
- if (isError()) {
- const auto encounteredErrors = errors();
- for (const QQmlError &e : encounteredErrors)
- qCDebug(DBG_DISK_CACHE) << e.toString();
- m_compiledData.reset();
- }
- });
-
- if (isError())
- return;
-
// Check all script dependencies for errors
for (int ii = 0; ii < m_scripts.size(); ++ii) {
const ScriptReference &script = m_scripts.at(ii);
Q_ASSERT(script.script->isCompleteOrError());
if (script.script->isError()) {
- QList<QQmlError> errors = script.script->errors();
- QQmlError error;
- error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line()));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column()));
- error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
- errors.prepend(error);
- setError(errors);
- return;
+ createError(
+ script,
+ QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
+ return false;
}
}
+ return true;
+}
+
+void QQmlTypeData::createError(const TypeReference &type, const QString &message)
+{
+ createError(type, message, type.typeData ? type.typeData->errors() : QList<QQmlError>());
+}
+
+void QQmlTypeData::createError(const ScriptReference &script, const QString &message)
+{
+ createError(script, message, script.script ? script.script->errors() : QList<QQmlError>());
+}
+bool QQmlTypeData::checkDependencies()
+{
// Check all type dependencies for errors
- for (auto it = std::as_const(m_resolvedTypes).begin(), end = std::as_const(m_resolvedTypes).end(); it != end;
- ++it) {
+ for (auto it = std::as_const(m_resolvedTypes).begin(), end = std::as_const(m_resolvedTypes).end();
+ it != end; ++it) {
const TypeReference &type = *it;
- Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError() || type.type.isInlineComponentType());
+ Q_ASSERT(!type.typeData
+ || type.typeData->isCompleteOrError()
+ || type.type.isInlineComponentType());
if (type.errorWhenNotFound
- && type.type.isInlineComponentType()
- && !type.type.pendingResolutionName().isEmpty()) {
+ && type.type.isInlineComponentType()
+ && !type.type.pendingResolutionName().isEmpty()) {
auto containingType = type.type.containingType();
- auto objectId = containingType.lookupInlineComponentIdByName(type.type.pendingResolutionName());
- if (objectId < 0) { // can be any negative number if we tentatively resolved it in QQmlImport but it actually was not an inline component
- const QString typeName = stringAt(it.key());
- int lastDot = typeName.lastIndexOf(u'.');
+ auto objectId
+ = containingType.lookupInlineComponentIdByName(type.type.pendingResolutionName());
- QList<QQmlError> errors = type.typeData ? type.typeData->errors() : QList<QQmlError>{};
- QQmlError error;
- error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line()));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column()));
- error.setDescription(QQmlTypeLoader::tr("Type %1 has no inline component type called %2").arg(QStringView{typeName}.left(lastDot), type.type.pendingResolutionName()));
- errors.prepend(error);
- setError(errors);
- return;
+ // can be any negative number if we tentatively resolved it in QQmlImport but it
+ // actually was not an inline component
+ if (objectId < 0) {
+ const QString &typeName = stringAt(it.key());
+ int lastDot = typeName.lastIndexOf(u'.');
+ createError(
+ type,
+ QQmlTypeLoader::tr("Type %1 has no inline component type called %2")
+ .arg(QStringView{typeName}.left(lastDot), type.type.elementName()));
+ return false;
} else {
type.type.setInlineComponentObjectId(objectId);
}
}
if (type.errorWhenNotFound && type.typeData && type.typeData->isError()) {
- const QString typeName = stringAt(it.key());
-
- QList<QQmlError> errors = type.typeData->errors();
- QQmlError error;
- error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line()));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column()));
- error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
- errors.prepend(error);
- setError(errors);
- return;
+ const QString &typeName = stringAt(it.key());
+ createError(type, QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
+ return false;
}
}
+ return true;
+}
+
+bool QQmlTypeData::checkCompositeSingletons()
+{
// Check all composite singleton type dependencies for errors
for (int ii = 0; ii < m_compositeSingletons.size(); ++ii) {
const TypeReference &type = m_compositeSingletons.at(ii);
Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
if (type.typeData && type.typeData->isError()) {
QString typeName = type.type.qmlTypeName();
-
- QList<QQmlError> errors = type.typeData->errors();
- QQmlError error;
- error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line()));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column()));
- error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
- errors.prepend(error);
- setError(errors);
- return;
+ createError(type, QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
+ return false;
}
}
+ return true;
+}
+
+void QQmlTypeData::createQQmlType()
+{
m_typeClassName = QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(finalUrl());
if (!m_typeClassName.isEmpty())
m_typeIds = CompositeMetaTypeIds::fromCompositeName(m_typeClassName);
+}
+
+bool QQmlTypeData::rebuildFromSource()
+{
+ // Clear and re-build everything.
+
+ m_typeReferences.clear();
+ m_scripts.clear();
+ m_namespaces.clear();
+ m_compositeSingletons.clear();
+
+ m_resolvedTypes.clear();
+ m_typesResolved = false;
+
+ m_typeClassName.clear();
+
+ m_inlineComponentData.clear();
+ m_compiledData.reset();
+
+ m_implicitImportLoaded = false;
+
+ m_importCache.adopt(new QQmlImports(m_typeLoader));
+ m_unresolvedImports.clear();
+
+ if (!loadFromSource())
+ return false;
+
+ continueLoadFromIR();
+
+ if (!resolveTypes())
+ return false;
+
+ if (!checkScripts())
+ return false;
+
+ if (!checkDependencies())
+ return false;
+
+ if (!checkCompositeSingletons())
+ return false;
+
+ createQQmlType();
+
+ setupICs(m_document, &m_inlineComponentData, finalUrl());
+ return true;
+}
+
+void QQmlTypeData::done()
+{
+ auto cleanup = qScopeGuard([this]{
+ m_backupSourceCode = SourceCodeData();
+ m_document.reset();
+ m_typeReferences.clear();
+ if (isError()) {
+ const auto encounteredErrors = errors();
+ for (const QQmlError &e : encounteredErrors)
+ qCDebug(DBG_DISK_CACHE) << e.toString();
+ m_compiledData.reset();
+ }
+ });
+
+ if (isError())
+ return;
+
+ if (!checkScripts())
+ return;
+
+ if (!checkDependencies())
+ return;
+
+ if (!checkCompositeSingletons())
+ return;
+
+ createQQmlType();
if (m_document) {
setupICs(m_document, &m_inlineComponentData, finalUrl());
@@ -493,28 +556,18 @@ void QQmlTypeData::done()
<< m_compiledData->fileName();
}
- if (!loadFromSource())
+ resolvedTypeCache.clear();
+ typeNameCache.reset();
+
+ if (!rebuildFromSource())
return;
- // We want to keep our resolve types ...
- m_compiledData->resolvedTypes.clear();
- // ... but we don't want the property caches we've created for the broken CU.
- for (QV4::ResolvedTypeReference *ref: std::as_const(resolvedTypeCache)) {
- const auto compilationUnit = ref->compilationUnit();
- if (compilationUnit.isNull()) {
- // Inline component references without CU belong to the surrounding CU.
- // We have to clear them. Inline component references to other documents
- // have a CU.
- if (!ref->type().isInlineComponentType())
- continue;
- } else if (compilationUnit != m_compiledData) {
- continue;
- }
- ref->setTypePropertyCache(QQmlPropertyCache::ConstPtr());
- ref->setCompilationUnit(QQmlRefPointer<QV4::ExecutableCompilationUnit>());
+ const QQmlError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
+ if (error.isValid()) {
+ setError(error);
+ qDeleteAll(resolvedTypeCache);
+ return;
}
-
- m_compiledData.reset();
}
}
@@ -809,36 +862,8 @@ void QQmlTypeData::allDependenciesDone()
{
QQmlTypeLoader::Blob::allDependenciesDone();
- if (!m_typesResolved) {
- // Check that all imports were resolved
- QList<QQmlError> errors;
- auto it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd();
- for ( ; it != end; ++it) {
- if ((*it)->priority == 0) {
- // This import was not resolved
- for (auto keyIt = m_unresolvedImports.constBegin(),
- keyEnd = m_unresolvedImports.constEnd();
- keyIt != keyEnd; ++keyIt) {
- const PendingImportPtr &import = *keyIt;
- QQmlError error;
- error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(import->uri));
- error.setUrl(m_importCache->baseUrl());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(
- import->location.line()));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(
- import->location.column()));
- errors.prepend(error);
- }
- }
- }
- if (errors.size()) {
- setError(errors);
- return;
- }
-
+ if (!m_typesResolved)
resolveTypes();
- m_typesResolved = true;
- }
}
void QQmlTypeData::downloadProgressChanged(qreal p)
@@ -889,8 +914,39 @@ void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCach
}
}
-void QQmlTypeData::resolveTypes()
+bool QQmlTypeData::resolveTypes()
{
+ Q_ASSERT(!m_typesResolved);
+
+ // Check that all imports were resolved
+ QList<QQmlError> errors;
+ auto it = m_unresolvedImports.constBegin(), end = m_unresolvedImports.constEnd();
+ for ( ; it != end; ++it) {
+ const PendingImportPtr &import = *it;
+ if (import->priority != 0)
+ continue;
+
+ // If the import was potentially remote and all the network requests have failed,
+ // we now know that there is no qmldir. We can register its types.
+ if (registerPendingTypes(import))
+ continue;
+
+ // This import was not resolved
+ QQmlError error;
+ error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(import->uri));
+ error.setUrl(m_importCache->baseUrl());
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(
+ import->location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(
+ import->location.column()));
+ errors.prepend(error);
+ }
+
+ if (errors.size()) {
+ setError(errors);
+ return false;
+ }
+
// Add any imported scripts to our resolved set
const auto resolvedScripts = m_importCache->resolvedScripts();
for (const QQmlImports::ScriptReference &script : resolvedScripts) {
@@ -927,7 +983,7 @@ void QQmlTypeData::resolveTypes()
QTypeRevision version = csRef.version;
if (!resolveType(typeName, version, ref, -1, -1, true, QQmlType::CompositeSingletonType))
- return;
+ return false;
if (ref.type.isCompositeSingleton()) {
ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
@@ -943,7 +999,7 @@ void QQmlTypeData::resolveTypes()
}
}
- for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd();
+ for (auto unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd();
unresolvedRef != end; ++unresolvedRef) {
TypeReference ref; // resolved reference
@@ -959,7 +1015,7 @@ void QQmlTypeData::resolveTypes()
if (!resolveType(name, version, ref, unresolvedRef->location.line(),
unresolvedRef->location.column(), reportErrors,
QQmlType::AnyRegistrationType, selfReferenceDetection) && reportErrors)
- return;
+ return false;
if (ref.type.isComposite() && !ref.selfReference) {
ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
@@ -969,7 +1025,7 @@ void QQmlTypeData::resolveTypes()
auto containingType = ref.type.containingType();
if (containingType.isValid()) {
auto const url = containingType.sourceUrl();
- if (url.isValid()) {
+ if (!url.isEmpty() && url != finalUrl()) {
auto typeData = typeLoader()->getType(url);
ref.typeData = typeData;
addDependency(typeData.data());
@@ -985,8 +1041,11 @@ void QQmlTypeData::resolveTypes()
}
// ### this allows enums to work without explicit import or instantiation of the type
- if (!m_implicitImportLoaded)
- loadImplicitImport();
+ if (!m_implicitImportLoaded && !loadImplicitImport())
+ return false;
+
+ m_typesResolved = true;
+ return true;
}
QQmlError QQmlTypeData::buildTypeResolutionCaches(
diff --git a/src/qml/qml/qqmltypedata_p.h b/src/qml/qml/qqmltypedata_p.h
index b067dea5bf..00007e1433 100644
--- a/src/qml/qml/qqmltypedata_p.h
+++ b/src/qml/qml/qqmltypedata_p.h
@@ -15,6 +15,7 @@
// We mean it.
//
+#include <private/qqmlsourcecoordinate_p.h>
#include <private/qqmltypeloader_p.h>
#include <private/qv4executablecompilationunit_p.h>
@@ -87,7 +88,7 @@ private:
bool loadFromSource();
void restoreIR(QV4::CompiledData::CompilationUnit &&unit);
void continueLoadFromIR();
- void resolveTypes();
+ bool resolveTypes();
QQmlError buildTypeResolutionCaches(
QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
QV4::ResolvedTypeReferenceMap *resolvedTypeCache
@@ -136,6 +137,27 @@ private:
bool m_implicitImportLoaded;
bool loadImplicitImport();
+ bool checkScripts();
+ bool checkDependencies();
+
+ template<typename Reference>
+ void createError(const Reference &ref, const QString &message, QList<QQmlError> errors)
+ {
+ QQmlError error;
+ error.setUrl(url());
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(ref.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(ref.location.column()));
+ error.setDescription(message);
+ errors.prepend(std::move(error));
+ setError(errors);
+ }
+
+ void createError(const TypeReference &type, const QString &message);
+ void createError(const ScriptReference &script, const QString &message);
+
+ bool checkCompositeSingletons();
+ void createQQmlType();
+ bool rebuildFromSource();
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 68c1163c8c..cf861cfd65 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -681,67 +681,59 @@ bool QQmlTypeLoader::Blob::addLibraryImport(const QQmlTypeLoader::Blob::PendingI
// If there is a qmldir we cannot see, yet, then we have to wait.
// The qmldir might contain import directives.
- if (qmldirResult != QQmlImportDatabase::QmldirInterceptedToRemote && (
- // Major version of module already registered:
- // We believe that the registration is complete.
- QQmlMetaType::typeModule(import->uri, import->version)
+ // TODO: This should trigger on any potentially remote URLs, not only intercepted ones.
+ // However, fixing this would open the door for follow-up problems while providing
+ // rather limited benefits.
+ if (qmldirResult != QQmlImportDatabase::QmldirInterceptedToRemote
+ && registerPendingTypes(import)) {
+ if (m_importCache->addLibraryImport(
+ importDatabase, import->uri, import->qualifier, import->version, QString(),
+ QString(), import->flags, import->precedence, errors).isValid()) {
+ return true;
+ }
- // Otherwise, try to register further module types.
- || QQmlMetaType::qmlRegisterModuleTypes(import->uri)
+ return false;
+ }
- // Otherwise, there is no way to register any further types.
- // Try with any module of that name.
- || QQmlMetaType::latestModuleVersion(import->uri).isValid())) {
+ // We haven't yet resolved this import
+ m_unresolvedImports << import;
- if (!m_importCache->addLibraryImport(
- importDatabase, import->uri, import->qualifier, import->version,
- QString(), QString(), import->flags, import->precedence, errors).isValid()) {
- return false;
- }
- } else {
- // We haven't yet resolved this import
- m_unresolvedImports << import;
-
- const QQmlEngine *engine = typeLoader()->engine();
- const bool hasInterceptors
- = !(QQmlEnginePrivate::get(engine)->urlInterceptors.isEmpty());
-
- // Query any network import paths for this library.
- // Interceptor might redirect local paths.
- QStringList remotePathList = importDatabase->importPathList(
- hasInterceptors ? QQmlImportDatabase::LocalOrRemote
- : QQmlImportDatabase::Remote);
- if (!remotePathList.isEmpty()) {
- // Add this library and request the possible locations for it
- const QTypeRevision version = m_importCache->addLibraryImport(
- importDatabase, import->uri, import->qualifier, import->version,
- QString(), QString(), import->flags | QQmlImports::ImportIncomplete,
- import->precedence, errors);
-
- if (!version.isValid())
- return false;
+ // Add this library and request the possible locations for it
+ const QTypeRevision version = m_importCache->addLibraryImport(
+ importDatabase, import->uri, import->qualifier, import->version, QString(),
+ QString(), import->flags | QQmlImports::ImportIncomplete, import->precedence,
+ errors);
+
+ if (!version.isValid())
+ return false;
- // Use more specific version for finding the qmldir if possible
- if (version.hasMajorVersion())
- import->version = version;
-
- // Probe for all possible locations
- int priority = 0;
- const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
- import->uri, remotePathList, import->version);
- for (const QString &qmldirPath : qmlDirPaths) {
- if (hasInterceptors) {
- QUrl url = engine->interceptUrl(
- QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
- QQmlAbstractUrlInterceptor::QmldirFile);
- if (!QQmlFile::isLocalFile(url)
- && !fetchQmldir(url, import, ++priority, errors)) {
- return false;
- }
- } else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) {
+ // Use more specific version for finding the qmldir if possible
+ if (version.hasMajorVersion())
+ import->version = version;
+
+ const QQmlEngine *engine = typeLoader()->engine();
+ const bool hasInterceptors = !(QQmlEnginePrivate::get(engine)->urlInterceptors.isEmpty());
+
+ // Query any network import paths for this library.
+ // Interceptor might redirect local paths.
+ QStringList remotePathList = importDatabase->importPathList(
+ hasInterceptors ? QQmlImportDatabase::LocalOrRemote : QQmlImportDatabase::Remote);
+ if (!remotePathList.isEmpty()) {
+ // Probe for all possible locations
+ int priority = 0;
+ const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
+ import->uri, remotePathList, import->version);
+ for (const QString &qmldirPath : qmlDirPaths) {
+ if (hasInterceptors) {
+ QUrl url = engine->interceptUrl(
+ QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
+ QQmlAbstractUrlInterceptor::QmldirFile);
+ if (!QQmlFile::isLocalFile(url)
+ && !fetchQmldir(url, import, ++priority, errors)) {
return false;
}
-
+ } else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) {
+ return false;
}
}
}
@@ -749,6 +741,21 @@ bool QQmlTypeLoader::Blob::addLibraryImport(const QQmlTypeLoader::Blob::PendingI
return true;
}
+bool QQmlTypeLoader::Blob::registerPendingTypes(const PendingImportPtr &import)
+{
+ return
+ // Major version of module already registered:
+ // We believe that the registration is complete.
+ QQmlMetaType::typeModule(import->uri, import->version)
+
+ // Otherwise, try to register further module types.
+ || QQmlMetaType::qmlRegisterModuleTypes(import->uri)
+
+ // Otherwise, there is no way to register any further types.
+ // Try with any module of that name.
+ || QQmlMetaType::latestModuleVersion(import->uri).isValid();
+}
+
bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import,
QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
{
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 854778125a..0c6df56d5a 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -102,6 +102,9 @@ public:
QQmlImports::ImportFlags flags, QList<QQmlError> *errors);
protected:
+
+ bool registerPendingTypes(const PendingImportPtr &import);
+
bool loadDependentImports(
const QList<QQmlDirParser::Import> &imports, const QString &qualifier,
QTypeRevision version, quint16 precedence, QQmlImports::ImportFlags flags,
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 6bd26f65dd..b036066f2f 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -570,6 +570,13 @@ QMetaType QQmlValueTypeWrapper::type() const
bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
{
bool destructGadgetOnExit = false;
+ auto cleanup = qScopeGuard([&]() {
+ if (destructGadgetOnExit) {
+ d()->valueType()->metaType().destruct(d()->gadgetPtr());
+ d()->setGadgetPtr(nullptr);
+ }
+ });
+
Q_ALLOCA_DECLARE(void, gadget);
if (d()->isReference()) {
if (!d()->gadgetPtr()) {
@@ -586,11 +593,6 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
int status = -1;
void *a[] = { d()->gadgetPtr(), nullptr, &status, &flags };
QMetaObject::metacall(target, QMetaObject::WriteProperty, propertyIndex, a);
-
- if (destructGadgetOnExit) {
- d()->valueType()->metaType().destruct(d()->gadgetPtr());
- d()->setGadgetPtr(nullptr);
- }
return true;
}
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 94c2c254c0..e27ab165be 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -119,8 +119,9 @@ void ResolvedList::append(QObject *o) const
QV4::ScopedObject object(scope, m_list);
QV4::ArrayData::realloc(object, QV4::Heap::ArrayData::Simple, length + 1, false);
+ QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(scope.engine, o));
arrayData->vtable()->put(
- object, length, QV4::QObjectWrapper::wrap(scope.engine, o));
+ object, length, wrappedObject);
}
QObject *ResolvedList::at(qsizetype i) const
@@ -134,7 +135,8 @@ void ResolvedList::replace(qsizetype i, QObject *o) const
{
QV4::Scope scope(m_list->internalClass->engine);
QV4::ScopedObject object(scope, m_list);
- m_list->arrayData->vtable()->put(object, i, QV4::QObjectWrapper::wrap(scope.engine, o));
+ QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(scope.engine, o));
+ m_list->arrayData->vtable()->put(object, i, wrappedObject);
}
static void list_append(QQmlListProperty<QObject> *prop, QObject *o)
diff --git a/src/qml/qmltc/supportlibrary/qqmlcpptypehelpers_p.h b/src/qml/qmltc/supportlibrary/qqmlcpptypehelpers_p.h
index 2470d87efe..bd3b987624 100644
--- a/src/qml/qmltc/supportlibrary/qqmlcpptypehelpers_p.h
+++ b/src/qml/qmltc/supportlibrary/qqmlcpptypehelpers_p.h
@@ -1,8 +1,8 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QQMLCPPTYPEHELPERS_H
-#define QQMLCPPTYPEHELPERS_H
+#ifndef QQMLCPPTYPEHELPERS_P_H
+#define QQMLCPPTYPEHELPERS_P_H
//
// W A R N I N G
@@ -25,4 +25,4 @@ using passByConstRefOrValue =
std::conditional_t<((sizeof(T) > 3 * sizeof(void *)) || !std::is_trivial_v<T>), const T &,
T>;
-#endif // QQMLCPPTYPEHELPERS_H
+#endif // QQMLCPPTYPEHELPERS_P_H
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index f6513c60a1..437d9b06f0 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -57,10 +57,8 @@ public:
silentDestroy(oldKind);
switch (newKind) {
case QQmlBindEntryKind::V4Value:
- new (&v4Value) QV4::PersistentValue(std::move(other.v4Value));
- break;
case QQmlBindEntryKind::Variant:
- new (&variant) QVariant(std::move(other.variant));
+ new (&v4Value) QV4::PersistentValue(std::move(other.v4Value));
break;
case QQmlBindEntryKind::Binding:
new (&binding) QQmlAnyBinding(std::move(other.binding));
@@ -77,10 +75,8 @@ public:
silentDestroy(oldKind);
switch (newKind) {
case QQmlBindEntryKind::V4Value:
- new (&v4Value) QV4::PersistentValue(other.v4Value);
- break;
case QQmlBindEntryKind::Variant:
- new (&variant) QVariant(other.variant);
+ new (&v4Value) QV4::PersistentValue(other.v4Value);
break;
case QQmlBindEntryKind::Binding:
new (&binding) QQmlAnyBinding(other.binding);
@@ -95,10 +91,8 @@ public:
{
switch (kind) {
case QQmlBindEntryKind::V4Value:
- v4Value.~PersistentValue();
- break;
case QQmlBindEntryKind::Variant:
- variant.~QVariant();
+ v4Value.~PersistentValue();
break;
case QQmlBindEntryKind::Binding:
binding.~QQmlAnyBinding();
@@ -109,10 +103,11 @@ public:
return QQmlBindEntryKind::None;
}
- [[nodiscard]] QQmlBindEntryKind set(QVariant v, QQmlBindEntryKind oldKind)
+ [[nodiscard]] QQmlBindEntryKind set(
+ QV4::ExecutionEngine *engine, const QVariant &v, QQmlBindEntryKind oldKind)
{
silentDestroy(oldKind);
- new (&variant) QVariant(std::move(v));
+ new (&v4Value) QV4::PersistentValue(engine, engine->fromVariant(v));
return QQmlBindEntryKind::Variant;
}
@@ -123,6 +118,13 @@ public:
return QQmlBindEntryKind::V4Value;
}
+ [[nodiscard]] QQmlBindEntryKind setVariant(QV4::PersistentValue v, QQmlBindEntryKind oldKind)
+ {
+ silentDestroy(oldKind);
+ new (&v4Value) QV4::PersistentValue(std::move(v));
+ return QQmlBindEntryKind::Variant;
+ }
+
[[nodiscard]] QQmlBindEntryKind set(QQmlAnyBinding v, QQmlBindEntryKind oldKind)
{
silentDestroy(oldKind);
@@ -131,7 +133,6 @@ public:
}
QV4::PersistentValue v4Value;
- QVariant variant;
QQmlAnyBinding binding;
private:
@@ -558,14 +559,22 @@ QVariant QQmlBind::value() const
if (!d->lastIsTarget)
return QVariant();
Q_ASSERT(d->entries.last().currentKind == QQmlBindEntryKind::Variant);
- return d->entries.last().current.variant;
+ const auto &v4Value = d->entries.last().current.v4Value;
+ QV4::ExecutionEngine *engine = v4Value.engine();
+ return engine->toVariant(*v4Value.valueRef(), QMetaType());
}
void QQmlBind::setValue(const QVariant &v)
{
Q_D(QQmlBind);
QQmlBindEntry *targetEntry = d->targetEntry();
- targetEntry->currentKind = targetEntry->current.set(v, targetEntry->currentKind);
+ QQmlEngine *engine = qmlEngine(this);
+ if (!engine) {
+ qWarning() << "QQmlBind must be created in a QML context";
+ return;
+ }
+ targetEntry->currentKind
+ = targetEntry->current.set(engine->handle(), v, targetEntry->currentKind);
prepareEval();
}
@@ -843,8 +852,8 @@ void QQmlBindPrivate::decodeBinding(
return;
}
- const auto setVariant = [&entry](QVariant var) {
- entry.currentKind = entry.current.set(std::move(var), entry.currentKind);
+ const auto setVariant = [&entry](QV4::PersistentValue value) {
+ entry.currentKind = entry.current.setVariant(value, entry.currentKind);
};
const auto setBinding = [&entry](QQmlAnyBinding binding) {
@@ -874,16 +883,20 @@ void QQmlBindPrivate::decodeBinding(
}
break;
case QV4::CompiledData::Binding::Type_String:
- setVariant(compilationUnit->bindingValueAsString(binding));
+ setVariant(QV4::PersistentValue(
+ compilationUnit->engine,
+ compilationUnit->runtimeStrings[binding->stringIndex]->asReturnedValue()));
break;
case QV4::CompiledData::Binding::Type_Number:
- setVariant(compilationUnit->bindingValueAsNumber(binding));
+ setVariant(QV4::PersistentValue(
+ compilationUnit->engine,
+ compilationUnit->constants[binding->value.constantValueIndex].asReturnedValue()));
break;
case QV4::CompiledData::Binding::Type_Boolean:
- setVariant(binding->valueAsBoolean());
+ setVariant(QV4::PersistentValue(compilationUnit->engine, QV4::Encode(binding->value.b)));
break;
case QV4::CompiledData::Binding::Type_Null:
- setVariant(QVariant::fromValue(nullptr));
+ setVariant(QV4::PersistentValue(compilationUnit->engine, QV4::Encode::null()));
break;
case QV4::CompiledData::Binding::Type_Object:
case QV4::CompiledData::Binding::Type_Invalid:
@@ -1038,7 +1051,9 @@ void QQmlBind::eval()
case QQmlBindEntryKind::Variant:
if (d->restoreValue) {
QQmlAnyBinding::takeFrom(entry.prop); // we don't want to have a binding active
- entry.prop.write(entry.previous.variant);
+ const QV4::PersistentValue &v4Value = entry.previous.v4Value;
+ entry.prop.write(v4Value.engine()->toVariant(
+ *v4Value.valueRef(), entry.prop.propertyMetaType()));
entry.clearPrev();
}
break;
@@ -1066,7 +1081,8 @@ void QQmlBind::eval()
QV4::PersistentValue(vmemo->engine, retVal), entry.previousKind);
} else {
// nope, use the meta object to get a QVariant
- entry.previousKind = entry.previous.set(entry.prop.read(), entry.previousKind);
+ entry.previousKind = entry.previous.set(
+ propPriv->engine->handle(), entry.prop.read(), entry.previousKind);
}
}
}
@@ -1085,9 +1101,12 @@ void QQmlBind::eval()
if (!entry.prop.isValid())
continue;
switch (entry.currentKind) {
- case QQmlBindEntryKind::Variant:
- entry.prop.write(entry.current.variant);
+ case QQmlBindEntryKind::Variant: {
+ const QV4::PersistentValue &v4Value = entry.current.v4Value;
+ entry.prop.write(
+ v4Value.engine()->toVariant(*v4Value.valueRef(), entry.prop.propertyMetaType()));
break;
+ }
case QQmlBindEntryKind::Binding:
Q_ASSERT(!d->delayed);
entry.current.binding.installOn(entry.prop);