aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqml.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqml.cpp')
-rw-r--r--src/qml/qml/qqml.cpp2219
1 files changed, 1975 insertions, 244 deletions
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index cb55c0d834..eb716671b1 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -1,78 +1,75 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 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
#include "qqml.h"
#include <QtQml/qqmlprivate.h>
#include <private/qjsvalue_p.h>
+#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmlcomponent_p.h>
#include <private/qqmlengine_p.h>
+#include <private/qqmlfinalizer_p.h>
+#include <private/qqmlloggingcategory_p.h>
#include <private/qqmlmetatype_p.h>
#include <private/qqmlmetatypedata_p.h>
#include <private/qqmltype_p_p.h>
#include <private/qqmltypemodule_p.h>
-#include <private/qqmltypenotavailable_p.h>
-#include <private/qqmlcomponent_p.h>
+#include <private/qqmltypewrapper_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qv4dateobject_p.h>
+#include <private/qv4errorobject_p.h>
+#include <private/qv4identifiertable_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4qobjectwrapper_p.h>
#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQml);
+Q_DECLARE_LOGGING_CATEGORY(lcJs);
/*!
\internal
+
+ This method completes the setup of all deferred properties of \a object.
+ Deferred properties are declared with
+ Q_CLASSINFO("DeferredPropertyNames", "comma,separated,property,list");
+
+ Any binding to a deferred property is not executed when the object is instantiated,
+ but only when completion is requested with qmlExecuteDeferred, or by manually
+ calling QQmlComponentPrivate::beginDeferred and completeDeferred.
+
+ \sa QV4::CompiledData::Binding::IsDeferredBinding,
+ QV4::CompiledData::Object::HasDeferredBindings,
+ QQmlData::deferData,
+ QQmlObjectCreator::setupBindings
*/
void qmlExecuteDeferred(QObject *object)
{
QQmlData *data = QQmlData::get(object);
- if (data && !data->deferredData.isEmpty() && !data->wasDeleted(object)) {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine());
+ if (!data
+ || !data->context
+ || !data->context->engine()
+ || data->deferredData.isEmpty()
+ || data->wasDeleted(object)) {
+ return;
+ }
- QQmlComponentPrivate::DeferredState state;
- QQmlComponentPrivate::beginDeferred(ep, object, &state);
+ if (!data->propertyCache)
+ data->propertyCache = QQmlMetaType::propertyCache(object->metaObject());
- // Release the reference for the deferral action (we still have one from construction)
- data->releaseDeferredData();
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine());
- QQmlComponentPrivate::completeDeferred(ep, &state);
- }
+ QQmlComponentPrivate::DeferredState state;
+ QQmlComponentPrivate::beginDeferred(ep, object, &state);
+
+ // Release the reference for the deferral action (we still have one from construction)
+ data->releaseDeferredData();
+
+ QQmlComponentPrivate::completeDeferred(ep, &state);
}
QQmlContext *qmlContext(const QObject *obj)
@@ -82,7 +79,7 @@ QQmlContext *qmlContext(const QObject *obj)
QQmlEngine *qmlEngine(const QObject *obj)
{
- QQmlData *data = QQmlData::get(obj, false);
+ QQmlData *data = QQmlData::get(obj);
if (!data || !data->context)
return nullptr;
return data->context->engine();
@@ -129,13 +126,79 @@ QObject *qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc
return resolveAttachedProperties(func, data, object, create);
}
+QObject *qmlExtendedObject(QObject *object)
+{
+ return QQmlPrivate::qmlExtendedObject(object, 0);
+}
+
+QObject *QQmlPrivate::qmlExtendedObject(QObject *object, int index)
+{
+ if (!object)
+ return nullptr;
+
+ void *result = nullptr;
+ QObjectPrivate *d = QObjectPrivate::get(object);
+ if (!d->metaObject)
+ return nullptr;
+
+ const int id = d->metaObject->metaCall(
+ object, QMetaObject::CustomCall,
+ QQmlProxyMetaObject::extensionObjectId(index), &result);
+ if (id != QQmlProxyMetaObject::extensionObjectId(index))
+ return nullptr;
+
+ return static_cast<QObject *>(result);
+}
+
+void QQmlPrivate::qmlRegistrationWarning(
+ QQmlPrivate::QmlRegistrationWarning warning, QMetaType metaType)
+{
+ switch (warning) {
+ case UnconstructibleType:
+ qWarning().nospace()
+ << metaType.name()
+ << " is neither a default constructible QObject, nor a default- "
+ << "and copy-constructible Q_GADGET, nor marked as uncreatable.\n"
+ << "You should not use it as a QML type.";
+ break;
+ case UnconstructibleSingleton:
+ qWarning()
+ << "Singleton" << metaType.name()
+ << "needs to be a concrete class with either a default constructor"
+ << "or, when adding a default constructor is infeasible, a public static"
+ << "create(QQmlEngine *, QJSEngine *) method.";
+ break;
+ case NonQObjectWithAtached:
+ qWarning()
+ << metaType.name()
+ << "is not a QObject, but has attached properties. This won't work.";
+ break;
+ }
+}
+
+QMetaType QQmlPrivate::compositeMetaType(
+ QV4::ExecutableCompilationUnit *unit, const QString &elementName)
+{
+ return QQmlTypePrivate::compositeQmlType(
+ unit->baseCompilationUnit(), unit->engine->typeLoader(), elementName)
+ .typeId();
+}
+
+QMetaType QQmlPrivate::compositeListMetaType(
+ QV4::ExecutableCompilationUnit *unit, const QString &elementName)
+{
+ return QQmlTypePrivate::compositeQmlType(
+ unit->baseCompilationUnit(), unit->engine->typeLoader(), elementName)
+ .qListTypeId();
+}
+
int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
const char *uri, int versionMajor,
int versionMinor, const char *qmlName,
const QString& reason)
{
QQmlPrivate::RegisterType type = {
- 0,
+ QQmlPrivate::RegisterType::CurrentVersion,
QMetaType(),
QMetaType(),
0,
@@ -149,14 +212,16 @@ int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
QQmlAttachedPropertiesFunc(),
nullptr,
- 0,
- 0,
- 0,
+ -1,
+ -1,
+ -1,
nullptr, nullptr,
nullptr,
- QTypeRevision::zero()
+ QTypeRevision::zero(),
+ -1,
+ QQmlPrivate::ValueTypeCreationMethod::None
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -202,6 +267,7 @@ static QTypeRevision resolveModuleVersion(int moduleMajor)
/*!
* \enum QQmlModuleImportSpecialVersions
+ * \relates QQmlEngine
*
* Defines some special values that can be passed to the version arguments of
* qmlRegisterModuleImport() and qmlUnregisterModuleImport().
@@ -220,25 +286,26 @@ static QTypeRevision resolveModuleVersion(int moduleMajor)
*/
/*!
- * Registers an implicit import for module \a uri of major version \a majorVersion.
+ * \relates QQmlEngine
+ * Registers a qmldir-import for module \a uri of major version \a moduleMajor.
*
* This has the same effect as an \c import statement in a qmldir file: Whenever
* \a uri of version \a moduleMajor is imported, \a import of version
* \a importMajor. \a importMinor is automatically imported, too. If
- * \a importMajor is \l QmlModuleImportLatest the latest version
+ * \a importMajor is \l QQmlModuleImportLatest the latest version
* available of that module is imported, and \a importMinor does not matter. If
- * \a importMinor is \l QmlModuleImportLatest the latest minor version of a
- * \a importMajor is chosen. If \a importMajor is \l QmlModuleImportAuto the
+ * \a importMinor is \l QQmlModuleImportLatest the latest minor version of a
+ * \a importMajor is chosen. If \a importMajor is \l QQmlModuleImportAuto the
* version of \a import is version of \a uri being imported, and \a importMinor
- * does not matter. If \a moduleMajor is \a QmlModuleImportModuleAny the module
+ * does not matter. If \a moduleMajor is \l QQmlModuleImportModuleAny the module
* import is applied for any major version of \a uri. For example, you may
* specify that whenever any version of MyModule is imported, the latest version
* of MyOtherModule should be imported. Then, the following call would be
* appropriate:
*
* \code
- * qmlRegisterModuleImport("MyModule", QmlModuleImportModuleAny,
- * "MyOtherModule", QmlModuleImportLatest);
+ * qmlRegisterModuleImport("MyModule", QQmlModuleImportModuleAny,
+ * "MyOtherModule", QQmlModuleImportLatest);
* \endcode
*
* Or, you may specify that whenever major version 5 of "MyModule" is imported,
@@ -252,8 +319,8 @@ static QTypeRevision resolveModuleVersion(int moduleMajor)
* imported whenever "MyModule" is imported, specify the following:
*
* \code
- * qmlRegisterModuleImport("MyModule", QmlModuleImportModuleAny,
- * "MyOtherModule", QmlModuleImportAuto);
+ * qmlRegisterModuleImport("MyModule", QQmlModuleImportModuleAny,
+ * "MyOtherModule", QQmlModuleImportAuto);
* \endcode
*
* \sa qmlUnregisterModuleImport()
@@ -268,6 +335,7 @@ void qmlRegisterModuleImport(const char *uri, int moduleMajor,
/*!
+ * \relates QQmlEngine
* Removes a module import previously registered with qmlRegisterModuleImport()
*
* Calling this function makes sure that \a import of version
@@ -291,30 +359,63 @@ int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *q
return QQmlMetaType::typeId(uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName);
}
+static bool checkSingletonInstance(QQmlEngine *engine, QObject *instance)
+{
+ if (!instance) {
+ QQmlError error;
+ error.setDescription(QStringLiteral("The registered singleton has already been deleted. "
+ "Ensure that it outlives the engine."));
+ QQmlEnginePrivate::get(engine)->warning(engine, error);
+ return false;
+ }
+
+ if (engine->thread() != instance->thread()) {
+ QQmlError error;
+ error.setDescription(QStringLiteral("Registered object must live in the same thread "
+ "as the engine it was registered with"));
+ QQmlEnginePrivate::get(engine)->warning(engine, error);
+ return false;
+ }
+
+ return true;
+}
+
// From qqmlprivate.h
+#if QT_DEPRECATED_SINCE(6, 3)
QObject *QQmlPrivate::SingletonFunctor::operator()(QQmlEngine *qeng, QJSEngine *)
{
- if (!m_object) {
- QQmlError error;
- error.setDescription(QLatin1String("The registered singleton has already been deleted. Ensure that it outlives the engine."));
- QQmlEnginePrivate::get(qeng)->warning(qeng, error);
+ if (!checkSingletonInstance(qeng, m_object))
return nullptr;
- }
- if (qeng->thread() != m_object->thread()) {
+ if (alreadyCalled) {
QQmlError error;
- error.setDescription(QLatin1String("Registered object must live in the same thread as the engine it was registered with"));
+ error.setDescription(QStringLiteral("Singleton registered by registerSingletonInstance "
+ "must only be accessed from one engine"));
QQmlEnginePrivate::get(qeng)->warning(qeng, error);
return nullptr;
}
- if (alreadyCalled) {
+
+ alreadyCalled = true;
+ QJSEngine::setObjectOwnership(m_object, QQmlEngine::CppOwnership);
+ return m_object;
+};
+#endif
+
+QObject *QQmlPrivate::SingletonInstanceFunctor::operator()(QQmlEngine *qeng, QJSEngine *)
+{
+ if (!checkSingletonInstance(qeng, m_object))
+ return nullptr;
+
+ if (!m_engine) {
+ m_engine = qeng;
+ QJSEngine::setObjectOwnership(m_object, QQmlEngine::CppOwnership);
+ } else if (m_engine != qeng) {
QQmlError error;
error.setDescription(QLatin1String("Singleton registered by registerSingletonInstance must only be accessed from one engine"));
QQmlEnginePrivate::get(qeng)->warning(qeng, error);
return nullptr;
}
- alreadyCalled = true;
- qeng->setObjectOwnership(m_object, QQmlEngine::CppOwnership);
+
return m_object;
};
@@ -325,9 +426,9 @@ static QVector<QTypeRevision> availableRevisions(const QMetaObject *metaObject)
return revisions;
const int propertyOffset = metaObject->propertyOffset();
const int propertyCount = metaObject->propertyCount();
- for (int propertyIndex = propertyOffset, propertyEnd = propertyOffset + propertyCount;
- propertyIndex < propertyEnd; ++propertyIndex) {
- const QMetaProperty property = metaObject->property(propertyIndex);
+ for (int coreIndex = propertyOffset, propertyEnd = propertyOffset + propertyCount;
+ coreIndex < propertyEnd; ++coreIndex) {
+ const QMetaProperty property = metaObject->property(coreIndex);
if (int revision = property.revision())
revisions.append(QTypeRevision::fromEncodedVersion(revision));
}
@@ -395,13 +496,280 @@ static void uniqueRevisions(QVector<QTypeRevision> *revisions, QTypeRevision def
revisions->erase(it, revisions->end());
}
+static QQmlType::SingletonInstanceInfo::ConstPtr singletonInstanceInfo(
+ const QQmlPrivate::RegisterSingletonType &type)
+{
+ QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create();
+ siinfo->scriptCallback = type.scriptApi;
+ siinfo->qobjectCallback = type.qObjectApi;
+ siinfo->typeName = type.typeName;
+ return QQmlType::SingletonInstanceInfo::ConstPtr(
+ siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt);
+}
+
+static QQmlType::SingletonInstanceInfo::ConstPtr singletonInstanceInfo(
+ const QQmlPrivate::RegisterCompositeSingletonType &type)
+{
+ QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create();
+ siinfo->url = QQmlTypeLoader::normalize(type.url);
+ siinfo->typeName = type.typeName;
+ return QQmlType::SingletonInstanceInfo::ConstPtr(
+ siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt);
+}
+
+static int finalizeType(const QQmlType &dtype)
+{
+ if (!dtype.isValid())
+ return -1;
+
+ QQmlMetaType::registerUndeletableType(dtype);
+ return dtype.index();
+}
+
+using ElementNames = QVarLengthArray<const char *, 8>;
+static ElementNames classElementNames(const QMetaObject *metaObject)
+{
+ Q_ASSERT(metaObject);
+ const char *key = "QML.Element";
+
+ const int offset = metaObject->classInfoOffset();
+ const int start = metaObject->classInfoCount() + offset - 1;
+
+ ElementNames elementNames;
+
+ for (int i = start; i >= offset; --i) {
+ const QMetaClassInfo classInfo = metaObject->classInfo(i);
+ if (qstrcmp(key, classInfo.name()) == 0) {
+ const char *elementName = classInfo.value();
+
+ if (qstrcmp(elementName, "auto") == 0) {
+ const char *strippedClassName = metaObject->className();
+ for (const char *c = strippedClassName; *c != '\0'; c++) {
+ if (*c == ':')
+ strippedClassName = c + 1;
+ }
+ elementName = strippedClassName;
+ } else if (qstrcmp(elementName, "anonymous") == 0) {
+ if (elementNames.isEmpty())
+ elementNames.push_back(nullptr);
+ else if (elementNames[0] != nullptr)
+ qWarning() << metaObject->className() << "is both anonymous and named";
+ continue;
+ }
+
+ if (!elementNames.isEmpty() && elementNames[0] == nullptr) {
+ qWarning() << metaObject->className() << "is both anonymous and named";
+ elementNames[0] = elementName;
+ } else {
+ elementNames.push_back(elementName);
+ }
+ }
+ }
+
+ return elementNames;
+}
+
+struct AliasRegistrar
+{
+ AliasRegistrar(const ElementNames *elementNames) : elementNames(elementNames) {}
+
+ void registerAliases(int typeId)
+ {
+ if (elementNames) {
+ for (int i = 1, end = elementNames->length(); i < end; ++i)
+ otherNames.append(QString::fromUtf8(elementNames->at(i)));
+ elementNames = nullptr;
+ }
+
+ for (const QString &otherName : std::as_const(otherNames))
+ QQmlMetaType::registerTypeAlias(typeId, otherName);
+ }
+
+private:
+ const ElementNames *elementNames;
+ QVarLengthArray<QString, 8> otherNames;
+};
+
+
+static void doRegisterTypeAndRevisions(
+ const QQmlPrivate::RegisterTypeAndRevisions &type,
+ const ElementNames &elementNames)
+{
+ using namespace QQmlPrivate;
+
+ const bool isValueType = !(type.typeId.flags() & QMetaType::PointerToQObject);
+ const bool creatable = (elementNames[0] != nullptr || isValueType)
+ && boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true);
+
+ QString noCreateReason;
+ ValueTypeCreationMethod creationMethod = ValueTypeCreationMethod::None;
+
+ if (!creatable) {
+ noCreateReason = QString::fromUtf8(
+ classInfo(type.classInfoMetaObject, "QML.UncreatableReason"));
+ if (noCreateReason.isEmpty())
+ noCreateReason = QLatin1String("Type cannot be created in QML.");
+ } else if (isValueType) {
+ const char *method = classInfo(type.classInfoMetaObject, "QML.CreationMethod");
+ if (qstrcmp(method, "structured") == 0)
+ creationMethod = ValueTypeCreationMethod::Structured;
+ else if (qstrcmp(method, "construct") == 0)
+ creationMethod = ValueTypeCreationMethod::Construct;
+ }
+
+ RegisterType typeRevision = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ type.typeId,
+ type.listId,
+ creatable ? type.objectSize : 0,
+ nullptr,
+ nullptr,
+ noCreateReason,
+ type.createValueType,
+ type.uri,
+ type.version,
+ nullptr,
+ type.metaObject,
+ type.attachedPropertiesFunction,
+ type.attachedPropertiesMetaObject,
+ type.parserStatusCast,
+ type.valueSourceCast,
+ type.valueInterceptorCast,
+ type.extensionObjectCreate,
+ type.extensionMetaObject,
+ nullptr,
+ QTypeRevision(),
+ type.structVersion > 0 ? type.finalizerCast : -1,
+ creationMethod
+ };
+
+ QQmlPrivate::RegisterSequentialContainer sequenceRevision = {
+ 0,
+ type.uri,
+ type.version,
+ nullptr,
+ type.listId,
+ type.structVersion > 1 ? type.listMetaSequence : QMetaSequence(),
+ QTypeRevision(),
+ };
+
+ const QTypeRevision added = revisionClassInfo(
+ type.classInfoMetaObject, "QML.AddedInVersion",
+ QTypeRevision::fromVersion(type.version.majorVersion(), 0));
+ const QTypeRevision removed = revisionClassInfo(
+ type.classInfoMetaObject, "QML.RemovedInVersion");
+ const QList<QTypeRevision> furtherRevisions = revisionClassInfos(type.classInfoMetaObject,
+ "QML.ExtraVersion");
+
+ auto revisions = prepareRevisions(type.metaObject, added) + furtherRevisions;
+ if (type.attachedPropertiesMetaObject)
+ revisions += availableRevisions(type.attachedPropertiesMetaObject);
+ uniqueRevisions(&revisions, type.version, added);
+
+ AliasRegistrar aliasRegistrar(&elementNames);
+ for (QTypeRevision revision : revisions) {
+ if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
+ break;
+
+ assignVersions(&typeRevision, revision, type.version);
+
+ // When removed or before added, we still add revisions, but anonymous ones
+ if (typeRevision.version < added
+ || (removed.isValid() && !(typeRevision.version < removed))) {
+ typeRevision.elementName = nullptr;
+ typeRevision.create = nullptr;
+ typeRevision.userdata = nullptr;
+ } else {
+ typeRevision.elementName = elementNames[0];
+ typeRevision.create = creatable ? type.create : nullptr;
+ typeRevision.userdata = type.userdata;
+ }
+
+ typeRevision.customParser = type.customParserFactory();
+ const int id = qmlregister(TypeRegistration, &typeRevision);
+ if (type.qmlTypeIds)
+ type.qmlTypeIds->append(id);
+
+ if (typeRevision.elementName)
+ aliasRegistrar.registerAliases(id);
+
+ if (sequenceRevision.metaSequence != QMetaSequence()) {
+ sequenceRevision.version = typeRevision.version;
+ sequenceRevision.revision = typeRevision.revision;
+ const int id = QQmlPrivate::qmlregister(
+ QQmlPrivate::SequentialContainerRegistration, &sequenceRevision);
+ if (type.qmlTypeIds)
+ type.qmlTypeIds->append(id);
+ }
+ }
+}
+
+static void doRegisterSingletonAndRevisions(
+ const QQmlPrivate::RegisterSingletonTypeAndRevisions &type,
+ const ElementNames &elementNames)
+{
+ using namespace QQmlPrivate;
+
+ RegisterSingletonType revisionRegistration = {
+ 0,
+ type.uri,
+ type.version,
+ elementNames[0],
+ nullptr,
+ type.qObjectApi,
+ type.instanceMetaObject,
+ type.typeId,
+ type.extensionObjectCreate,
+ type.extensionMetaObject,
+ QTypeRevision()
+ };
+ const QQmlType::SingletonInstanceInfo::ConstPtr siinfo
+ = singletonInstanceInfo(revisionRegistration);
+
+ const QTypeRevision added = revisionClassInfo(
+ type.classInfoMetaObject, "QML.AddedInVersion",
+ QTypeRevision::fromVersion(type.version.majorVersion(), 0));
+ const QTypeRevision removed = revisionClassInfo(
+ type.classInfoMetaObject, "QML.RemovedInVersion");
+ const QList<QTypeRevision> furtherRevisions = revisionClassInfos(type.classInfoMetaObject,
+ "QML.ExtraVersion");
+
+ auto revisions = prepareRevisions(type.instanceMetaObject, added) + furtherRevisions;
+ uniqueRevisions(&revisions, type.version, added);
+
+ AliasRegistrar aliasRegistrar(&elementNames);
+ for (QTypeRevision revision : std::as_const(revisions)) {
+ if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
+ break;
+
+ assignVersions(&revisionRegistration, revision, type.version);
+
+ // When removed or before added, we still add revisions, but anonymous ones
+ if (revisionRegistration.version < added
+ || (removed.isValid() && !(revisionRegistration.version < removed))) {
+ revisionRegistration.typeName = nullptr;
+ revisionRegistration.qObjectApi = nullptr;
+ } else {
+ revisionRegistration.typeName = elementNames[0];
+ revisionRegistration.qObjectApi = type.qObjectApi;
+ }
+
+ const int id = finalizeType(
+ QQmlMetaType::registerSingletonType(revisionRegistration, siinfo));
+ if (type.qmlTypeIds)
+ type.qmlTypeIds->append(id);
+
+ if (revisionRegistration.typeName)
+ aliasRegistrar.registerAliases(id);
+ }
+}
+
/*
This method is "over generalized" to allow us to (potentially) register more types of things in
the future without adding exported symbols.
*/
int QQmlPrivate::qmlregister(RegistrationType type, void *data)
{
- QQmlType dtype;
switch (type) {
case AutoParentRegistration:
return QQmlMetaType::registerAutoParentFunction(
@@ -411,135 +779,40 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
*reinterpret_cast<RegisterQmlUnitCacheHook *>(data));
case TypeAndRevisionsRegistration: {
const RegisterTypeAndRevisions &type = *reinterpret_cast<RegisterTypeAndRevisions *>(data);
- const char *elementName = classElementName(type.classInfoMetaObject);
- const bool creatable = (elementName != nullptr)
- && boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true);
-
- QString noCreateReason;
-
- if (!creatable) {
- noCreateReason = QString::fromUtf8(classInfo(type.classInfoMetaObject, "QML.UncreatableReason"));
- if (noCreateReason.isEmpty())
- noCreateReason = QLatin1String("Type cannot be created in QML.");
- }
-
- RegisterType revisionRegistration = {
- 0,
- type.typeId,
- type.listId,
- creatable ? type.objectSize : 0,
- nullptr,
- nullptr,
- noCreateReason,
- type.createValueType,
- type.uri,
- type.version,
- nullptr,
- type.metaObject,
- type.attachedPropertiesFunction,
- type.attachedPropertiesMetaObject,
- type.parserStatusCast,
- type.valueSourceCast,
- type.valueInterceptorCast,
- type.extensionObjectCreate,
- type.extensionMetaObject,
- nullptr,
- QTypeRevision()
- };
-
- const QTypeRevision added = revisionClassInfo(
- type.classInfoMetaObject, "QML.AddedInVersion",
- QTypeRevision::fromMinorVersion(0));
- const QTypeRevision removed = revisionClassInfo(
- type.classInfoMetaObject, "QML.RemovedInVersion");
-
- auto revisions = prepareRevisions(type.metaObject, added);
- if (type.attachedPropertiesMetaObject)
- revisions += availableRevisions(type.attachedPropertiesMetaObject);
- uniqueRevisions(&revisions, type.version, added);
-
- for (QTypeRevision revision : revisions) {
- if (revision < added)
- continue;
- if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
- break;
-
- // When removed, we still add revisions, but anonymous ones
- if (removed.isValid() && !(revision < removed)) {
- revisionRegistration.elementName = nullptr;
- revisionRegistration.create = nullptr;
+ if (type.structVersion > 1 && type.forceAnonymous) {
+ doRegisterTypeAndRevisions(type, {nullptr});
+ } else {
+ const ElementNames names = classElementNames(type.classInfoMetaObject);
+ if (names.isEmpty()) {
+ qWarning().nospace() << "Missing QML.Element class info for "
+ << type.classInfoMetaObject->className();
} else {
- revisionRegistration.elementName = elementName;
- revisionRegistration.create = creatable ? type.create : nullptr;
- revisionRegistration.userdata = type.userdata;
+ doRegisterTypeAndRevisions(type, names);
}
- assignVersions(&revisionRegistration, revision, type.version);
- revisionRegistration.customParser = type.customParserFactory();
- const int id = qmlregister(TypeRegistration, &revisionRegistration);
- if (type.qmlTypeIds)
- type.qmlTypeIds->append(id);
}
break;
}
case SingletonAndRevisionsRegistration: {
const RegisterSingletonTypeAndRevisions &type
= *reinterpret_cast<RegisterSingletonTypeAndRevisions *>(data);
- const char *elementName = classElementName(type.classInfoMetaObject);
- RegisterSingletonType revisionRegistration = {
- 0,
- type.uri,
- type.version,
- elementName,
- nullptr,
- type.qObjectApi,
- type.instanceMetaObject,
- type.typeId,
- type.extensionObjectCreate,
- type.extensionMetaObject,
- QTypeRevision()
- };
-
- const QTypeRevision added = revisionClassInfo(
- type.classInfoMetaObject, "QML.AddedInVersion",
- QTypeRevision::fromMinorVersion(0));
- const QTypeRevision removed = revisionClassInfo(
- type.classInfoMetaObject, "QML.RemovedInVersion");
-
- auto revisions = prepareRevisions(type.instanceMetaObject, added);
- uniqueRevisions(&revisions, type.version, added);
-
- for (QTypeRevision revision : qAsConst(revisions)) {
- if (revision < added)
- continue;
- if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
- break;
-
- // When removed, we still add revisions, but anonymous ones
- if (removed.isValid() && !(revision < removed)) {
- revisionRegistration.typeName = nullptr;
- revisionRegistration.qObjectApi = nullptr;
- } else {
- revisionRegistration.typeName = elementName;
- revisionRegistration.qObjectApi = type.qObjectApi;
- }
-
- assignVersions(&revisionRegistration, revision, type.version);
- const int id = qmlregister(SingletonRegistration, &revisionRegistration);
- if (type.qmlTypeIds)
- type.qmlTypeIds->append(id);
+ const ElementNames names = classElementNames(type.classInfoMetaObject);
+ if (names.isEmpty()) {
+ qWarning().nospace() << "Missing QML.Element class info for "
+ << type.classInfoMetaObject->className();
+ } else {
+ doRegisterSingletonAndRevisions(type, names);
}
break;
}
case SequentialContainerAndRevisionsRegistration: {
const RegisterSequentialContainerAndRevisions &type
= *reinterpret_cast<RegisterSequentialContainerAndRevisions *>(data);
- const char *elementName = classElementName(type.classInfoMetaObject);
RegisterSequentialContainer revisionRegistration = {
0,
type.uri,
type.version,
- elementName,
+ nullptr,
type.typeId,
type.metaSequence,
QTypeRevision()
@@ -548,24 +821,17 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
const QTypeRevision added = revisionClassInfo(
type.classInfoMetaObject, "QML.AddedInVersion",
QTypeRevision::fromMinorVersion(0));
- const QTypeRevision removed = revisionClassInfo(
- type.classInfoMetaObject, "QML.RemovedInVersion");
-
- QVector<QTypeRevision> revisions = { added };
+ QList<QTypeRevision> revisions = revisionClassInfos(
+ type.classInfoMetaObject, "QML.ExtraVersion");
+ revisions.append(added);
uniqueRevisions(&revisions, type.version, added);
- for (QTypeRevision revision : qAsConst(revisions)) {
+ for (QTypeRevision revision : std::as_const(revisions)) {
if (revision < added)
continue;
if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
break;
- // When removed, we still add revisions, but anonymous ones
- if (removed.isValid() && !(revision < removed))
- revisionRegistration.typeName = nullptr;
- else
- revisionRegistration.typeName = elementName;
-
assignVersions(&revisionRegistration, revision, type.version);
const int id = qmlregister(SequentialContainerRegistration, &revisionRegistration);
if (type.qmlTypeIds)
@@ -574,32 +840,30 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
break;
}
case TypeRegistration:
- dtype = QQmlMetaType::registerType(*reinterpret_cast<RegisterType *>(data));
- break;
+ return finalizeType(
+ QQmlMetaType::registerType(*reinterpret_cast<RegisterType *>(data)));
case InterfaceRegistration:
- dtype = QQmlMetaType::registerInterface(*reinterpret_cast<RegisterInterface *>(data));
- break;
+ return finalizeType(
+ QQmlMetaType::registerInterface(*reinterpret_cast<RegisterInterface *>(data)));
case SingletonRegistration:
- dtype = QQmlMetaType::registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data));
- break;
+ return finalizeType(QQmlMetaType::registerSingletonType(
+ *reinterpret_cast<RegisterSingletonType *>(data),
+ singletonInstanceInfo(*reinterpret_cast<RegisterSingletonType *>(data))));
case CompositeRegistration:
- dtype = QQmlMetaType::registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data));
- break;
+ return finalizeType(QQmlMetaType::registerCompositeType(
+ *reinterpret_cast<RegisterCompositeType *>(data)));
case CompositeSingletonRegistration:
- dtype = QQmlMetaType::registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data));
- break;
+ return finalizeType(QQmlMetaType::registerCompositeSingletonType(
+ *reinterpret_cast<RegisterCompositeSingletonType *>(data),
+ singletonInstanceInfo(*reinterpret_cast<RegisterCompositeSingletonType *>(data))));
case SequentialContainerRegistration:
- dtype = QQmlMetaType::registerSequentialContainer(*reinterpret_cast<RegisterSequentialContainer *>(data));
- break;
+ return finalizeType(QQmlMetaType::registerSequentialContainer(
+ *reinterpret_cast<RegisterSequentialContainer *>(data)));
default:
return -1;
}
- if (!dtype.isValid())
- return -1;
-
- QQmlMetaType::registerUndeletableType(dtype);
- return dtype.index();
+ return -1;
}
void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
@@ -634,53 +898,1520 @@ void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
}
}
+QList<QTypeRevision> QQmlPrivate::revisionClassInfos(const QMetaObject *metaObject,
+ const char *key)
+{
+ QList<QTypeRevision> revisions;
+ for (int index = indexOfOwnClassInfo(metaObject, key); index != -1;
+ index = indexOfOwnClassInfo(metaObject, key, index - 1)) {
+ revisions.push_back(QTypeRevision::fromEncodedVersion(
+ QLatin1StringView(metaObject->classInfo(index).value()).toInt()));
+ }
+ return revisions;
+}
+
+int qmlRegisterTypeNotAvailable(
+ const char *uri, int versionMajor, int versionMinor,
+ const char *qmlName, const QString &message)
+{
+ return qmlRegisterUncreatableType<QQmlTypeNotAvailable>(
+ uri, versionMajor, versionMinor, qmlName, message);
+}
+
namespace QQmlPrivate {
- template<>
- void qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>(
- const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject,
- QVector<int> *qmlTypeIds, const QMetaObject *extension)
- {
- using T = QQmlTypeNotAvailable;
+template<>
+void qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>(
+ const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject,
+ QVector<int> *qmlTypeIds, const QMetaObject *extension, bool)
+{
+ using T = QQmlTypeNotAvailable;
- RegisterTypeAndRevisions type = {
- 0,
- QMetaType::fromType<T *>(),
- QMetaType::fromType<QQmlListProperty<T>>(),
- 0,
- nullptr,
- nullptr,
- nullptr,
+ RegisterTypeAndRevisions type = {
+ 3,
+ QmlMetaType<T>::self(),
+ QmlMetaType<T>::list(),
+ 0,
+ nullptr,
+ nullptr,
+ nullptr,
- uri,
- QTypeRevision::fromMajorVersion(versionMajor),
+ uri,
+ QTypeRevision::fromMajorVersion(versionMajor),
- &QQmlTypeNotAvailable::staticMetaObject,
- classInfoMetaObject,
+ &QQmlTypeNotAvailable::staticMetaObject,
+ classInfoMetaObject,
- attachedPropertiesFunc<T>(),
- attachedPropertiesMetaObject<T>(),
+ attachedPropertiesFunc<T>(),
+ attachedPropertiesMetaObject<T>(),
- StaticCastSelector<T, QQmlParserStatus>::cast(),
- StaticCastSelector<T, QQmlPropertyValueSource>::cast(),
- StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
+ StaticCastSelector<T, QQmlParserStatus>::cast(),
+ StaticCastSelector<T, QQmlPropertyValueSource>::cast(),
+ StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
- nullptr, extension, qmlCreateCustomParser<T>, qmlTypeIds
- };
+ nullptr,
+ extension,
+ qmlCreateCustomParser<T>,
+ qmlTypeIds,
+ QQmlPrivate::StaticCastSelector<T, QQmlFinalizerHook>::cast(),
+ false,
+ QmlMetaType<T>::sequence(),
+ };
- qmlregister(TypeAndRevisionsRegistration, &type);
- }
+ qmlregister(TypeAndRevisionsRegistration, &type);
+}
+
+QObject *AOTCompiledContext::thisObject() const
+{
+ return static_cast<QV4::MetaTypesStackFrame *>(engine->handle()->currentStackFrame)
+ ->thisObject();
}
-QJSValue QQmlPrivate::AOTCompiledContext::jsMetaType(int index) const
+QQmlEngine *AOTCompiledContext::qmlEngine() const
+{
+ return engine->handle()->qmlEngine();
+}
+
+static QQmlPropertyCapture *propertyCapture(const AOTCompiledContext *aotContext)
+{
+ QQmlEngine *engine = aotContext->qmlEngine();
+ return engine ? QQmlEnginePrivate::get(aotContext->qmlEngine())->propertyCapture : nullptr;
+}
+
+QJSValue AOTCompiledContext::jsMetaType(int index) const
{
return QJSValuePrivate::fromReturnedValue(
compilationUnit->runtimeClasses[index]->asReturnedValue());
}
-void QQmlPrivate::AOTCompiledContext::setInstructionPointer(int offset) const
+void AOTCompiledContext::setInstructionPointer(int offset) const
{
if (auto *frame = engine->handle()->currentStackFrame)
frame->instructionPointer = offset;
}
+void AOTCompiledContext::setReturnValueUndefined() const
+{
+ if (auto *frame = engine->handle()->currentStackFrame) {
+ Q_ASSERT(frame->isMetaTypesFrame());
+ static_cast<QV4::MetaTypesStackFrame *>(frame)->setReturnValueUndefined();
+ }
+}
+
+static void captureFallbackProperty(
+ QObject *object, int coreIndex, int notifyIndex, bool isConstant,
+ const AOTCompiledContext *aotContext)
+{
+ if (isConstant)
+ return;
+
+ if (QQmlPropertyCapture *capture = propertyCapture(aotContext))
+ capture->captureProperty(object, coreIndex, notifyIndex);
+}
+
+static void captureObjectProperty(
+ QObject *object, const QQmlPropertyCache *propertyCache,
+ const QQmlPropertyData *property, const AOTCompiledContext *aotContext)
+{
+ if (property->isConstant())
+ return;
+
+ if (QQmlPropertyCapture *capture = propertyCapture(aotContext))
+ capture->captureProperty(object, propertyCache, property);
+}
+
+static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCache *ancestor)
+{
+ for (const QQmlPropertyCache *cache = descendent; cache; cache = cache->parent().data()) {
+ if (cache == ancestor)
+ return true;
+ }
+ return false;
+}
+
+enum class ObjectPropertyResult { OK, NeedsInit, Deleted };
+
+struct ObjectPropertyQmlData
+{
+ QQmlData *qmlData;
+ ObjectPropertyResult result;
+};
+
+template<bool StrictType>
+ObjectPropertyQmlData findObjectPropertyQmlData(QV4::Lookup *l, QObject *object)
+{
+ QQmlData *qmlData = QQmlData::get(object);
+ if (!qmlData)
+ return {qmlData, ObjectPropertyResult::NeedsInit};
+ if (qmlData->isQueuedForDeletion)
+ return {qmlData, ObjectPropertyResult::Deleted};
+ Q_ASSERT(!QQmlData::wasDeleted(object));
+ const QQmlPropertyCache *propertyCache = l->qobjectLookup.propertyCache;
+ if (StrictType) {
+ if (qmlData->propertyCache.data() != propertyCache)
+ return {qmlData, ObjectPropertyResult::NeedsInit};
+ } else if (!inherits(qmlData->propertyCache.data(), propertyCache)) {
+ return {qmlData, ObjectPropertyResult::NeedsInit};
+ }
+ return {qmlData, ObjectPropertyResult::OK};
+}
+
+template<bool StrictType = false>
+ObjectPropertyResult loadObjectProperty(
+ QV4::Lookup *l, QObject *object, void *target, const AOTCompiledContext *aotContext)
+{
+ const ObjectPropertyQmlData data = findObjectPropertyQmlData<StrictType>(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ const QQmlPropertyData *propertyData = l->qobjectLookup.propertyData;
+ const int coreIndex = propertyData->coreIndex();
+ if (data.qmlData->hasPendingBindingBit(coreIndex))
+ data.qmlData->flushPendingBinding(coreIndex);
+
+ captureObjectProperty(object, l->qobjectLookup.propertyCache, propertyData, aotContext);
+ propertyData->readProperty(object, target);
+ return ObjectPropertyResult::OK;
+}
+
+template<bool StrictType = false>
+ObjectPropertyResult writeBackObjectProperty(QV4::Lookup *l, QObject *object, void *source)
+{
+ const ObjectPropertyQmlData data = findObjectPropertyQmlData<StrictType>(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ l->qobjectLookup.propertyData->writeProperty(object, source, {});
+ return ObjectPropertyResult::OK;
+}
+
+struct FallbackPropertyQmlData
+{
+ QQmlData *qmlData;
+ const QMetaObject *metaObject;
+ ObjectPropertyResult result;
+};
+
+static FallbackPropertyQmlData findFallbackPropertyQmlData(QV4::Lookup *l, QObject *object)
+{
+ QQmlData *qmlData = QQmlData::get(object);
+ if (qmlData && qmlData->isQueuedForDeletion)
+ return {qmlData, nullptr, ObjectPropertyResult::Deleted};
+
+ Q_ASSERT(!QQmlData::wasDeleted(object));
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ if (!metaObject || metaObject != object->metaObject())
+ return {qmlData, nullptr, ObjectPropertyResult::NeedsInit};
+
+ return {qmlData, metaObject, ObjectPropertyResult::OK};
+}
+
+static ObjectPropertyResult loadFallbackProperty(
+ QV4::Lookup *l, QObject *object, void *target, const AOTCompiledContext *aotContext)
+{
+ const FallbackPropertyQmlData data = findFallbackPropertyQmlData(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ if (data.qmlData && data.qmlData->hasPendingBindingBit(coreIndex))
+ data.qmlData->flushPendingBinding(coreIndex);
+
+ captureFallbackProperty(object, coreIndex, l->qobjectFallbackLookup.notifyIndex,
+ l->qobjectFallbackLookup.isConstant, aotContext);
+
+ void *a[] = { target, nullptr };
+ data.metaObject->metacall(object, QMetaObject::ReadProperty, coreIndex, a);
+
+ return ObjectPropertyResult::OK;
+}
+
+static ObjectPropertyResult writeBackFallbackProperty(QV4::Lookup *l, QObject *object, void *source)
+{
+ const FallbackPropertyQmlData data = findFallbackPropertyQmlData(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ void *a[] = { source, nullptr };
+ data.metaObject->metacall(
+ object, QMetaObject::WriteProperty, l->qobjectFallbackLookup.coreIndex, a);
+
+ return ObjectPropertyResult::OK;
+}
+
+ObjectPropertyResult loadObjectAsVariant(
+ QV4::Lookup *l, QObject *object, void *target, const AOTCompiledContext *aotContext)
+{
+ QVariant *variant = static_cast<QVariant *>(target);
+ const QMetaType propType = l->qobjectLookup.propertyData->propType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return loadObjectProperty<true>(l, object, variant, aotContext);
+
+ *variant = QVariant(propType);
+ return loadObjectProperty<true>(l, object, variant->data(), aotContext);
+}
+
+ObjectPropertyResult writeBackObjectAsVariant(QV4::Lookup *l, QObject *object, void *source)
+{
+ QVariant *variant = static_cast<QVariant *>(source);
+ const QMetaType propType = l->qobjectLookup.propertyData->propType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return writeBackObjectProperty<true>(l, object, variant);
+
+ Q_ASSERT(variant->metaType() == propType);
+ return writeBackObjectProperty<true>(l, object, variant->data());
+}
+
+ObjectPropertyResult loadFallbackAsVariant(
+ QV4::Lookup *l, QObject *object, void *target, const AOTCompiledContext *aotContext)
+{
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ QVariant *variant = static_cast<QVariant *>(target);
+ const QMetaType propType = metaObject->property(l->qobjectFallbackLookup.coreIndex).metaType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return loadFallbackProperty(l, object, variant, aotContext);
+
+ *variant = QVariant(propType);
+ return loadFallbackProperty(l, object, variant->data(), aotContext);
+}
+
+ObjectPropertyResult writeBackFallbackAsVariant(QV4::Lookup *l, QObject *object, void *source)
+{
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ QVariant *variant = static_cast<QVariant *>(source);
+ const QMetaType propType = metaObject->property(l->qobjectFallbackLookup.coreIndex).metaType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return writeBackFallbackProperty(l, object, variant);
+
+ Q_ASSERT(variant->metaType() == propType);
+ return writeBackFallbackProperty(l, object, variant->data());
+}
+
+template<bool StrictType, typename Op>
+static ObjectPropertyResult changeObjectProperty(QV4::Lookup *l, QObject *object, Op op)
+{
+ const ObjectPropertyQmlData data = findObjectPropertyQmlData<StrictType>(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ const QQmlPropertyData *property = l->qobjectLookup.propertyData;
+ QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(property->coreIndex()));
+ op(property);
+ return ObjectPropertyResult::OK;
+}
+
+template<bool StrictType = false>
+static ObjectPropertyResult resetObjectProperty(
+ QV4::Lookup *l, QObject *object, QV4::ExecutionEngine *v4)
+{
+ return changeObjectProperty<StrictType>(l, object, [&](const QQmlPropertyData *property) {
+ if (property->isResettable()) {
+ property->resetProperty(object, {});
+ } else {
+ v4->throwError(
+ QLatin1String("Cannot assign [undefined] to ") +
+ QLatin1String(property->propType().name()));
+ }
+ });
+}
+
+template<bool StrictType = false>
+static ObjectPropertyResult storeObjectProperty(QV4::Lookup *l, QObject *object, void *value)
+{
+ return changeObjectProperty<StrictType>(l, object, [&](const QQmlPropertyData *property) {
+ property->writeProperty(object, value, {});
+ });
+}
+
+template<typename Op>
+static ObjectPropertyResult changeFallbackProperty(QV4::Lookup *l, QObject *object, Op op)
+{
+ const FallbackPropertyQmlData data = findFallbackPropertyQmlData(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(coreIndex));
+
+ op(data.metaObject, coreIndex);
+ return ObjectPropertyResult::OK;
+}
+
+static ObjectPropertyResult storeFallbackProperty(QV4::Lookup *l, QObject *object, void *value)
+{
+ return changeFallbackProperty(l, object, [&](const QMetaObject *metaObject, int coreIndex) {
+ void *args[] = { value, nullptr };
+ metaObject->metacall(object, QMetaObject::WriteProperty, coreIndex, args);
+ });
+}
+
+static ObjectPropertyResult resetFallbackProperty(
+ QV4::Lookup *l, QObject *object, const QMetaProperty *property, QV4::ExecutionEngine *v4)
+{
+ return changeFallbackProperty(l, object, [&](const QMetaObject *metaObject, int coreIndex) {
+ if (property->isResettable()) {
+ void *args[] = { nullptr };
+ metaObject->metacall(object, QMetaObject::ResetProperty, coreIndex, args);
+ } else {
+ v4->throwError(
+ QLatin1String("Cannot assign [undefined] to ") +
+ QLatin1String(property->typeName()));
+ }
+ });
+}
+
+static bool isTypeCompatible(QMetaType lookupType, QMetaType propertyType)
+{
+ if (!lookupType.isValid()) {
+ // If type is invalid, then the calling code depends on the lookup
+ // to be set up in order to query the type, via lookupResultMetaType.
+ // We cannot verify the type in this case.
+ } else if ((lookupType.flags() & QMetaType::IsQmlList)
+ && (propertyType.flags() & QMetaType::IsQmlList)) {
+ // We want to check the value types here, but we cannot easily do it.
+ // Internally those are all QObject* lists, though.
+ } else if (lookupType.flags() & QMetaType::PointerToQObject) {
+ // We accept any base class as type, too
+
+ const QMetaObject *typeMetaObject = lookupType.metaObject();
+ const QMetaObject *foundMetaObject = propertyType.metaObject();
+ if (!foundMetaObject)
+ foundMetaObject = QQmlMetaType::metaObjectForType(propertyType).metaObject();
+
+ while (foundMetaObject && foundMetaObject != typeMetaObject)
+ foundMetaObject = foundMetaObject->superClass();
+
+ if (!foundMetaObject)
+ return false;
+ } else if (propertyType.flags() & QMetaType::IsEnumeration) {
+ if (propertyType == lookupType)
+ return true;
+
+ // You can pass the underlying type of an enum.
+ // We don't want to check for the actual underlying type because
+ // moc and qmltyperegistrar are not very precise about it. Especially
+ // the long and longlong types can be ambiguous.
+
+ const bool isUnsigned = propertyType.flags() & QMetaType::IsUnsignedEnumeration;
+ switch (propertyType.sizeOf()) {
+ case 1:
+ return isUnsigned
+ ? lookupType == QMetaType::fromType<quint8>()
+ : lookupType == QMetaType::fromType<qint8>();
+ case 2:
+ return isUnsigned
+ ? lookupType == QMetaType::fromType<ushort>()
+ : lookupType == QMetaType::fromType<short>();
+ case 4:
+ // The default type, if moc doesn't know the actual enum type, is int.
+ // However, the compiler can still decide to encode the enum in uint.
+ // Therefore, we also accept int for uint enums.
+ // TODO: This is technically UB.
+ return isUnsigned
+ ? (lookupType == QMetaType::fromType<int>()
+ || lookupType == QMetaType::fromType<uint>())
+ : lookupType == QMetaType::fromType<int>();
+ case 8:
+ return isUnsigned
+ ? lookupType == QMetaType::fromType<qulonglong>()
+ : lookupType == QMetaType::fromType<qlonglong>();
+ }
+
+ return false;
+ } else if (propertyType != lookupType) {
+ return false;
+ }
+ return true;
+}
+
+static ObjectPropertyResult storeObjectAsVariant(
+ QV4::ExecutionEngine *v4, QV4::Lookup *l, QObject *object, void *value)
+{
+ QVariant *variant = static_cast<QVariant *>(value);
+ const QMetaType propType = l->qobjectLookup.propertyData->propType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return storeObjectProperty<true>(l, object, variant);
+
+ if (!variant->isValid())
+ return resetObjectProperty<true>(l, object, v4);
+
+ if (isTypeCompatible(variant->metaType(), propType))
+ return storeObjectProperty<true>(l, object, variant->data());
+
+ QVariant converted(propType);
+ v4->metaTypeFromJS(v4->fromVariant(*variant), propType, converted.data());
+ return storeObjectProperty<true>(l, object, converted.data());
+}
+
+static ObjectPropertyResult storeFallbackAsVariant(
+ QV4::ExecutionEngine *v4, QV4::Lookup *l, QObject *object, void *value)
+{
+ QVariant *variant = static_cast<QVariant *>(value);
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ const QMetaProperty property = metaObject->property(l->qobjectFallbackLookup.coreIndex);
+ const QMetaType propType = property.metaType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return storeFallbackProperty(l, object, variant);
+
+ if (!variant->isValid())
+ return resetFallbackProperty(l, object, &property, v4);
+
+ if (isTypeCompatible(variant->metaType(), propType))
+ return storeFallbackProperty(l, object, variant->data());
+
+ QVariant converted(propType);
+ v4->metaTypeFromJS(v4->fromVariant(*variant), propType, converted.data());
+ return storeFallbackProperty(l, object, converted.data());
+}
+
+enum class ObjectLookupResult {
+ Failure,
+ Object,
+ Fallback,
+ ObjectAsVariant,
+ FallbackAsVariant,
+};
+
+static ObjectLookupResult initObjectLookup(
+ const AOTCompiledContext *aotContext, QV4::Lookup *l, QObject *object, QMetaType type)
+{
+ QV4::Scope scope(aotContext->engine->handle());
+ QV4::PropertyKey id = scope.engine->identifierTable->asPropertyKey(
+ aotContext->compilationUnit->runtimeStrings[l->nameIndex]);
+
+ Q_ASSERT(id.isString());
+
+ QV4::ScopedString name(scope, id.asStringOrSymbol());
+
+ Q_ASSERT(!name->equals(scope.engine->id_toString()));
+ Q_ASSERT(!name->equals(scope.engine->id_destroy()));
+
+ QQmlData *ddata = QQmlData::get(object, true);
+ Q_ASSERT(ddata);
+ if (ddata->isQueuedForDeletion)
+ return ObjectLookupResult::Failure;
+
+ const QQmlPropertyData *property;
+ if (!ddata->propertyCache) {
+ property = QQmlPropertyCache::property(object, name, aotContext->qmlContext, nullptr);
+ } else {
+ property = ddata->propertyCache->property(
+ name.getPointer(), object, aotContext->qmlContext);
+ }
+
+ const bool doVariantLookup = type == QMetaType::fromType<QVariant>();
+ if (!property) {
+ const QMetaObject *metaObject = object->metaObject();
+ if (!metaObject)
+ return ObjectLookupResult::Failure;
+
+ const int coreIndex = metaObject->indexOfProperty(
+ name->toQStringNoThrow().toUtf8().constData());
+ if (coreIndex < 0)
+ return ObjectLookupResult::Failure;
+
+ const QMetaProperty property = metaObject->property(coreIndex);
+ if (!doVariantLookup && !isTypeCompatible(type, property.metaType()))
+ return ObjectLookupResult::Failure;
+
+ l->releasePropertyCache();
+ // & 1 to tell the gc that this is not heap allocated; see markObjects in qv4lookup_p.h
+ l->qobjectFallbackLookup.metaObject = quintptr(metaObject) + 1;
+ l->qobjectFallbackLookup.coreIndex = coreIndex;
+ l->qobjectFallbackLookup.notifyIndex =
+ QMetaObjectPrivate::signalIndex(property.notifySignal());
+ l->qobjectFallbackLookup.isConstant = property.isConstant() ? 1 : 0;
+ return doVariantLookup
+ ? ObjectLookupResult::FallbackAsVariant
+ : ObjectLookupResult::Fallback;
+ }
+
+ if (!doVariantLookup && !isTypeCompatible(type, property->propType()))
+ return ObjectLookupResult::Failure;
+
+ Q_ASSERT(ddata->propertyCache);
+
+ QV4::setupQObjectLookup(l, ddata, property);
+
+ return doVariantLookup
+ ? ObjectLookupResult::ObjectAsVariant
+ : ObjectLookupResult::Object;
+}
+
+static bool initValueLookup(QV4::Lookup *l, QV4::ExecutableCompilationUnit *compilationUnit,
+ const QMetaObject *metaObject, QMetaType type)
+{
+ Q_ASSERT(metaObject);
+ const QByteArray name = compilationUnit->runtimeStrings[l->nameIndex]->toQString().toUtf8();
+ const int coreIndex = metaObject->indexOfProperty(name.constData());
+ QMetaType lookupType = metaObject->property(coreIndex).metaType();
+ if (!isTypeCompatible(type, lookupType))
+ return false;
+ l->qgadgetLookup.metaObject = quintptr(metaObject) + 1;
+ l->qgadgetLookup.coreIndex = coreIndex;
+ l->qgadgetLookup.metaType = lookupType.iface();
+ return true;
+}
+
+static void amendException(QV4::ExecutionEngine *engine)
+{
+ const int missingLineNumber = engine->currentStackFrame->missingLineNumber();
+ const int lineNumber = engine->currentStackFrame->lineNumber();
+ Q_ASSERT(missingLineNumber != lineNumber);
+
+ auto amendStackTrace = [&](QV4::StackTrace *stackTrace) {
+ for (auto it = stackTrace->begin(), end = stackTrace->end(); it != end; ++it) {
+ if (it->line == missingLineNumber) {
+ it->line = lineNumber;
+ break;
+ }
+ }
+ };
+
+ amendStackTrace(&engine->exceptionStackTrace);
+
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::ErrorObject> error(scope, *engine->exceptionValue);
+ if (error) // else some other value was thrown
+ amendStackTrace(error->d()->stackTrace);
+}
+
+
+bool AOTCompiledContext::captureLookup(uint index, QObject *object) const
+{
+ if (!object)
+ return false;
+
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter == QV4::QQmlTypeWrapper::lookupSingletonProperty
+ || l->getter == QV4::Lookup::getterQObject
+ || l->getter == QV4::Lookup::getterQObjectAsVariant) {
+ const QQmlPropertyData *property = l->qobjectLookup.propertyData;
+ QQmlData::flushPendingBinding(object, property->coreIndex());
+ captureObjectProperty(object, l->qobjectLookup.propertyCache, property, this);
+ return true;
+ }
+
+ if (l->getter == QV4::Lookup::getterFallback
+ || l->getter == QV4::Lookup::getterFallbackAsVariant) {
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ QQmlData::flushPendingBinding(object, coreIndex);
+ captureFallbackProperty(
+ object, coreIndex, l->qobjectFallbackLookup.notifyIndex,
+ l->qobjectFallbackLookup.isConstant, this);
+ return true;
+ }
+
+ return false;
+}
+
+bool AOTCompiledContext::captureQmlContextPropertyLookup(uint index) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty
+ && l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupContextObjectProperty) {
+ const QQmlPropertyData *property = l->qobjectLookup.propertyData;
+ QQmlData::flushPendingBinding(qmlScopeObject, property->coreIndex());
+ captureObjectProperty(qmlScopeObject, l->qobjectLookup.propertyCache, property, this);
+ return true;
+ }
+
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeFallbackProperty) {
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ QQmlData::flushPendingBinding(qmlScopeObject, coreIndex);
+ captureFallbackProperty(qmlScopeObject, coreIndex, l->qobjectFallbackLookup.notifyIndex,
+ l->qobjectFallbackLookup.isConstant, this);
+ return true;
+ }
+
+ return false;
+}
+
+void AOTCompiledContext::captureTranslation() const
+{
+ if (QQmlPropertyCapture *capture = propertyCapture(this))
+ capture->captureTranslation();
+}
+
+QString AOTCompiledContext::translationContext() const
+{
+#if QT_CONFIG(translation)
+ return QV4::GlobalExtensions::currentTranslationContext(engine->handle());
+#else
+ return QString();
+#endif
+}
+
+QMetaType AOTCompiledContext::lookupResultMetaType(uint index) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty
+ || l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupContextObjectProperty
+ || l->getter == QV4::QQmlTypeWrapper::lookupSingletonProperty
+ || l->getter == QV4::Lookup::getterQObject
+ || l->setter == QV4::Lookup::setterQObject
+ || l->getter == QV4::Lookup::getterQObjectAsVariant
+ || l->setter == QV4::Lookup::setterQObjectAsVariant) {
+ return l->qobjectLookup.propertyData->propType();
+ } else if (l->getter == QV4::QQmlValueTypeWrapper::lookupGetter) {
+ return QMetaType(l->qgadgetLookup.metaType);
+ } else if (l->getter == QV4::QQmlTypeWrapper::lookupEnumValue) {
+ return QMetaType::fromType<int>();
+ } else if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupIdObject
+ || l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupType
+ || l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupSingleton
+ || l->getter == QV4::QObjectWrapper::lookupAttached) {
+ return QMetaType::fromType<QObject *>();
+ } else if (l->getter == QV4::Lookup::getterFallback
+ || l->setter == QV4::Lookup::setterFallback
+ || l->getter == QV4::Lookup::getterFallbackAsVariant
+ || l->setter == QV4::Lookup::setterFallbackAsVariant
+ || l->qmlContextPropertyGetter
+ == QV4::QQmlContextWrapper::lookupScopeFallbackProperty) {
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ return metaObject->property(coreIndex).metaType();
+ }
+ return QMetaType();
+}
+
+static bool isUndefined(const void *value, QMetaType type)
+{
+ if (type == QMetaType::fromType<QVariant>())
+ return !static_cast<const QVariant *>(value)->isValid();
+ if (type == QMetaType::fromType<QJSValue>())
+ return static_cast<const QJSValue *>(value)->isUndefined();
+ if (type == QMetaType::fromType<QJSPrimitiveValue>()) {
+ return static_cast<const QJSPrimitiveValue *>(value)->type()
+ == QJSPrimitiveValue::Undefined;
+ }
+ return false;
+}
+
+void AOTCompiledContext::storeNameSloppy(uint nameIndex, void *value, QMetaType type) const
+{
+ // We don't really use any part of the lookup machinery here.
+ // The QV4::Lookup is created on the stack to conveniently get the property cache, and through
+ // the property cache we store a value into the property.
+
+ QV4::Lookup l;
+ memset(&l, 0, sizeof(QV4::Lookup));
+ l.nameIndex = nameIndex;
+ l.forCall = false;
+ ObjectPropertyResult storeResult = ObjectPropertyResult::NeedsInit;
+ switch (initObjectLookup(this, &l, qmlScopeObject, QMetaType())) {
+ case ObjectLookupResult::ObjectAsVariant:
+ case ObjectLookupResult::Object: {
+ const QMetaType propType = l.qobjectLookup.propertyData->propType();
+ if (isTypeCompatible(type, propType)) {
+ storeResult = storeObjectProperty(&l, qmlScopeObject, value);
+ } else if (isUndefined(value, type)) {
+ storeResult = resetObjectProperty(&l, qmlScopeObject, engine->handle());
+ } else {
+ QVariant var(propType);
+ QV4::ExecutionEngine *v4 = engine->handle();
+ v4->metaTypeFromJS(v4->metaTypeToJS(type, value), propType, var.data());
+ storeResult = storeObjectProperty(&l, qmlScopeObject, var.data());
+ }
+
+ l.qobjectLookup.propertyCache->release();
+ break;
+ }
+ case ObjectLookupResult::FallbackAsVariant:
+ case ObjectLookupResult::Fallback: {
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l.qobjectFallbackLookup.metaObject - 1);
+ const QMetaProperty property = metaObject->property(l.qobjectFallbackLookup.coreIndex);
+ const QMetaType propType = property.metaType();
+ if (isTypeCompatible(type, propType)) {
+ storeResult = storeFallbackProperty(&l, qmlScopeObject, value);
+ } else if (isUndefined(value, type)) {
+ storeResult = resetFallbackProperty(&l, qmlScopeObject, &property, engine->handle());
+ } else {
+ QVariant var(propType);
+ QV4::ExecutionEngine *v4 = engine->handle();
+ v4->metaTypeFromJS(v4->metaTypeToJS(type, value), propType, var.data());
+ storeResult = storeFallbackProperty(&l, qmlScopeObject, var.data());
+ }
+ break;
+ }
+ case ObjectLookupResult::Failure:
+ engine->handle()->throwTypeError();
+ return;
+ }
+
+ switch (storeResult) {
+ case ObjectPropertyResult::NeedsInit:
+ engine->handle()->throwTypeError();
+ break;
+ case ObjectPropertyResult::Deleted:
+ engine->handle()->throwTypeError(
+ QStringLiteral("Value is null and could not be converted to an object"));
+ break;
+ case ObjectPropertyResult::OK:
+ break;
+ }
+}
+
+QJSValue AOTCompiledContext::javaScriptGlobalProperty(uint nameIndex) const
+{
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedString name(scope, compilationUnit->runtimeStrings[nameIndex]);
+ QV4::ScopedObject global(scope, scope.engine->globalObject);
+ return QJSValuePrivate::fromReturnedValue(global->get(name->toPropertyKey()));
+}
+
+const QLoggingCategory *AOTCompiledContext::resolveLoggingCategory(QObject *wrapper, bool *ok) const
+{
+ if (wrapper) {
+ // We have to check this here because you may pass a plain QObject that only
+ // turns out to be a QQmlLoggingCategory at run time.
+ if (QQmlLoggingCategory *qQmlLoggingCategory
+ = qobject_cast<QQmlLoggingCategory *>(wrapper)) {
+ QLoggingCategory *loggingCategory = qQmlLoggingCategory->category();
+ *ok = true;
+ if (!loggingCategory) {
+ engine->handle()->throwError(
+ QStringLiteral("A QmlLoggingCatgory was provided without a valid name"));
+ }
+ return loggingCategory;
+ }
+ }
+
+ *ok = false;
+ return qmlEngine() ? &lcQml() : &lcJs();
+}
+
+void AOTCompiledContext::writeToConsole(
+ QtMsgType type, const QString &message, const QLoggingCategory *loggingCategory) const
+{
+ Q_ASSERT(loggingCategory->isEnabled(type));
+
+ const QV4::CppStackFrame *frame = engine->handle()->currentStackFrame;
+ Q_ASSERT(frame);
+
+ const QByteArray source(frame->source().toUtf8());
+ const QByteArray function(frame->function().toUtf8());
+ QMessageLogger logger(source.constData(), frame->lineNumber(),
+ function.constData(), loggingCategory->categoryName());
+
+ switch (type) {
+ case QtDebugMsg:
+ logger.debug("%s", qUtf8Printable(message));
+ break;
+ case QtInfoMsg:
+ logger.info("%s", qUtf8Printable(message));
+ break;
+ case QtWarningMsg:
+ logger.warning("%s", qUtf8Printable(message));
+ break;
+ case QtCriticalMsg:
+ logger.critical("%s", qUtf8Printable(message));
+ break;
+ default:
+ break;
+ }
+}
+
+QVariant AOTCompiledContext::constructValueType(
+ QMetaType resultMetaType, const QMetaObject *resultMetaObject,
+ int ctorIndex, void *ctorArg) const
+{
+ return QQmlValueTypeProvider::constructValueType(
+ resultMetaType, resultMetaObject, ctorIndex, ctorArg);
+}
+
+QDateTime AOTCompiledContext::constructDateTime(double timestamp) const
+{
+ return QV4::DateObject::timestampToDateTime(timestamp);
+}
+
+QDateTime AOTCompiledContext::constructDateTime(const QString &string) const
+{
+ return QV4::DateObject::stringToDateTime(string, engine->handle());
+}
+
+QDateTime AOTCompiledContext::constructDateTime(
+ double year, double month, double day, double hours,
+ double minutes, double seconds, double msecs) const
+{
+ return constructDateTime(QV4::DateObject::componentsToTimestamp(
+ year, month, day, hours, minutes, seconds, msecs, engine->handle()));
+}
+
+bool AOTCompiledContext::callQmlContextPropertyLookup(
+ uint index, void **args, const QMetaType *types, int argc) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedValue thisObject(scope);
+ QV4::ScopedFunctionObject function(
+ scope, l->qmlContextPropertyGetter(l, scope.engine, thisObject));
+ if (!function) {
+ scope.engine->throwTypeError(
+ QStringLiteral("Property '%1' of object [null] is not a function").arg(
+ compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ }
+
+ function->call(qmlScopeObject, args, types, argc);
+ return !scope.hasException();
+}
+
+void AOTCompiledContext::initCallQmlContextPropertyLookup(uint index) const
+{
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
+}
+
+bool AOTCompiledContext::loadContextIdLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ int objectId = -1;
+ QQmlContextData *context = nullptr;
+ Q_ASSERT(qmlContext);
+
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupIdObject) {
+ objectId = l->qmlContextIdObjectLookup.objectId;
+ context = qmlContext;
+ } else if (l->qmlContextPropertyGetter
+ == QV4::QQmlContextWrapper::lookupIdObjectInParentContext) {
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedString name(scope, compilationUnit->runtimeStrings[l->nameIndex]);
+ for (context = qmlContext; context; context = context->parent().data()) {
+ objectId = context->propertyIndex(name);
+ if (objectId != -1 && objectId < context->numIdValues())
+ break;
+ }
+ } else {
+ return false;
+ }
+
+ Q_ASSERT(objectId >= 0);
+ Q_ASSERT(context != nullptr);
+ QQmlEnginePrivate *engine = QQmlEnginePrivate::get(qmlEngine());
+ if (QQmlPropertyCapture *capture = engine->propertyCapture)
+ capture->captureProperty(context->idValueBindings(objectId));
+ *static_cast<QObject **>(target) = context->idValue(objectId);
+ return true;
+}
+
+void AOTCompiledContext::initLoadContextIdLookup(uint index) const
+{
+ Q_ASSERT(!engine->hasError());
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedString name(scope, compilationUnit->runtimeStrings[l->nameIndex]);
+ const QQmlRefPointer<QQmlContextData> ownContext = qmlContext;
+ for (auto context = ownContext; context; context = context->parent()) {
+ const int propertyIdx = context->propertyIndex(name);
+ if (propertyIdx == -1 || propertyIdx >= context->numIdValues())
+ continue;
+
+ if (context.data() == ownContext.data()) {
+ l->qmlContextIdObjectLookup.objectId = propertyIdx;
+ l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupIdObject;
+ } else {
+ l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupIdObjectInParentContext;
+ }
+
+ return;
+ }
+
+ Q_UNREACHABLE();
+}
+
+bool AOTCompiledContext::callObjectPropertyLookup(
+ uint index, QObject *object, void **args, const QMetaType *types, int argc) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedValue thisObject(scope, QV4::QObjectWrapper::wrap(scope.engine, object));
+ QV4::ScopedFunctionObject function(scope, l->getter(l, engine->handle(), thisObject));
+ if (!function) {
+ scope.engine->throwTypeError(
+ QStringLiteral("Property '%1' of object [object Object] is not a function")
+ .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ }
+
+ function->call(object, args, types, argc);
+ return !scope.hasException();
+}
+
+void AOTCompiledContext::initCallObjectPropertyLookup(uint index) const
+{
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
+}
+
+bool AOTCompiledContext::callGlobalLookup(
+ uint index, void **args, const QMetaType *types, int argc) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedFunctionObject function(scope, l->globalGetter(l, scope.engine));
+ if (!function) {
+ scope.engine->throwTypeError(
+ QStringLiteral("Property '%1' of object [null] is not a function")
+ .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ }
+
+ function->call(nullptr, args, types, argc);
+ return true;
+}
+
+void AOTCompiledContext::initCallGlobalLookup(uint index) const
+{
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
+}
+
+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)) {
+ engine->handle()->throwTypeError();
+ return false;
+ }
+ return true;
+}
+
+void AOTCompiledContext::initLoadGlobalLookup(uint index) const
+{
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
+}
+
+bool AOTCompiledContext::loadScopeObjectPropertyLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+
+ if (!qmlScopeObject) {
+ engine->handle()->throwReferenceError(
+ compilationUnit->runtimeStrings[l->nameIndex]->toQString());
+ return false;
+ }
+
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty)
+ result = loadObjectProperty(l, qmlScopeObject, target, this);
+ else if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeFallbackProperty)
+ result = loadFallbackProperty(l, qmlScopeObject, target, this);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::Deleted:
+ engine->handle()->throwTypeError(
+ QStringLiteral("Cannot read property '%1' of null")
+ .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+bool AOTCompiledContext::writeBackScopeObjectPropertyLookup(uint index, void *source) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty)
+ result = writeBackObjectProperty(l, qmlScopeObject, source);
+ else if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeFallbackProperty)
+ result = writeBackFallbackProperty(l, qmlScopeObject, source);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::Deleted: // Silently omit the write back. Same as interpreter
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+void AOTCompiledContext::initLoadScopeObjectPropertyLookup(uint index, QMetaType type) const
+{
+ QV4::ExecutionEngine *v4 = engine->handle();
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+
+ if (v4->hasException) {
+ amendException(v4);
+ return;
+ }
+
+ switch (initObjectLookup(this, l, qmlScopeObject, type)) {
+ case ObjectLookupResult::ObjectAsVariant:
+ case ObjectLookupResult::Object:
+ l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupScopeObjectProperty;
+ break;
+ case ObjectLookupResult::FallbackAsVariant:
+ case ObjectLookupResult::Fallback:
+ l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupScopeFallbackProperty;
+ break;
+ case ObjectLookupResult::Failure:
+ v4->throwTypeError();
+ break;
+ }
+}
+
+bool AOTCompiledContext::loadSingletonLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupSingleton) {
+ QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(
+ scope, l->qmlContextSingletonLookup.singletonObject);
+
+ // We don't handle non-QObject singletons (as those can't be declared in qmltypes anyway)
+ Q_ASSERT(wrapper);
+ *static_cast<QObject **>(target) = wrapper->object();
+ return true;
+ }
+
+ return false;
+}
+
+using QmlContextPropertyGetter
+ = QV4::ReturnedValue (*)(QV4::Lookup *l, QV4::ExecutionEngine *engine, QV4::Value *thisObject);
+
+template<QmlContextPropertyGetter qmlContextPropertyGetter>
+static void initTypeWrapperLookup(
+ const AOTCompiledContext *context, QV4::Lookup *l, uint importNamespace)
+{
+ Q_ASSERT(!context->engine->hasError());
+ if (importNamespace != AOTCompiledContext::InvalidStringId) {
+ QV4::Scope scope(context->engine->handle());
+ QV4::ScopedString import(scope, context->compilationUnit->runtimeStrings[importNamespace]);
+
+ QQmlTypeLoader *typeLoader = scope.engine->typeLoader();
+ Q_ASSERT(typeLoader);
+ if (const QQmlImportRef *importRef
+ = context->qmlContext->imports()->query(import, typeLoader).importNamespace) {
+
+ QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(
+ scope, QV4::QQmlTypeWrapper::create(
+ scope.engine, nullptr, context->qmlContext->imports(), importRef));
+ wrapper = l->qmlContextPropertyGetter(l, context->engine->handle(), wrapper);
+ l->qmlContextPropertyGetter = qmlContextPropertyGetter;
+ if (qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupSingleton)
+ l->qmlContextSingletonLookup.singletonObject.set(scope.engine, wrapper->heapObject());
+ else if (qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupType)
+ l->qmlTypeLookup.qmlTypeWrapper.set(scope.engine, wrapper->heapObject());
+ return;
+ }
+ scope.engine->throwTypeError();
+ } else {
+ QV4::ExecutionEngine *v4 = context->engine->handle();
+ l->qmlContextPropertyGetter(l, v4, nullptr);
+ if (l->qmlContextPropertyGetter != qmlContextPropertyGetter) {
+ const QString error
+ = QLatin1String(qmlContextPropertyGetter
+ == QV4::QQmlContextWrapper::lookupSingleton
+ ? "%1 was a singleton at compile time, "
+ "but is not a singleton anymore."
+ : "%1 was not a singleton at compile time, "
+ "but is a singleton now.")
+ .arg(context->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
+ v4->throwTypeError(error);
+ }
+ }
+}
+
+void AOTCompiledContext::initLoadSingletonLookup(uint index, uint importNamespace) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ initTypeWrapperLookup<QV4::QQmlContextWrapper::lookupSingleton>(this, l, importNamespace);
+}
+
+bool AOTCompiledContext::loadAttachedLookup(uint index, QObject *object, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter != QV4::QObjectWrapper::lookupAttached)
+ return false;
+
+ QV4::Scope scope(engine->handle());
+ QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(scope, l->qmlTypeLookup.qmlTypeWrapper);
+ Q_ASSERT(wrapper);
+ *static_cast<QObject **>(target) = qmlAttachedPropertiesObject(
+ object, wrapper->d()->type().attachedPropertiesFunction(
+ QQmlEnginePrivate::get(qmlEngine())));
+ return true;
+}
+
+void AOTCompiledContext::initLoadAttachedLookup(
+ uint index, uint importNamespace, QObject *object) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedString name(scope, compilationUnit->runtimeStrings[l->nameIndex]);
+
+ QQmlType type;
+ QQmlTypeLoader *typeLoader = scope.engine->typeLoader();
+ Q_ASSERT(typeLoader);
+ if (importNamespace != InvalidStringId) {
+ QV4::ScopedString import(scope, compilationUnit->runtimeStrings[importNamespace]);
+ if (const QQmlImportRef *importRef
+ = qmlContext->imports()->query(import, typeLoader).importNamespace) {
+ type = qmlContext->imports()->query(name, importRef, typeLoader).type;
+ }
+ } else {
+ type = qmlContext->imports()->query<QQmlImport::AllowRecursion>(name, typeLoader).type;
+ }
+
+ if (!type.isValid()) {
+ scope.engine->throwTypeError();
+ return;
+ }
+
+ QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(
+ scope, QV4::QQmlTypeWrapper::create(scope.engine, object, type,
+ QV4::Heap::QQmlTypeWrapper::ExcludeEnums));
+
+ l->qmlTypeLookup.qmlTypeWrapper.set(scope.engine, wrapper->d());
+ l->getter = QV4::QObjectWrapper::lookupAttached;
+}
+
+bool AOTCompiledContext::loadTypeLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->qmlContextPropertyGetter != QV4::QQmlContextWrapper::lookupType)
+ return false;
+
+ const QV4::Heap::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::Heap::QQmlTypeWrapper *>(
+ l->qmlTypeLookup.qmlTypeWrapper.get());
+
+ QMetaType metaType = typeWrapper->type().typeId();
+ *static_cast<const QMetaObject **>(target)
+ = QQmlMetaType::metaObjectForType(metaType).metaObject();
+ return true;
+}
+
+void AOTCompiledContext::initLoadTypeLookup(uint index, uint importNamespace) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ initTypeWrapperLookup<QV4::QQmlContextWrapper::lookupType>(this, l, importNamespace);
+}
+
+bool AOTCompiledContext::getObjectLookup(uint index, QObject *object, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ const auto doThrow = [&]() {
+ engine->handle()->throwTypeError(
+ QStringLiteral("Cannot read property '%1' of null")
+ .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ };
+
+ if (!object)
+ return doThrow();
+
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->getter == QV4::Lookup::getterQObject)
+ result = loadObjectProperty(l, object, target, this);
+ else if (l->getter == QV4::Lookup::getterFallback)
+ result = loadFallbackProperty(l, object, target, this);
+ else if (l->getter == QV4::Lookup::getterQObjectAsVariant)
+ result = loadObjectAsVariant(l, object, target, this);
+ else if (l->getter == QV4::Lookup::getterFallbackAsVariant)
+ result = loadFallbackAsVariant(l, object, target, this);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::Deleted:
+ return doThrow();
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+bool AOTCompiledContext::writeBackObjectLookup(uint index, QObject *object, void *source) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (!object)
+ return true;
+
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->getter == QV4::Lookup::getterQObject)
+ result = writeBackObjectProperty(l, object, source);
+ else if (l->getter == QV4::Lookup::getterFallback)
+ result = writeBackFallbackProperty(l, object, source);
+ else if (l->getter == QV4::Lookup::getterQObjectAsVariant)
+ result = writeBackObjectAsVariant(l, object, source);
+ else if (l->getter == QV4::Lookup::getterFallbackAsVariant)
+ result = writeBackFallbackAsVariant(l, object, source);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::Deleted: // Silently omit the write back
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+void AOTCompiledContext::initGetObjectLookup(uint index, QObject *object, QMetaType type) const
+{
+ QV4::ExecutionEngine *v4 = engine->handle();
+ if (v4->hasException) {
+ amendException(v4);
+ } else {
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ switch (initObjectLookup(this, l, object, type)) {
+ case ObjectLookupResult::Object:
+ l->getter = QV4::Lookup::getterQObject;
+ break;
+ case ObjectLookupResult::ObjectAsVariant:
+ l->getter = QV4::Lookup::getterQObjectAsVariant;
+ break;
+ case ObjectLookupResult::Fallback:
+ l->getter = QV4::Lookup::getterFallback;
+ break;
+ case ObjectLookupResult::FallbackAsVariant:
+ l->getter = QV4::Lookup::getterFallbackAsVariant;
+ break;
+ case ObjectLookupResult::Failure:
+ engine->handle()->throwTypeError();
+ break;
+ }
+ }
+}
+
+bool AOTCompiledContext::getValueLookup(uint index, void *value, void *target) const
+{
+ Q_ASSERT(value);
+
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter != QV4::QQmlValueTypeWrapper::lookupGetter)
+ return false;
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qgadgetLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ void *args[] = { target, nullptr };
+ metaObject->d.static_metacall(
+ reinterpret_cast<QObject*>(value), QMetaObject::ReadProperty,
+ l->qgadgetLookup.coreIndex, args);
+ return true;
+}
+
+bool AOTCompiledContext::writeBackValueLookup(uint index, void *value, void *source) const
+{
+ Q_ASSERT(value);
+
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter != QV4::QQmlValueTypeWrapper::lookupGetter)
+ return false;
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qgadgetLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ void *args[] = { source, nullptr };
+ metaObject->d.static_metacall(
+ reinterpret_cast<QObject*>(value), QMetaObject::WriteProperty,
+ l->qgadgetLookup.coreIndex, args);
+ return true;
+}
+
+void AOTCompiledContext::initGetValueLookup(
+ uint index, const QMetaObject *metaObject, QMetaType type) const
+{
+ Q_ASSERT(!engine->hasError());
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (initValueLookup(l, compilationUnit, metaObject, type))
+ l->getter = QV4::QQmlValueTypeWrapper::lookupGetter;
+ else
+ engine->handle()->throwTypeError();
+}
+
+bool AOTCompiledContext::getEnumLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter != QV4::QQmlTypeWrapper::lookupEnumValue)
+ return false;
+ const bool isUnsigned
+ = l->qmlEnumValueLookup.metaType->flags & QMetaType::IsUnsignedEnumeration;
+ const QV4::ReturnedValue encoded = l->qmlEnumValueLookup.encodedEnumValue;
+ switch (l->qmlEnumValueLookup.metaType->size) {
+ case 1:
+ if (isUnsigned)
+ *static_cast<quint8 *>(target) = encoded;
+ else
+ *static_cast<qint8 *>(target) = encoded;
+ return true;
+ case 2:
+ if (isUnsigned)
+ *static_cast<quint16 *>(target) = encoded;
+ else
+ *static_cast<qint16 *>(target) = encoded;
+ return true;
+ case 4:
+ if (isUnsigned)
+ *static_cast<quint32 *>(target) = encoded;
+ else
+ *static_cast<qint32 *>(target) = encoded;
+ return true;
+ case 8:
+ if (isUnsigned)
+ *static_cast<quint64 *>(target) = encoded;
+ else
+ *static_cast<qint64 *>(target) = encoded;
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void AOTCompiledContext::initGetEnumLookup(
+ uint index, const QMetaObject *metaObject,
+ const char *enumerator, const char *enumValue) const
+{
+ Q_ASSERT(!engine->hasError());
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (!metaObject) {
+ engine->handle()->throwTypeError(
+ QStringLiteral("Cannot read property '%1' of undefined")
+ .arg(QString::fromUtf8(enumValue)));
+ return;
+ }
+ const int enumIndex = metaObject->indexOfEnumerator(enumerator);
+ const QMetaEnum metaEnum = metaObject->enumerator(enumIndex);
+ l->qmlEnumValueLookup.encodedEnumValue = metaEnum.keyToValue(enumValue);
+ l->qmlEnumValueLookup.metaType = metaEnum.metaType().iface();
+ l->getter = QV4::QQmlTypeWrapper::lookupEnumValue;
+}
+
+bool AOTCompiledContext::setObjectLookup(uint index, QObject *object, void *value) const
+{
+ const auto doThrow = [&]() {
+ engine->handle()->throwTypeError(
+ QStringLiteral("Value is null and could not be converted to an object"));
+ return false;
+ };
+
+ if (!object)
+ return doThrow();
+
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->setter == QV4::Lookup::setterQObject)
+ result = storeObjectProperty(l, object, value);
+ else if (l->setter == QV4::Lookup::setterFallback)
+ result = storeFallbackProperty(l, object, value);
+ else if (l->setter == QV4::Lookup::setterQObjectAsVariant)
+ result = storeObjectAsVariant(engine->handle(), l, object, value);
+ else if (l->setter == QV4::Lookup::setterFallbackAsVariant)
+ result = storeFallbackAsVariant(engine->handle(), l, object, value);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::Deleted:
+ return doThrow();
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+void AOTCompiledContext::initSetObjectLookup(uint index, QObject *object, QMetaType type) const
+{
+ QV4::ExecutionEngine *v4 = engine->handle();
+ if (v4->hasException) {
+ amendException(v4);
+ } else {
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ switch (initObjectLookup(this, l, object, type)) {
+ case ObjectLookupResult::Object:
+ l->setter = QV4::Lookup::setterQObject;
+ break;
+ case ObjectLookupResult::ObjectAsVariant:
+ l->setter = QV4::Lookup::setterQObjectAsVariant;
+ break;
+ case ObjectLookupResult::Fallback:
+ l->setter = QV4::Lookup::setterFallback;
+ break;
+ case ObjectLookupResult::FallbackAsVariant:
+ l->setter = QV4::Lookup::setterFallbackAsVariant;
+ break;
+ case ObjectLookupResult::Failure:
+ engine->handle()->throwTypeError();
+ break;
+ }
+ }
+}
+
+bool AOTCompiledContext::setValueLookup(
+ uint index, void *target, void *value) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->setter != QV4::QQmlValueTypeWrapper::lookupSetter)
+ return false;
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qgadgetLookup.metaObject - 1);
+
+ void *args[] = { value, nullptr };
+ metaObject->d.static_metacall(
+ reinterpret_cast<QObject*>(target), QMetaObject::WriteProperty,
+ l->qgadgetLookup.coreIndex, args);
+ return true;
+}
+
+void AOTCompiledContext::initSetValueLookup(uint index, const QMetaObject *metaObject,
+ QMetaType type) const
+{
+ Q_ASSERT(!engine->hasError());
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (initValueLookup(l, compilationUnit, metaObject, type))
+ l->setter = QV4::QQmlValueTypeWrapper::lookupSetter;
+ else
+ engine->handle()->throwTypeError();
+}
+
+} // namespace QQmlPrivate
+
QT_END_NAMESPACE