aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorTarja Sundqvist <tarja.sundqvist@qt.io>2023-10-03 14:55:01 +0300
committerTarja Sundqvist <tarja.sundqvist@qt.io>2023-10-03 14:55:01 +0300
commiteca36baf3d8c6c52509f487f75dc7c46bd63e73c (patch)
tree408acf2cc6d3227a82e2f2765bc6ad71e3bff5c7 /src/qml
parent4a6dfcd838a62ed7b3500326af6099c00a5cbf49 (diff)
parentb65d9135ebd43d5bf3cc882a94230a305893fd6a (diff)
Merge remote-tracking branch 'origin/tqtc/lts-6.2.7' into tqtc/lts-6.2-opensource
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/Qt6QmlMacros.cmake10
-rw-r--r--src/qml/common/qv4compileddata_p.h6
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp62
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h4
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc4
-rw-r--r--src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc2
-rw-r--r--src/qml/jsapi/qjsvalue.cpp10
-rw-r--r--src/qml/jsruntime/qv4engine.cpp19
-rw-r--r--src/qml/jsruntime/qv4engine_p.h11
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp11
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4reflect.cpp5
-rw-r--r--src/qml/qml/qqmlcomponent.cpp10
-rw-r--r--src/qml/qml/qqmlincubator.cpp15
-rw-r--r--src/qml/qml/qqmlpropertycachecreator.cpp4
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h11
-rw-r--r--src/qml/qml/qqmlpropertydata_p.h1
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp10
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp9
19 files changed, 121 insertions, 85 deletions
diff --git a/src/qml/Qt6QmlMacros.cmake b/src/qml/Qt6QmlMacros.cmake
index d26f183f5d..bda7b9b83a 100644
--- a/src/qml/Qt6QmlMacros.cmake
+++ b/src/qml/Qt6QmlMacros.cmake
@@ -1810,6 +1810,11 @@ function(_qt_internal_qml_type_registration target)
if (TARGET ${target}Private)
list(APPEND cmd_args --private-includes)
+ else()
+ string(REGEX MATCH "Private$" privateSuffix ${target})
+ if (privateSuffix)
+ list(APPEND cmd_args --private-includes)
+ endif()
endif()
get_target_property(target_metatypes_json_file ${target} INTERFACE_QT_META_TYPES_BUILD_FILE)
@@ -2043,9 +2048,8 @@ but this file does not exist. Possible reasons include:
-cmake-output
)
get_target_property(qml_import_path ${target} QT_QML_IMPORT_PATH)
-
- if (qml_import_path)
- list(APPEND cmd_args ${qml_import_path})
+ if(qml_import_path)
+ list(APPEND qml_import_paths ${qml_import_path})
endif()
# Facilitate self-import so we can find the qmldir file
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index 3f33743ecf..8b2d5066c6 100644
--- a/src/qml/common/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -79,7 +79,11 @@ QT_BEGIN_NAMESPACE
// Also change the comment behind the number to describe the latest change. This has the added
// benefit that if another patch changes the version too, it will result in a merge conflict, and
// not get removed silently.
-#define QV4_DATA_STRUCTURE_VERSION 0x34 // added a flag to mark functions as closure wrappers
+
+// Note: We got two different versions 0x36 now, one with builtin value types and one without.
+// However, the one without is exclusive to Qt 6.4+ and the compiled data cannot be preserved
+// across Qt versions. Therefore, this is fine.
+#define QV4_DATA_STRUCTURE_VERSION 0x36 // reordered runtime functions when compiling at run time
class QIODevice;
class QQmlTypeNameCache;
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 1ac2c4c7e3..9739c936da 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1984,61 +1984,23 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
return runtimeFunctionIndices;
}
-bool JSCodeGen::generateCodeForComponents(const QVector<quint32> &componentRoots)
+bool JSCodeGen::generateRuntimeFunctions(QmlIR::Object *object)
{
- for (int i = 0; i < componentRoots.count(); ++i) {
- if (!compileComponent(componentRoots.at(i)))
- return false;
- }
-
- return compileComponent(/*root object*/0);
-}
-
-bool JSCodeGen::compileComponent(int contextObject)
-{
- const QmlIR::Object *obj = document->objects.at(contextObject);
- if (obj->flags & QV4::CompiledData::Object::IsComponent && !obj->isInlineComponent) {
- Q_ASSERT(obj->bindingCount() == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
- Q_ASSERT(componentBinding->type() == QV4::CompiledData::Binding::Type_Object);
- contextObject = componentBinding->value.objectIndex;
- }
-
- return compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject);
-}
-
-bool JSCodeGen::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
-{
- QmlIR::Object *object = document->objects.at(objectIndex);
- if (object->flags & QV4::CompiledData::Object::IsComponent && !object->isInlineComponent)
+ if (object->functionsAndExpressions->count == 0)
return true;
- for (auto it = object->inlineComponentsBegin(); it != object->inlineComponentsEnd(); ++it)
- compileComponent(it->objectIndex);
-
- if (object->functionsAndExpressions->count > 0) {
- QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
- for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next)
- functionsToCompile << *foe;
- const QVector<int> runtimeFunctionIndices = generateJSCodeForFunctionsAndBindings(functionsToCompile);
- if (hasError())
- return false;
-
- object->runtimeFunctionIndices.allocate(document->jsParserEngine.pool(),
- runtimeFunctionIndices);
+ QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
+ functionsToCompile.reserve(object->functionsAndExpressions->count);
+ for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe;
+ foe = foe->next) {
+ functionsToCompile << *foe;
}
- for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
- const Binding::Type bindingType = binding->type();
- if (bindingType < QV4::CompiledData::Binding::Type_Object)
- continue;
-
- int target = binding->value.objectIndex;
- int scope = bindingType == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex;
-
- if (!compileJavaScriptCodeInObjectsRecursively(binding->value.objectIndex, scope))
- return false;
- }
+ const auto runtimeFunctionIndices = generateJSCodeForFunctionsAndBindings(functionsToCompile);
+ if (hasError())
+ return false;
+ object->runtimeFunctionIndices.allocate(document->jsParserEngine.pool(),
+ runtimeFunctionIndices);
return true;
}
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 9342e0f178..93e550a530 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -595,9 +595,7 @@ struct Q_QMLCOMPILER_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen
// Returns mapping from input functions to index in IR::Module::functions / compiledData->runtimeFunctions
QVector<int> generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions);
- bool generateCodeForComponents(const QVector<quint32> &componentRoots);
- bool compileComponent(int contextObject);
- bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
+ bool generateRuntimeFunctions(QmlIR::Object *object);
private:
Document *document;
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index 6760f87dc7..cc4f4a2747 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -284,7 +284,7 @@
// Initialize this using myObject where you would previously
// call qmlRegisterSingletonInstance().
- static MySingleton *s_singletonInstance = nullptr;
+ inline static MySingleton *s_singletonInstance = nullptr;
static MySingleton *create(QQmlEngine *, QJSEngine *engine)
{
@@ -308,7 +308,7 @@
}
private:
- static QJSEngine *s_engine = nullptr;
+ inline static QJSEngine *s_engine = nullptr;
};
\endcode
diff --git a/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc b/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
index be1908f7cd..4d7ea272ce 100644
--- a/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
+++ b/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
@@ -443,7 +443,7 @@ documentation on this, no further action is needed. qmltyperegistrar will
automatically generate the \c .qmltypes files.
Example:
-If your module is in \c /tmp/imports/My/Module, a file caled \c plugins.qmltypes
+If your module is in \c /tmp/imports/My/Module, a file called \c plugins.qmltypes
should be generated alongside the actual plugin binary.
Add the line
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 03cd1e9aa9..832eaca8da 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -142,6 +142,16 @@
integers.append(jsArray.property(i).toInt());
}
\endcode
+
+ \section2 Converting to JSON
+
+ It's possible to convert a QJSValue to a JSON type. For example,
+ to convert to an array, use \l QJSEngine::fromScriptValue():
+
+ \code
+ const QJsonValue jsonValue = engine.fromScriptValue<QJsonValue>(jsValue);
+ const QJsonArray jsonArray = jsonValue.toArray();
+ \endcode
*/
/*!
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 8eb7d8982d..f47ce4f825 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -2005,6 +2005,25 @@ int ExecutionEngine::maxGCStackSize() const
return m_maxGCStackSize;
}
+/*!
+ \internal
+ Returns \a length converted to int if its safe to
+ pass to \c Scope::alloc.
+ Otherwise it throws a RangeError, and returns 0.
+ */
+int ExecutionEngine::safeForAllocLength(qint64 len64)
+{
+ if (len64 < 0ll || len64 > qint64(std::numeric_limits<int>::max())) {
+ this->throwRangeError(QStringLiteral("Invalid array length."));
+ return 0;
+ }
+ if (len64 > qint64(this->jsStackLimit - this->jsStackTop)) {
+ this->throwRangeError(QStringLiteral("Array too large for apply()."));
+ return 0;
+ }
+ return len64;
+}
+
ReturnedValue ExecutionEngine::global()
{
return globalObject->asReturnedValue();
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index db6bfcc84b..0d3b279377 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -694,6 +694,7 @@ public:
int maxGCStackSize() const;
bool checkStackLimits();
+ int safeForAllocLength(qint64 len64);
bool canJIT(Function *f = nullptr)
{
@@ -778,6 +779,9 @@ public:
int argc, void **args, QMetaType *types);
private:
+ template<int Frames>
+ friend struct ExecutionEngineCallDepthRecorder;
+
QV4::ReturnedValue fromData(
const QMetaType &type, const void *ptr, const QVariant *variant = nullptr);
@@ -813,12 +817,15 @@ private:
#define CHECK_STACK_LIMITS(v4) if ((v4)->checkStackLimits()) return Encode::undefined(); \
ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4);
+template<int Frames = 1>
struct ExecutionEngineCallDepthRecorder
{
ExecutionEngine *ee;
- ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ++ee->callDepth; }
- ~ExecutionEngineCallDepthRecorder() { --ee->callDepth; }
+ ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ee->callDepth += Frames; }
+ ~ExecutionEngineCallDepthRecorder() { ee->callDepth -= Frames; }
+
+ bool hasOverflow() const { return ee->callDepth >= ExecutionEngine::maxCallDepth; }
};
inline bool ExecutionEngine::checkStackLimits()
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index d3bafbe055..798cfc131d 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -387,15 +387,10 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons
if (!arr)
return v4->throwTypeError();
- const qint64 len64 = arr->getLength();
- if (len64 < 0ll || len64 > qint64(std::numeric_limits<int>::max()))
- return v4->throwRangeError(QStringLiteral("Invalid array length."));
- if (len64 > qint64(v4->jsStackLimit - v4->jsStackTop))
- return v4->throwRangeError(QStringLiteral("Array too large for apply()."));
-
- const uint len = uint(len64);
-
Scope scope(v4);
+ const uint len = v4->safeForAllocLength(arr->getLength());
+ CHECK_EXCEPTION();
+
Value *arguments = scope.alloc<Scope::Uninitialized>(len);
if (len) {
if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast<ArgumentsObject>()->fullyCreated()) {
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 994d9a79a0..ad9760bfd6 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -665,7 +665,7 @@ public:
bool foundProblem() const { return m_callDepthRecorder.ee->hasException; }
private:
- ExecutionEngineCallDepthRecorder m_callDepthRecorder;
+ ExecutionEngineCallDepthRecorder<1> m_callDepthRecorder;
};
static QString quote(const QString &str)
diff --git a/src/qml/jsruntime/qv4reflect.cpp b/src/qml/jsruntime/qv4reflect.cpp
index 2a6c61f044..39a0b03dec 100644
--- a/src/qml/jsruntime/qv4reflect.cpp
+++ b/src/qml/jsruntime/qv4reflect.cpp
@@ -76,7 +76,10 @@ struct CallArgs {
static CallArgs createListFromArrayLike(Scope &scope, const Object *o)
{
- int len = o->getLength();
+ int len = scope.engine->safeForAllocLength(o->getLength());
+ if (scope.engine->hasException)
+ return {nullptr, 0};
+
Value *arguments = scope.alloc(len);
for (int i = 0; i < len; ++i) {
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 064eddc76a..80f8c88973 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1422,10 +1422,18 @@ void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV
break;
}
}
- if (engine->hasException || !object) {
+ if (engine->hasException) {
qmlWarning(createdComponent, engine->catchExceptionAsQmlError());
continue;
}
+ if (!object) {
+ QQmlError error;
+ error.setUrl(qmlContext ? qmlContext->qmlContext()->url() : QUrl());
+ error.setDescription(QLatin1String("Cannot resolve property \"%1\".")
+ .arg(properties.join(u'.')));
+ qmlWarning(createdComponent, error);
+ continue;
+ }
name = engine->newString(properties.last());
object->put(name, val);
if (engine->hasException) {
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index 7d4ffcec3f..59f4bf296e 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -269,6 +269,7 @@ void QQmlIncubatorPrivate::forceCompletion(QQmlInstantiationInterrupt &i)
}
}
+
void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
{
if (!compilationUnit)
@@ -280,6 +281,20 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
// get a copy of the engine pointer as it might get reset;
QQmlEnginePrivate *enginePriv = this->enginePriv;
+ // Incubating objects takes quite a bit more stack space than our usual V4 function
+ enum { EstimatedSizeInV4Frames = 2 };
+ QV4::ExecutionEngineCallDepthRecorder<EstimatedSizeInV4Frames> callDepthRecorder(
+ compilationUnit->engine);
+ if (callDepthRecorder.hasOverflow()) {
+ QQmlError error;
+ error.setMessageType(QtCriticalMsg);
+ error.setUrl(compilationUnit->url());
+ error.setDescription(QQmlComponent::tr("Maximum call stack size exceeded."));
+ errors << error;
+ progress = QQmlIncubatorPrivate::Completed;
+ goto finishIncubate;
+ }
+
if (!vmeGuard.isOK()) {
QQmlError error;
error.setMessageType(QtInfoMsg);
diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp
index 5c88761d78..f6bedc94e9 100644
--- a/src/qml/qml/qqmlpropertycachecreator.cpp
+++ b/src/qml/qml/qqmlpropertycachecreator.cpp
@@ -115,8 +115,10 @@ bool QQmlBindingInstantiationContext::resolveInstantiatingProperty()
return true;
}
+ if (!referencingObjectPropertyCache)
+ return false;
+
Q_ASSERT(referencingObjectIndex >= 0);
- Q_ASSERT(referencingObjectPropertyCache);
Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);
bool notInRevision = false;
diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h
index f4845ec27b..c415b5f33a 100644
--- a/src/qml/qml/qqmlpropertycachecreator_p.h
+++ b/src/qml/qml/qqmlpropertycachecreator_p.h
@@ -703,8 +703,15 @@ inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter
QQmlType::AnyRegistrationType, &selfReference))
return QMetaType();
- if (!qmltype.isComposite())
- return qmltype.typeId();
+ if (!qmltype.isComposite()) {
+ const QMetaType typeId = qmltype.typeId();
+ if (!typeId.isValid() && qmltype.isInlineComponentType()) {
+ const int objectId = qmltype.inlineComponentId();
+ return objectContainer->typeIdsForComponent(objectId).id;
+ } else {
+ return typeId;
+ }
+ }
if (selfReference)
return objectContainer->typeIdsForComponent().id;
diff --git a/src/qml/qml/qqmlpropertydata_p.h b/src/qml/qml/qqmlpropertydata_p.h
index edf777ff18..1fbf24a1a7 100644
--- a/src/qml/qml/qqmlpropertydata_p.h
+++ b/src/qml/qml/qqmlpropertydata_p.h
@@ -281,7 +281,6 @@ public:
{
Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
- Q_ASSERT(idx != m_coreIndex);
m_overrideIndex = qint16(idx);
}
diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp
index ca1ed72a7f..d72fdb4d5c 100644
--- a/src/qml/qml/qqmltypecompiler.cpp
+++ b/src/qml/qml/qqmltypecompiler.cpp
@@ -151,11 +151,13 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
document->jsModule.fileName = typeData->urlString();
document->jsModule.finalUrl = typeData->finalUrlString();
QmlIR::JSCodeGen v4CodeGenerator(document, engine->v4engine()->illegalNames());
- if (!v4CodeGenerator.generateCodeForComponents(componentRoots())) {
- recordError(v4CodeGenerator.error());
- return nullptr;
+ for (QmlIR::Object *object : qAsConst(document->objects)) {
+ if (!v4CodeGenerator.generateRuntimeFunctions(object)) {
+ Q_ASSERT(v4CodeGenerator.hasError());
+ recordError(v4CodeGenerator.error());
+ return nullptr;
+ }
}
-
document->javaScriptCompilationUnit = v4CodeGenerator.generateCompilationUnit(/*generated unit data*/false);
}
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index cbf28c6f2b..b6f68536ca 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -240,13 +240,14 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
if (!target)
return;
- QQmlData *targetDData = QQmlData::get(target, /*create*/false);
- if (!targetDData)
- return;
QQmlPropertyIndex encodedIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex);
int coreIndex = encodedIndex.coreIndex();
int valueTypeIndex = encodedIndex.valueTypeIndex();
- const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
+ QJSEngine *engine = qjsEngine(target);
+ if (!engine)
+ return; // dont crash
+ const QQmlPropertyData *pd =
+ QQmlData::ensurePropertyCache(engine, target)->property(coreIndex);
if (pd && valueTypeIndex != -1 && !QQmlMetaType::valueType(pd->propType())) {
// deep alias
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(metaObject->compilationUnit->engine->qmlEngine());