aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqml.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2021-04-23 16:19:35 +0200
committerUlf Hermann <ulf.hermann@qt.io>2021-04-30 17:54:10 +0200
commit2b49615db4381fa7c54b1ebbc9875d214ad292aa (patch)
treeb79a86598e02af8a497e8e05446291d4769b8e5b /src/qml/qml/qqml.cpp
parent499fcb5d399321c3d887ead8f5a5b8696841a7f9 (diff)
Redesign the AOT lookups
Each kind of lookup should come with a function that tries to execute the lookup, taking a minimal number of parameters, and another one that initializes the lookup, taking whatever is needed for that. No initialization should be done in the execution step and vice versa. Rather, the execution step should be repeated if an initialization had to be done first. This way, the happy path can be very fast if the lookups have been initialized before. Change-Id: Ic435b3dd4906d00144138cb05161a99a0a9c64ed Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/qml/qqml.cpp')
-rw-r--r--src/qml/qml/qqml.cpp654
1 files changed, 449 insertions, 205 deletions
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index 9da48fc0e0..afe6bedf56 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -53,6 +53,8 @@
#include <private/qqmlvaluetypewrapper_p.h>
#include <private/qv4lookup_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4identifiertable_p.h>
+#include <private/qv4errorobject_p.h>
#include <QtCore/qmutex.h>
@@ -652,67 +654,167 @@ void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
}
namespace QQmlPrivate {
- template<>
- void qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>(
- const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject,
- QVector<int> *qmlTypeIds, const QMetaObject *extension)
- {
- using T = QQmlTypeNotAvailable;
-
- RegisterTypeAndRevisions type = {
- 0,
- QMetaType::fromType<T *>(),
- QMetaType::fromType<QQmlListProperty<T>>(),
- 0,
- nullptr,
- nullptr,
- nullptr,
+template<>
+void qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>(
+ const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject,
+ QVector<int> *qmlTypeIds, const QMetaObject *extension)
+{
+ using T = QQmlTypeNotAvailable;
- uri,
- QTypeRevision::fromMajorVersion(versionMajor),
+ RegisterTypeAndRevisions type = {
+ 0,
+ QMetaType::fromType<T *>(),
+ QMetaType::fromType<QQmlListProperty<T>>(),
+ 0,
+ nullptr,
+ nullptr,
+ nullptr,
- &QQmlTypeNotAvailable::staticMetaObject,
- classInfoMetaObject,
+ uri,
+ QTypeRevision::fromMajorVersion(versionMajor),
- attachedPropertiesFunc<T>(),
- attachedPropertiesMetaObject<T>(),
+ &QQmlTypeNotAvailable::staticMetaObject,
+ classInfoMetaObject,
- StaticCastSelector<T, QQmlParserStatus>::cast(),
- StaticCastSelector<T, QQmlPropertyValueSource>::cast(),
- StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
+ attachedPropertiesFunc<T>(),
+ attachedPropertiesMetaObject<T>(),
- nullptr, extension, qmlCreateCustomParser<T>, qmlTypeIds
- };
+ StaticCastSelector<T, QQmlParserStatus>::cast(),
+ StaticCastSelector<T, QQmlPropertyValueSource>::cast(),
+ StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
- qmlregister(TypeAndRevisionsRegistration, &type);
- }
+ nullptr, extension, qmlCreateCustomParser<T>, qmlTypeIds
+ };
+
+ qmlregister(TypeAndRevisionsRegistration, &type);
}
-QQmlEngine *QQmlPrivate::AOTCompiledContext::qmlEngine() const
+
+QQmlEngine *AOTCompiledContext::qmlEngine() const
{
return qmlContext ? qmlContext->engine() : nullptr;
}
-QJSValue QQmlPrivate::AOTCompiledContext::jsMetaType(int index) const
+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;
}
-QJSValue QQmlPrivate::AOTCompiledContext::loadQmlContextPropertyLookup(uint index) const
+
+static void captureObjectProperty(
+ QObject *object, const QQmlPropertyCache *propertyCache,
+ const QQmlPropertyData *property, QQmlContextData *qmlContext)
+{
+ if (!qmlContext || property->isConstant())
+ return;
+
+ QQmlEngine *engine = qmlContext->engine();
+ Q_ASSERT(engine);
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ Q_ASSERT(ep);
+ if (QQmlPropertyCapture *capture = ep->propertyCapture)
+ capture->captureProperty(object, propertyCache, property);
+}
+
+static void loadObjectProperty(QV4::Lookup *l, QObject *object, void *target,
+ QQmlContextData *qmlContext)
+{
+ const QQmlPropertyCache *propertyCache = l->qobjectLookup.propertyCache;
+ Q_ASSERT(!QQmlData::wasDeleted(object));
+ Q_ASSERT(QQmlData::get(object)->propertyCache == propertyCache);
+ const QQmlPropertyData *property = l->qobjectLookup.propertyData;
+ captureObjectProperty(object, propertyCache, property, qmlContext);
+ property->readProperty(object, target);
+}
+
+static void storeObjectProperty(QV4::Lookup *l, QObject *object, void *value)
+{
+ const QQmlPropertyCache *propertyCache = l->qobjectLookup.propertyCache;
+ Q_ASSERT(!QQmlData::wasDeleted(object));
+ Q_ASSERT(QQmlData::get(object)->propertyCache == propertyCache);
+ const QQmlPropertyData *property = l->qobjectLookup.propertyData;
+ QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(property->coreIndex()));
+ property->writeProperty(object, value, {});
+}
+
+static void initObjectLookup(
+ const AOTCompiledContext *aotContext, QV4::Lookup *l, QObject *object)
+{
+ 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);
+
+ QQmlPropertyData *property;
+ if (!ddata->propertyCache) {
+ property = QQmlPropertyCache::property(
+ aotContext->engine, object, name, aotContext->qmlContext, nullptr);
+ } else {
+ property = ddata->propertyCache->property(
+ name.getPointer(), object, aotContext->qmlContext);
+ }
+
+ Q_ASSERT(property);
+ Q_ASSERT(ddata->propertyCache);
+
+ l->qobjectLookup.propertyCache = ddata->propertyCache;
+ l->qobjectLookup.propertyCache->addref();
+ l->qobjectLookup.propertyData = property;
+}
+
+static void initValueLookup(QV4::Lookup *l, QV4::ExecutableCompilationUnit *compilationUnit,
+ const QMetaObject *metaObject)
+{
+ Q_ASSERT(metaObject);
+ l->qgadgetLookup.metaObject = quintptr(metaObject) + 1;
+ const QByteArray name = compilationUnit->runtimeStrings[l->nameIndex]->toQString().toUtf8();
+ l->qgadgetLookup.coreIndex = metaObject->indexOfProperty(name.constData());
+ l->qgadgetLookup.metaType = metaObject->property(
+ l->qgadgetLookup.coreIndex).metaType().iface();
+}
+
+static void amendException(QV4::ExecutionEngine *engine)
+{
+ const int lineNumber = engine->currentStackFrame->lineNumber();
+ engine->exceptionStackTrace.front().line = lineNumber;
+
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::ErrorObject> error(scope, *engine->exceptionValue);
+ if (error) // else some other value was thrown
+ error->d()->stackTrace->front().line = lineNumber;
+}
+
+
+bool AOTCompiledContext::captureLookup(uint index, QObject *object) const
{
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- return QJSValuePrivate::fromReturnedValue(l->qmlContextPropertyGetter(
- l, engine->handle(), nullptr));
+ if (l->getter != QV4::QQmlTypeWrapper::lookupSingletonProperty
+ && l->getter != QV4::QObjectWrapper::lookupGetter) {
+ return false;
+ }
+
+ captureObjectProperty(
+ object, l->qobjectLookup.propertyCache, l->qobjectLookup.propertyData, qmlContext);
+ return true;
}
-bool QQmlPrivate::AOTCompiledContext::captureQmlContextPropertyLookup(uint index) const
+bool AOTCompiledContext::captureQmlContextPropertyLookup(uint index) const
{
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
if (l->qmlContextPropertyGetter != QV4::QQmlContextWrapper::lookupScopeObjectProperty
@@ -720,133 +822,308 @@ bool QQmlPrivate::AOTCompiledContext::captureQmlContextPropertyLookup(uint index
return false;
}
- const auto *property = l->qobjectLookup.propertyData;
- Q_ASSERT(property);
- if (property->isConstant())
- return true;
+ captureObjectProperty(qmlScopeObject, l->qobjectLookup.propertyCache,
+ l->qobjectLookup.propertyData, qmlContext);
+ return true;
+}
- if (QQmlEngine *engine = qmlContext->engine()) {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
- if (QQmlPropertyCapture *capture = ep->propertyCapture)
- capture->captureProperty(qmlScopeObject, l->qobjectLookup.propertyCache, property);
+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::QObjectWrapper::lookupGetter) {
+ 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 *>();
}
+ return QMetaType();
+}
- return true;
+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(thisObject, args, types, argc);
+ return !scope.engine->hasException;
+}
+
+void AOTCompiledContext::initCallQmlContextPropertyLookup(uint index) const
+{
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
}
-QObject *QQmlPrivate::AOTCompiledContext::loadQmlContextPropertyIdLookup(uint index) const
+bool AOTCompiledContext::loadContextIdLookup(uint index, void *target) const
{
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupIdObject) {
- // Shortcut this to avoid the wrapping when returning from lookupIdObject().
- if (!qmlContext)
- return nullptr;
+ if (l->qmlContextPropertyGetter != QV4::QQmlContextWrapper::lookupIdObject)
+ return false;
- QQmlEnginePrivate *qmlEngine = QQmlEnginePrivate::get(qmlContext->engine());
- const int objectId = l->qmlContextIdObjectLookup.objectId;
+ Q_ASSERT(qmlContext);
+
+ QQmlContextData *contextData;
+ if (auto *wrapper = l->qmlContextIdObjectLookup.ownContextWrapper) {
+ QV4::Scope scope(engine->handle());
+ QV4::Scoped<QV4::QQmlContextWrapper> ownContext(scope, wrapper);
+ if (ownContext->d()->context != qmlContext)
+ return false; // context has changed. Look up again.
+ QV4::Scoped<QV4::QQmlContextWrapper> objectContext(
+ scope, l->qmlContextIdObjectLookup.objectContextWrapper);
+ contextData = objectContext->d()->context;
+ } else {
+ contextData = qmlContext;
+ }
+
+ const int objectId = l->qmlContextIdObjectLookup.objectId;
+ QQmlEnginePrivate *engine = QQmlEnginePrivate::get(qmlEngine());
- if (QQmlPropertyCapture *capture = qmlEngine->propertyCapture)
- capture->captureProperty(qmlContext->idValueBindings(objectId));
- return qmlContext->idValue(objectId);
+ if (QQmlPropertyCapture *capture = engine->propertyCapture)
+ capture->captureProperty(contextData->idValueBindings(objectId));
+ *static_cast<QObject **>(target) = contextData->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;
+
+ l->qmlContextIdObjectLookup.objectId = propertyIdx;
+ l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupIdObject;
+ if (context.data() != ownContext.data()) {
+ l->qmlContextIdObjectLookup.objectContextWrapper
+ = scope.engine->memoryManager->allocate<QV4::QQmlContextWrapper>(
+ context, nullptr);
+ l->qmlContextIdObjectLookup.ownContextWrapper
+ = scope.engine->memoryManager->allocate<QV4::QQmlContextWrapper>(
+ ownContext, nullptr);
+ }
+ 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::Scoped<QV4::QObjectWrapper> o(
- scope, l->qmlContextPropertyGetter(l, scope.engine, nullptr));
- return o ? o->object() : nullptr;
+ 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(thisObject, args, types, argc);
+ return !scope.engine->hasException;
}
-static void captureObjectProperty(
- QObject *object, const QQmlPropertyCache *propertyCache,
- const QQmlPropertyData *property, QQmlContextData *qmlContext)
+void AOTCompiledContext::initCallObjectPropertyLookup(uint index) const
{
- if (!qmlContext || property->isConstant())
- return;
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
+}
- QQmlEngine *engine = qmlContext->engine();
- Q_ASSERT(engine);
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
- Q_ASSERT(ep);
- if (QQmlPropertyCapture *capture = ep->propertyCapture)
- capture->captureProperty(object, propertyCache, property);
+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;
+ }
+
+ QV4::ScopedValue thisObject(scope, QV4::Encode::undefined());
+ function->call(thisObject, args, types, argc);
+ return true;
}
-static void *transformVariant(void *target, QMetaType propertyType)
+void AOTCompiledContext::initCallGlobalLookup(uint index) const
{
- QVariant *v = static_cast<QVariant *>(target);
- if (v->metaType() != propertyType)
- *v = QVariant(propertyType);
- return v->data();
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
}
-static void loadObjectProperty(QV4::Lookup *l, QObject *object, void *target, QMetaType type,
- QQmlContextData *qmlContext)
+bool AOTCompiledContext::loadGlobalLookup(uint index, void *target, QMetaType type) const
{
- const QQmlPropertyCache *propertyCache = l->qobjectLookup.propertyCache;
- Q_ASSERT(!QQmlData::wasDeleted(object));
- Q_ASSERT(QQmlData::get(object)->propertyCache == propertyCache);
- const QQmlPropertyData *property = l->qobjectLookup.propertyData;
- const QMetaType propertyType = property->propType();
- if (type != propertyType && type == QMetaType::fromType<QVariant>()) {
- // We can read into the contents of a QVariant without conversion.
- captureObjectProperty(object, propertyCache, property, qmlContext);
- property->readProperty(object, transformVariant(target, propertyType));
- } else {
- Q_ASSERT(propertyType == type
- || (type.flags() & QMetaType::PointerToQObject
- && propertyType.flags() & QMetaType::PointerToQObject));
- captureObjectProperty(object, propertyCache, property, qmlContext);
- property->readProperty(object, target);
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::ExecutionEngine *v4 = engine->handle();
+ if (!v4->metaTypeFromJS(l->globalGetter(l, engine->handle()), type, target)) {
+ v4->throwTypeError();
+ return false;
}
+ return true;
+}
+
+void AOTCompiledContext::initLoadGlobalLookup(uint index) const
+{
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
}
-bool QQmlPrivate::AOTCompiledContext::loadQmlContextPropertyLookup(
- uint index, void *target, QMetaType type) const
+bool AOTCompiledContext::loadScopeObjectPropertyLookup(uint index, void *target) const
{
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty) {
- loadObjectProperty(l, qmlScopeObject, target, type, qmlContext);
+ if (l->qmlContextPropertyGetter != QV4::QQmlContextWrapper::lookupScopeObjectProperty)
+ return false;
+ loadObjectProperty(l, qmlScopeObject, target, qmlContext);
+ return true;
+}
+
+void AOTCompiledContext::initLoadScopeObjectPropertyLookup(uint index) const
+{
+ Q_ASSERT(!engine->hasError());
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ initObjectLookup(this, l, qmlScopeObject);
+ l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupScopeObjectProperty;
+}
+
+bool AOTCompiledContext::loadTypeLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupType) {
+ // We resolve it right away. An AOT compiler, in contrast to a naive interpreter
+ // should only request objects it actually needs.
+ QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(scope, l->qmlTypeLookup.qmlTypeWrapper);
+ Q_ASSERT(wrapper);
+ *static_cast<QObject **>(target) = wrapper->object();
return true;
}
- QV4::Scope scope(engine->handle());
- QV4::ScopedValue result(scope, l->qmlContextPropertyGetter(l, scope.engine, nullptr));
- if (type == QMetaType::fromType<QVariant>()) {
- // Special case QVariant in order to retain JS objects.
- // We don't want to convert JS arrays into QVariantList, for example.
- *static_cast<QVariant *>(target) = scope.engine->toVariant(result, QMetaType {});
+ 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 scope.engine->metaTypeFromJS(result, type, target);
+
+ return false;
}
-bool QQmlPrivate::AOTCompiledContext::getObjectLookup(
- uint index, QObject *object, void *target, QMetaType type) const
+void AOTCompiledContext::initLoadTypeLookup(uint index) const
{
+ Q_ASSERT(!engine->hasError());
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ l->qmlContextPropertyGetter(l, engine->handle(), nullptr);
- if (!object)
+ // Singleton instances can be retrieved via either lookupType or lookupSingleton
+ // and both use QQmlTypeWrapper to store them.
+ // TODO: Wat? Looking up the singleton instances on each access is horribly inefficient.
+ // There is plenty of space in the lookup to store the instances.
+
+ Q_ASSERT(l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupType
+ || l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupSingleton);
+}
+
+bool AOTCompiledContext::loadAttachedLookup(uint index, QObject *object, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter != QV4::QObjectWrapper::lookupAttached)
return false;
- if (l->getter == QV4::QObjectWrapper::lookupGetter) {
- loadObjectProperty(l, object, target, type, qmlContext);
- return true;
- }
+ 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, QObject *object) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
QV4::Scope scope(engine->handle());
- QV4::ScopedValue o(scope, QV4::QObjectWrapper::wrap(scope.engine, object));
- QV4::ScopedValue result(scope, l->getter(l, scope.engine, o));
- if (type == QMetaType::fromType<QVariant>()) {
- // Special case QVariant in order to retain JS objects.
- // We don't want to convert JS arrays into QVariantList, for example.
- *static_cast<QVariant *>(target) = scope.engine->toVariant(result, QMetaType {});
- return true;
+ QV4::ScopedString name(scope, compilationUnit->runtimeStrings[l->nameIndex]);
+ QQmlTypeNameCache::Result r = qmlContext->imports()->query(name);
+
+ if (!r.isValid() || !r.type.isValid()) {
+ scope.engine->throwTypeError();
+ return;
}
- return scope.engine->metaTypeFromJS(result, type, target);
+
+ QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(
+ scope, QV4::QQmlTypeWrapper::create(scope.engine, object, r.type,
+ QV4::Heap::QQmlTypeWrapper::ExcludeEnums));
+
+ l->qmlTypeLookup.qmlTypeWrapper = wrapper->d();
+ l->getter = QV4::QObjectWrapper::lookupAttached;
}
-bool QQmlPrivate::AOTCompiledContext::getValueLookup(
- uint index, void *value, QMetaType valueType, void *target, QMetaType type) const
+bool AOTCompiledContext::getObjectLookup(uint index, QObject *object, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (!object) {
+ engine->handle()->throwTypeError(
+ QStringLiteral("Cannot read property '%1' of null")
+ .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ }
+
+ if (l->getter != QV4::QObjectWrapper::lookupGetter)
+ return false;
+
+ loadObjectProperty(l, object, target, qmlContext);
+ return true;
+}
+
+void AOTCompiledContext::initGetObjectLookup(uint index, QObject *object) const
+{
+ QV4::ExecutionEngine *v4 = engine->handle();
+ if (v4->hasException) {
+ amendException(v4);
+ } else {
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ initObjectLookup(this, l, object);
+ l->getter = QV4::QObjectWrapper::lookupGetter;
+ }
+}
+
+bool AOTCompiledContext::getValueLookup(uint index, void *value, void *target) const
{
Q_ASSERT(value);
@@ -858,129 +1135,96 @@ bool QQmlPrivate::AOTCompiledContext::getValueLookup(
= reinterpret_cast<const QMetaObject *>(l->qgadgetLookup.metaObject - 1);
Q_ASSERT(metaObject);
- // We cannot assert on anything here. You may even override the metaObject of Q_GADGET
- // types with the foreign/extended mechanism. See for example QQuickFontValueType.
- Q_UNUSED(valueType);
-
void *args[] = { target, nullptr };
- if (type == QMetaType::fromType<QVariant>())
- args[0] = transformVariant(target, QMetaType(l->qgadgetLookup.metaType));
- else if (type != QMetaType(l->qgadgetLookup.metaType))
- return false;
-
metaObject->d.static_metacall(
reinterpret_cast<QObject*>(value), QMetaObject::ReadProperty,
l->qgadgetLookup.coreIndex, args);
return true;
}
-QJSValue QQmlPrivate::AOTCompiledContext::callQmlContextPropertyLookup(
- uint index, const QJSValueList &args) const
-{
- QV4::Scope scope(engine->handle());
- const int argc = args.length();
- QV4::Value *argv = scope.alloc(args.length());
- for (int i = 0; i < argc; ++i)
- argv[i] = QJSValuePrivate::convertToReturnedValue(scope.engine, args.at(i));
- return QJSValuePrivate::fromReturnedValue(QV4::Runtime::CallQmlContextPropertyLookup::call(
- engine->handle(), index, argv, argc));
-}
-
-QJSValue QQmlPrivate::AOTCompiledContext::getLookup(uint index, const QJSValue &object) const
+void AOTCompiledContext::initGetValueLookup(uint index, const QMetaObject *metaObject) const
{
+ Q_ASSERT(!engine->hasError());
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
-
- if (object.isNull() || object.isUndefined()) {
- QString message = QStringLiteral("Cannot read property '%1' of %2")
- .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString(), object.toString());
- return QJSValuePrivate::fromReturnedValue(engine->handle()->throwTypeError(message));
- }
-
- return QJSValuePrivate::fromReturnedValue(
- l->getter(l, engine->handle(),
- QJSValuePrivate::convertToReturnedValue(engine->handle(), object)));
+ initValueLookup(l, compilationUnit, metaObject);
+ l->getter = QV4::QQmlValueTypeWrapper::lookupGetter;
}
-bool QQmlPrivate::AOTCompiledContext::captureLookup(uint index, QObject *object) const
+bool AOTCompiledContext::getEnumLookup(uint index, int *target) const
{
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- if (l->getter != QV4::QQmlTypeWrapper::lookupSingletonProperty
- && l->getter != QV4::QObjectWrapper::lookupGetter) {
+ if (l->getter != QV4::QQmlTypeWrapper::lookupEnumValue)
return false;
- }
-
- captureObjectProperty(
- object, l->qobjectLookup.propertyCache, l->qobjectLookup.propertyData, qmlContext);
+ *target = l->qmlEnumValueLookup.encodedEnumValue;
return true;
}
-void QQmlPrivate::AOTCompiledContext::setLookup(
- uint index, const QJSValue &object, const QJSValue &value) const
+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;
- QV4::Scope scope(engine->handle());
- QV4::ScopedValue o(scope, QJSValuePrivate::convertToReturnedValue(scope.engine, object));
- if (!l->setter(l, engine->handle(), *o,
- QJSValuePrivate::convertToReturnedValue(engine->handle(), value))) {
- engine->handle()->throwTypeError();
- }
+ Q_ASSERT(metaObject);
+ const int enumIndex = metaObject->indexOfEnumerator(enumerator);
+ const int value = metaObject->enumerator(enumIndex).keyToValue(enumValue);
+ l->qmlEnumValueLookup.encodedEnumValue = value;
+ l->getter = QV4::QQmlTypeWrapper::lookupEnumValue;
}
-QJSValue QQmlPrivate::AOTCompiledContext::callPropertyLookup(
- uint index, const QJSValue &object, const QJSValueList &args) const
+bool AOTCompiledContext::setObjectLookup(uint index, QObject *object, void *value) const
{
- QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- QV4::Scope scope(engine->handle());
- QV4::ScopedValue o(scope, QJSValuePrivate::convertToReturnedValue(scope.engine, object));
-
- // ok to have the value on the stack here
- QV4::Value f = QV4::Value::fromReturnedValue(l->getter(l, engine->handle(), o));
-
- if (Q_UNLIKELY(!f.isFunctionObject())) {
- QString message = QStringLiteral("Property '%1' of object %2 is not a function")
- .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString(),
- object.toString());
- engine->handle()->throwTypeError(message);
- return QJSValue();
+ if (!object) {
+ engine->handle()->throwTypeError(
+ QStringLiteral("Value is null and could not be converted to an object"));
+ return false;
}
- const int argc = args.length();
- QV4::Value *argv = scope.alloc(args.length());
- for (int i = 0; i < argc; ++i)
- argv[i] = QJSValuePrivate::convertToReturnedValue(scope.engine, args.at(i));
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->setter != QV4::QObjectWrapper::lookupSetter)
+ return false;
- return QJSValuePrivate::fromReturnedValue(
- static_cast<QV4::FunctionObject &>(f).call(o, argv, argc));
+ storeObjectProperty(l, object, value);
+ return true;
}
-QJSValue QQmlPrivate::AOTCompiledContext::callGlobalLookup(
- uint index, const QJSValueList &args) const
+void AOTCompiledContext::initSetObjectLookup(uint index, QObject *object) const
{
- QV4::Scope scope(engine->handle());
- QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- QV4::Value function = QV4::Value::fromReturnedValue(l->globalGetter(l, scope.engine));
- if (!function.isFunctionObject()) {
- const QString msg = QStringLiteral("Property '%1' of object [null] is not a function")
- .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString());
- return QJSValuePrivate::fromReturnedValue(scope.engine->throwTypeError(msg));
+ QV4::ExecutionEngine *v4 = engine->handle();
+ if (v4->hasException) {
+ amendException(v4);
+ } else {
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ initObjectLookup(this, l, object);
+ l->setter = QV4::QObjectWrapper::lookupSetter;
}
+}
- const int argc = args.length();
- QV4::Value *argv = scope.alloc(args.length());
- for (int i = 0; i < argc; ++i)
- argv[i] = QJSValuePrivate::convertToReturnedValue(scope.engine, args.at(i));
+bool AOTCompiledContext::setValueLookup(
+ uint index, void *target, void *value) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->setter != QV4::QQmlValueTypeWrapper::lookupSetter)
+ return false;
- QV4::Value thisObject = QV4::Value::undefinedValue();
- QV4::ReturnedValue result = static_cast<QV4::FunctionObject &>(function).call(
- &thisObject, argv, argc);
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qgadgetLookup.metaObject - 1);
- return scope.engine->hasException ? QJSValue() : QJSValuePrivate::fromReturnedValue(result);
+ void *args[] = { value, nullptr };
+ metaObject->d.static_metacall(
+ reinterpret_cast<QObject*>(target), QMetaObject::WriteProperty,
+ l->qgadgetLookup.coreIndex, args);
+ return true;
}
-QJSValue QQmlPrivate::AOTCompiledContext::loadGlobalLookup(uint index) const
+void AOTCompiledContext::initSetValueLookup(uint index, const QMetaObject *metaObject) const
{
+ Q_ASSERT(!engine->hasError());
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- return QJSValuePrivate::fromReturnedValue(l->globalGetter(l, engine->handle()));
+ initValueLookup(l, compilationUnit, metaObject);
+ l->setter = QV4::QQmlValueTypeWrapper::lookupSetter;
}
+} // namespace QQmlPrivate
+
QT_END_NAMESPACE