diff options
author | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2023-10-03 14:55:01 +0300 |
---|---|---|
committer | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2023-10-03 14:55:01 +0300 |
commit | eca36baf3d8c6c52509f487f75dc7c46bd63e73c (patch) | |
tree | 408acf2cc6d3227a82e2f2765bc6ad71e3bff5c7 /src/qml | |
parent | 4a6dfcd838a62ed7b3500326af6099c00a5cbf49 (diff) | |
parent | b65d9135ebd43d5bf3cc882a94230a305893fd6a (diff) |
Merge remote-tracking branch 'origin/tqtc/lts-6.2.7' into tqtc/lts-6.2-opensource
Change-Id: Ib72ded968b7ac6b75b499392162e3cf3b761ec48
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/Qt6QmlMacros.cmake | 10 | ||||
-rw-r--r-- | src/qml/common/qv4compileddata_p.h | 6 | ||||
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 62 | ||||
-rw-r--r-- | src/qml/compiler/qqmlirbuilder_p.h | 4 | ||||
-rw-r--r-- | src/qml/doc/src/qmlfunctions.qdoc | 4 | ||||
-rw-r--r-- | src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc | 2 | ||||
-rw-r--r-- | src/qml/jsapi/qjsvalue.cpp | 10 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 19 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 11 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 11 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4jsonobject.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4reflect.cpp | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponent.cpp | 10 | ||||
-rw-r--r-- | src/qml/qml/qqmlincubator.cpp | 15 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycachecreator.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycachecreator_p.h | 11 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertydata_p.h | 1 | ||||
-rw-r--r-- | src/qml/qml/qqmltypecompiler.cpp | 10 | ||||
-rw-r--r-- | src/qml/qml/qqmlvmemetaobject.cpp | 9 |
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()); |