diff options
Diffstat (limited to 'src/qml/compiler/qqmltypecompiler.cpp')
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 1952 |
1 files changed, 390 insertions, 1562 deletions
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index caa4a55d3d..2308e66609 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -44,9 +44,10 @@ #include <private/qqmlcustomparser_p.h> #include <private/qqmlvmemetaobject_p.h> #include <private/qqmlcomponent_p.h> -#include <private/qqmlstringconverters_p.h> #include <private/qv4ssa_p.h> +#include "qqmlpropertycachecreator_p.h" + #define COMPILE_EXCEPTION(token, desc) \ { \ recordError((token)->location, desc); \ @@ -55,95 +56,35 @@ QT_BEGIN_NAMESPACE -QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *compiledData, QQmlTypeData *typeData, QmlIR::Document *parsedQML) - : engine(engine) - , compiledData(compiledData) +QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, + QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &importCache, + const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache) + : resolvedTypes(resolvedTypeCache) + , engine(engine) , typeData(typeData) + , importCache(importCache) , document(parsedQML) { } -bool QQmlTypeCompiler::compile() +QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile() { - compiledData->importCache = new QQmlTypeNameCache; - - foreach (const QString &ns, typeData->namespaces()) - compiledData->importCache->add(ns); - - // Add any Composite Singletons that were used to the import cache - foreach (const QQmlTypeData::TypeReference &singleton, typeData->compositeSingletons()) - compiledData->importCache->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix); - - typeData->imports().populateCache(compiledData->importCache); - - const QHash<int, QQmlTypeData::TypeReference> &resolvedTypes = typeData->resolvedTypeRefs(); - for (QHash<int, QQmlTypeData::TypeReference>::ConstIterator resolvedType = resolvedTypes.constBegin(), end = resolvedTypes.constEnd(); - resolvedType != end; ++resolvedType) { - QScopedPointer<QQmlCompiledData::TypeReference> ref(new QQmlCompiledData::TypeReference); - QQmlType *qmlType = resolvedType->type; - if (resolvedType->typeData) { - if (resolvedType->needsCreation && qmlType->isCompositeSingleton()) { - QQmlError error; - QString reason = tr("Composite Singleton Type %1 is not creatable.").arg(qmlType->qmlTypeName()); - error.setDescription(reason); - error.setColumn(resolvedType->location.column); - error.setLine(resolvedType->location.line); - recordError(error); - return false; - } - ref->component = resolvedType->typeData->compiledData(); - ref->component->addref(); - } else if (qmlType) { - ref->type = qmlType; - Q_ASSERT(ref->type); - - if (resolvedType->needsCreation && !ref->type->isCreatable()) { - QQmlError error; - QString reason = ref->type->noCreationReason(); - if (reason.isEmpty()) - reason = tr("Element is not creatable."); - error.setDescription(reason); - error.setColumn(resolvedType->location.column); - error.setLine(resolvedType->location.line); - recordError(error); - return false; - } - - if (ref->type->containsRevisionedAttributes()) { - ref->typePropertyCache = engine->cache(ref->type, - resolvedType->minorVersion); - if (!ref->typePropertyCache) { - QQmlError cacheError; - cacheError.setColumn(resolvedType->location.column); - cacheError.setLine(resolvedType->location.line); - recordError(cacheError); - return false; - } - ref->typePropertyCache->addref(); - } - } - ref->majorVersion = resolvedType->majorVersion; - ref->minorVersion = resolvedType->minorVersion; - ref->doDynamicTypeCheck(); - compiledData->resolvedTypes.insert(resolvedType.key(), ref.take()); - } - // Build property caches and VME meta object data - for (QHash<int, QQmlCompiledData::TypeReference*>::ConstIterator it = compiledData->resolvedTypes.constBegin(), end = compiledData->resolvedTypes.constEnd(); + for (auto it = resolvedTypes.constBegin(), end = resolvedTypes.constEnd(); it != end; ++it) { QQmlCustomParser *customParser = (*it)->type ? (*it)->type->customParser() : 0; if (customParser) customParsers.insert(it.key(), customParser); } - compiledData->metaObjects.reserve(document->objects.count()); - compiledData->propertyCaches.reserve(document->objects.count()); - { - QQmlPropertyCacheCreator propertyCacheBuilder(this); - if (!propertyCacheBuilder.buildMetaObjects()) - return false; + QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, engine, this, imports()); + QQmlCompileError error = propertyCacheBuilder.buildMetaObjects(); + if (error.isSet()) { + recordError(error); + return nullptr; + } } { @@ -154,13 +95,13 @@ bool QQmlTypeCompiler::compile() { SignalHandlerConverter converter(this); if (!converter.convertSignalHandlerExpressionsToFunctionDeclarations()) - return false; + return nullptr; } { QQmlEnumTypeResolver enumResolver(this); if (!enumResolver.resolveEnumBindings()) - return false; + return nullptr; } { @@ -173,34 +114,19 @@ bool QQmlTypeCompiler::compile() annotator.annotateBindingsToAliases(); } - // Collect imported scripts - const QList<QQmlTypeData::ScriptReference> &scripts = typeData->resolvedScripts(); - compiledData->scripts.reserve(scripts.count()); - for (int scriptIndex = 0; scriptIndex < scripts.count(); ++scriptIndex) { - const QQmlTypeData::ScriptReference &script = scripts.at(scriptIndex); - - QStringRef qualifier(&script.qualifier); - QString enclosingNamespace; - - const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.')); - if (lastDotIndex != -1) { - enclosingNamespace = qualifier.left(lastDotIndex).toString(); - qualifier = qualifier.mid(lastDotIndex+1); - } - - compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace); - QQmlScriptData *scriptData = script.script->scriptData(); - scriptData->addref(); - compiledData->scripts << scriptData; - } - // Resolve component boundaries and aliases { // Scan for components, determine their scopes and resolve aliases within the scope. QQmlComponentAndAliasResolver resolver(this); if (!resolver.resolve()) - return false; + return nullptr; + } + + { + QQmlDeferredAndCustomParserBindingScanner deferredAndCustomParserBindingScanner(this); + if (!deferredAndCustomParserBindingScanner.scanObject()) + return nullptr; } // Compile JS binding expressions and signal handlers @@ -212,10 +138,10 @@ bool QQmlTypeCompiler::compile() sss.scan(); } - QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, compiledData->importCache, &document->jsGenerator.stringTable); + QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, importCache, &document->jsGenerator.stringTable); QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator); if (!jsCodeGen.generateCodeForComponents()) - return false; + return nullptr; QQmlJavaScriptBindingExpressionSimplificationPass pass(this); pass.reduceTranslationBindings(); @@ -230,70 +156,45 @@ bool QQmlTypeCompiler::compile() // Generate QML compiled type data structures QmlIR::QmlUnitGenerator qmlGenerator; - QV4::CompiledData::Unit *qmlUnit = qmlGenerator.generate(*document); + QV4::CompiledData::Unit *qmlUnit = qmlGenerator.generate(*document, QQmlEnginePrivate::get(engine), resolvedTypes); Q_ASSERT(document->javaScriptCompilationUnit); // The js unit owns the data and will free the qml unit. document->javaScriptCompilationUnit->data = qmlUnit; - compiledData->compilationUnit = document->javaScriptCompilationUnit; - - // Add to type registry of composites - if (compiledData->isCompositeType()) - engine->registerInternalCompositeType(compiledData); - else { - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(qmlUnit->indexOfRootObject); - QQmlCompiledData::TypeReference *typeRef = compiledData->resolvedTypes.value(obj->inheritedTypeNameIndex); - Q_ASSERT(typeRef); - if (typeRef->component) { - compiledData->metaTypeId = typeRef->component->metaTypeId; - compiledData->listMetaTypeId = typeRef->component->listMetaTypeId; - } else { - compiledData->metaTypeId = typeRef->type->typeId(); - compiledData->listMetaTypeId = typeRef->type->qListTypeId(); - } - } - - // Sanity check property bindings - QQmlPropertyValidator validator(this); - if (!validator.validate()) - return false; + QV4::CompiledData::CompilationUnit *compilationUnit = document->javaScriptCompilationUnit; + compilationUnit = document->javaScriptCompilationUnit; + compilationUnit->importCache = importCache; + compilationUnit->resolvedTypes = resolvedTypes; + compilationUnit->propertyCaches = std::move(m_propertyCaches); + Q_ASSERT(compilationUnit->propertyCaches.count() == static_cast<int>(compilationUnit->data->nObjects)); - // Collect some data for instantiation later. - int bindingCount = 0; - int parserStatusCount = 0; - int objectCount = 0; - for (quint32 i = 0; i < qmlUnit->nObjects; ++i) { - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i); - bindingCount += obj->nBindings; - if (QQmlCompiledData::TypeReference *typeRef = compiledData->resolvedTypes.value(obj->inheritedTypeNameIndex)) { - if (QQmlType *qmlType = typeRef->type) { - if (qmlType->parserStatusCast() != -1) - ++parserStatusCount; - } - ++objectCount; - if (typeRef->component) { - bindingCount += typeRef->component->totalBindingsCount; - parserStatusCount += typeRef->component->totalParserStatusCount; - objectCount += typeRef->component->totalObjectCount; - } - } - } - compiledData->totalBindingsCount = bindingCount; - compiledData->totalParserStatusCount = parserStatusCount; - compiledData->totalObjectCount = objectCount; + if (errors.isEmpty()) + return compilationUnit; + else + return nullptr; +} - Q_ASSERT(compiledData->propertyCaches.count() == static_cast<int>(compiledData->compilationUnit->data->nObjects)); +void QQmlTypeCompiler::recordError(QQmlError error) +{ + error.setUrl(url()); + errors << error; +} - return errors.isEmpty(); +void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description) +{ + QQmlError error; + error.setLine(location.line); + error.setColumn(location.column); + error.setDescription(description); + error.setUrl(url()); + errors << error; } -void QQmlTypeCompiler::recordError(const QQmlError &error) +void QQmlTypeCompiler::recordError(const QQmlCompileError &error) { - QQmlError e = error; - e.setUrl(url()); - errors << e; + recordError(error.location, error.description); } QString QQmlTypeCompiler::stringAt(int idx) const @@ -313,7 +214,7 @@ QV4::IR::Module *QQmlTypeCompiler::jsIRModule() const const QV4::CompiledData::Unit *QQmlTypeCompiler::qmlUnit() const { - return compiledData->compilationUnit->data; + return document->javaScriptCompilationUnit->data; } const QQmlImports *QQmlTypeCompiler::imports() const @@ -321,12 +222,7 @@ const QQmlImports *QQmlTypeCompiler::imports() const return &typeData->imports(); } -QHash<int, QQmlCompiledData::TypeReference*> *QQmlTypeCompiler::resolvedTypes() -{ - return &compiledData->resolvedTypes; -} - -QList<QmlIR::Object *> *QQmlTypeCompiler::qmlObjects() +QVector<QmlIR::Object *> *QQmlTypeCompiler::qmlObjects() const { return &document->objects; } @@ -336,45 +232,20 @@ int QQmlTypeCompiler::rootObjectIndex() const return document->indexOfRootObject; } -void QQmlTypeCompiler::setPropertyCaches(const QVector<QQmlPropertyCache *> &caches) +void QQmlTypeCompiler::setPropertyCaches(QQmlPropertyCacheVector &&caches) { - compiledData->propertyCaches = caches; - Q_ASSERT(caches.count() >= document->indexOfRootObject); - if (compiledData->rootPropertyCache) - compiledData->rootPropertyCache->release(); - compiledData->rootPropertyCache = caches.at(document->indexOfRootObject); - compiledData->rootPropertyCache->addref(); + m_propertyCaches = std::move(caches); + Q_ASSERT(m_propertyCaches.count() >= document->indexOfRootObject); } -const QVector<QQmlPropertyCache *> &QQmlTypeCompiler::propertyCaches() const +const QQmlPropertyCacheVector *QQmlTypeCompiler::propertyCaches() const { - return compiledData->propertyCaches; + return &m_propertyCaches; } -void QQmlTypeCompiler::setVMEMetaObjects(const QVector<QByteArray> &metaObjects) +QQmlPropertyCacheVector &&QQmlTypeCompiler::takePropertyCaches() { - Q_ASSERT(compiledData->metaObjects.isEmpty()); - compiledData->metaObjects = metaObjects; -} - -QVector<QByteArray> *QQmlTypeCompiler::vmeMetaObjects() const -{ - return &compiledData->metaObjects; -} - -QHash<int, int> *QQmlTypeCompiler::objectIndexToIdForRoot() -{ - return &compiledData->objectIndexToIdForRoot; -} - -QHash<int, QHash<int, int> > *QQmlTypeCompiler::objectIndexToIdPerComponent() -{ - return &compiledData->objectIndexToIdPerComponent; -} - -QHash<int, QBitArray> *QQmlTypeCompiler::customParserBindings() -{ - return &compiledData->customParserBindings; + return std::move(m_propertyCaches); } QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool() @@ -392,14 +263,9 @@ const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const return &document->jsGenerator.stringTable; } -void QQmlTypeCompiler::setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject) -{ - compiledData->deferredBindingsPerObject = deferredBindingsPerObject; -} - void QQmlTypeCompiler::setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData) { - compiledData->compilationUnit->bindingPropertyDataPerObject = propertyData; + document->javaScriptCompilationUnit->bindingPropertyDataPerObject = propertyData; } QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scriptIndex) const @@ -407,499 +273,34 @@ QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scrip return object->bindingAsString(document, scriptIndex); } -QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler) - : compiler(typeCompiler) -{ -} - -void QQmlCompilePass::recordError(const QV4::CompiledData::Location &location, const QString &description) const -{ - QQmlError error; - error.setLine(location.line); - error.setColumn(location.column); - error.setDescription(description); - compiler->recordError(error); -} - -static QAtomicInt classIndexCounter(0); - -QQmlPropertyCacheCreator::QQmlPropertyCacheCreator(QQmlTypeCompiler *typeCompiler) - : QQmlCompilePass(typeCompiler) - , enginePrivate(typeCompiler->enginePrivate()) - , qmlObjects(*typeCompiler->qmlObjects()) - , imports(typeCompiler->imports()) - , resolvedTypes(typeCompiler->resolvedTypes()) -{ -} - -QQmlPropertyCacheCreator::~QQmlPropertyCacheCreator() -{ - for (int i = 0; i < propertyCaches.count(); ++i) - if (QQmlPropertyCache *cache = propertyCaches.at(i)) - cache->release(); - propertyCaches.clear(); -} - -bool QQmlPropertyCacheCreator::buildMetaObjects() -{ - propertyCaches.resize(qmlObjects.count()); - vmeMetaObjects.resize(qmlObjects.count()); - - if (!buildMetaObjectRecursively(compiler->rootObjectIndex(), /*referencing object*/-1, /*instantiating binding*/0)) - return false; - - compiler->setVMEMetaObjects(vmeMetaObjects); - compiler->setPropertyCaches(propertyCaches); - propertyCaches.clear(); - - return true; -} - -bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding) +void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion) { - const QmlIR::Object *obj = qmlObjects.at(objectIndex); - - QQmlPropertyCache *baseTypeCache = 0; - QQmlPropertyData *instantiatingProperty = 0; - if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) { - Q_ASSERT(referencingObjectIndex >= 0); - QQmlPropertyCache *parentCache = propertyCaches.at(referencingObjectIndex); - Q_ASSERT(parentCache); - Q_ASSERT(instantiatingBinding->propertyNameIndex != 0); - - bool notInRevision = false; - instantiatingProperty = QmlIR::PropertyResolver(parentCache).property(stringAt(instantiatingBinding->propertyNameIndex), ¬InRevision); - if (instantiatingProperty) { - if (instantiatingProperty->isQObject()) { - baseTypeCache = enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType); - Q_ASSERT(baseTypeCache); - } else if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(instantiatingProperty->propType)) { - baseTypeCache = enginePrivate->cache(vtmo); - Q_ASSERT(baseTypeCache); - } - } - } - - bool needVMEMetaObject = obj->propertyCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0; - if (!needVMEMetaObject) { - for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { - if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) { - - // On assignments are implemented using value interceptors, which require a VME meta object. - needVMEMetaObject = true; - - // If the on assignment is inside a group property, we need to distinguish between QObject based - // group properties and value type group properties. For the former the base type is derived from - // the property that references us, for the latter we only need a meta-object on the referencing object - // because interceptors can't go to the shared value type instances. - if (instantiatingProperty && QQmlValueTypeFactory::isValueType(instantiatingProperty->propType)) { - needVMEMetaObject = false; - if (!ensureMetaObject(referencingObjectIndex)) - return false; - } - break; - } - } - } - - if (obj->inheritedTypeNameIndex != 0) { - QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex); - Q_ASSERT(typeRef); - - if (typeRef->isFullyDynamicType) { - if (obj->propertyCount() > 0) { - recordError(obj->location, tr("Fully dynamic types cannot declare new properties.")); - return false; - } - if (obj->signalCount() > 0) { - recordError(obj->location, tr("Fully dynamic types cannot declare new signals.")); - return false; - } - if (obj->functionCount() > 0) { - recordError(obj->location, tr("Fully Dynamic types cannot declare new functions.")); - return false; - } - } - - baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); - Q_ASSERT(baseTypeCache); - } else if (instantiatingBinding && instantiatingBinding->isAttachedProperty()) { - QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(instantiatingBinding->propertyNameIndex); - Q_ASSERT(typeRef); - QQmlType *qmltype = typeRef->type; - if (!qmltype) { - QString propertyName = stringAt(instantiatingBinding->propertyNameIndex); - if (imports->resolveType(propertyName, &qmltype, 0, 0, 0)) { - if (qmltype->isComposite()) { - QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl()); - Q_ASSERT(tdata); - Q_ASSERT(tdata->isComplete()); - - QQmlCompiledData *data = tdata->compiledData(); - qmltype = QQmlMetaType::qmlType(data->metaTypeId); - - tdata->release(); - } - } - } + const quint32 moduleIdx = registerString(module); + const quint32 qualifierIdx = registerString(qualifier); - const QMetaObject *attachedMo = qmltype ? qmltype->attachedPropertiesType(enginePrivate) : 0; - if (!attachedMo) { - recordError(instantiatingBinding->location, tr("Non-existent attached object")); - return false; - } - baseTypeCache = enginePrivate->cache(attachedMo); - Q_ASSERT(baseTypeCache); - } - - if (baseTypeCache) { - if (needVMEMetaObject) { - if (!createMetaObject(objectIndex, obj, baseTypeCache)) - return false; - } else { - propertyCaches[objectIndex] = baseTypeCache; - baseTypeCache->addref(); - } - } - - if (propertyCaches.at(objectIndex)) { - for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) - if (binding->type >= QV4::CompiledData::Binding::Type_Object) { - if (!buildMetaObjectRecursively(binding->value.objectIndex, objectIndex, binding)) - return false; - } + for (int i = 0, count = document->imports.count(); i < count; ++i) { + const QV4::CompiledData::Import *existingImport = document->imports.at(i); + if (existingImport->type == QV4::CompiledData::Import::ImportLibrary + && existingImport->uriIndex == moduleIdx + && existingImport->qualifierIndex == qualifierIdx) + return; } - - return true; + auto pool = memoryPool(); + QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>(); + import->type = QV4::CompiledData::Import::ImportLibrary; + import->majorVersion = majorVersion; + import->minorVersion = minorVersion; + import->uriIndex = moduleIdx; + import->qualifierIndex = qualifierIdx; + document->imports.append(import); } -bool QQmlPropertyCacheCreator::ensureMetaObject(int objectIndex) +QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler) + : compiler(typeCompiler) { - if (!vmeMetaObjects.at(objectIndex).isEmpty()) - return true; - const QmlIR::Object *obj = qmlObjects.at(objectIndex); - QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex); - Q_ASSERT(typeRef); - QQmlPropertyCache *baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); - return createMetaObject(objectIndex, obj, baseTypeCache); -} - -bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Object *obj, QQmlPropertyCache *baseTypeCache) -{ - QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(obj->propertyCount(), - obj->functionCount() + obj->propertyCount() + obj->signalCount(), - obj->signalCount() + obj->propertyCount()); - propertyCaches[objectIndex] = cache; - - struct TypeData { - QV4::CompiledData::Property::Type dtype; - int metaType; - } builtinTypes[] = { - { QV4::CompiledData::Property::Var, QMetaType::QVariant }, - { QV4::CompiledData::Property::Variant, QMetaType::QVariant }, - { QV4::CompiledData::Property::Int, QMetaType::Int }, - { QV4::CompiledData::Property::Bool, QMetaType::Bool }, - { QV4::CompiledData::Property::Real, QMetaType::Double }, - { QV4::CompiledData::Property::String, QMetaType::QString }, - { QV4::CompiledData::Property::Url, QMetaType::QUrl }, - { QV4::CompiledData::Property::Color, QMetaType::QColor }, - { QV4::CompiledData::Property::Font, QMetaType::QFont }, - { QV4::CompiledData::Property::Time, QMetaType::QTime }, - { QV4::CompiledData::Property::Date, QMetaType::QDate }, - { QV4::CompiledData::Property::DateTime, QMetaType::QDateTime }, - { QV4::CompiledData::Property::Rect, QMetaType::QRectF }, - { QV4::CompiledData::Property::Point, QMetaType::QPointF }, - { QV4::CompiledData::Property::Size, QMetaType::QSizeF }, - { QV4::CompiledData::Property::Vector2D, QMetaType::QVector2D }, - { QV4::CompiledData::Property::Vector3D, QMetaType::QVector3D }, - { QV4::CompiledData::Property::Vector4D, QMetaType::QVector4D }, - { QV4::CompiledData::Property::Matrix4x4, QMetaType::QMatrix4x4 }, - { QV4::CompiledData::Property::Quaternion, QMetaType::QQuaternion } - }; - static const uint builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData); - - QByteArray newClassName; - - if (objectIndex == compiler->rootObjectIndex()) { - QString path = compiler->url().path(); - int lastSlash = path.lastIndexOf(QLatin1Char('/')); - if (lastSlash > -1) { - const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5); - if (!nameBase.isEmpty() && nameBase.at(0).isUpper()) - newClassName = nameBase.toUtf8() + "_QMLTYPE_" + - QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)); - } - } - if (newClassName.isEmpty()) { - newClassName = QQmlMetaObject(baseTypeCache).className(); - newClassName.append("_QML_"); - newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1))); - } - - cache->_dynamicClassName = newClassName; - - int aliasCount = 0; - int varPropCount = 0; - - QmlIR::PropertyResolver resolver(baseTypeCache); - - for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) { - if (p->type == QV4::CompiledData::Property::Alias) - aliasCount++; - else if (p->type == QV4::CompiledData::Property::Var) - varPropCount++; - - // No point doing this for both the alias and non alias cases - bool notInRevision = false; - QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), ¬InRevision); - if (d && d->isFinal()) - COMPILE_EXCEPTION(p, tr("Cannot override FINAL property")); - } - - typedef QQmlVMEMetaData VMD; - - QByteArray &dynamicData = vmeMetaObjects[objectIndex] = QByteArray(sizeof(QQmlVMEMetaData) - + obj->propertyCount() * sizeof(VMD::PropertyData) - + obj->functionCount() * sizeof(VMD::MethodData) - + aliasCount * sizeof(VMD::AliasData), 0); - - int effectivePropertyIndex = cache->propertyIndexCacheStart; - int effectiveMethodIndex = cache->methodIndexCacheStart; - - // For property change signal override detection. - // We prepopulate a set of signal names which already exist in the object, - // and throw an error if there is a signal/method defined as an override. - QSet<QString> seenSignals; - seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged"); - QQmlPropertyCache *parentCache = cache; - while ((parentCache = parentCache->parent())) { - if (int pSigCount = parentCache->signalCount()) { - int pSigOffset = parentCache->signalOffset(); - for (int i = pSigOffset; i < pSigCount; ++i) { - QQmlPropertyData *currPSig = parentCache->signal(i); - // XXX TODO: find a better way to get signal name from the property data :-/ - for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin(); - iter != parentCache->stringCache.end(); ++iter) { - if (currPSig == (*iter).second) { - seenSignals.insert(iter.key()); - break; - } - } - } - } - } - - // First set up notify signals for properties - first normal, then var, then alias - enum { NSS_Normal = 0, NSS_Alias = 1 }; - for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias - - if (ii == NSS_Alias && aliasCount == 0) continue; - - for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) { - if ((ii == NSS_Normal && p->type == QV4::CompiledData::Property::Alias) || - (ii == NSS_Alias && p->type != QV4::CompiledData::Property::Alias)) - continue; - - quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | - QQmlPropertyData::IsVMESignal; - - QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed"); - seenSignals.insert(changedSigName); - - cache->appendSignal(changedSigName, flags, effectiveMethodIndex++); - } - } - - // Dynamic signals - for (const QmlIR::Signal *s = obj->firstSignal(); s; s = s->next) { - const int paramCount = s->parameters->count; - - QList<QByteArray> names; - names.reserve(paramCount); - QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0); - - if (paramCount) { - paramTypes[0] = paramCount; - - QmlIR::SignalParameter *param = s->parameters->first; - for (int i = 0; i < paramCount; ++i, param = param->next) { - names.append(stringAt(param->nameIndex).toUtf8()); - if (param->type < builtinTypeCount) { - // built-in type - paramTypes[i + 1] = builtinTypes[param->type].metaType; - } else { - // lazily resolved type - Q_ASSERT(param->type == QV4::CompiledData::Property::Custom); - const QString customTypeName = stringAt(param->customTypeNameIndex); - QQmlType *qmltype = 0; - if (!imports->resolveType(customTypeName, &qmltype, 0, 0, 0)) - COMPILE_EXCEPTION(s, tr("Invalid signal parameter type: %1").arg(customTypeName)); - - if (qmltype->isComposite()) { - QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl()); - Q_ASSERT(tdata); - Q_ASSERT(tdata->isComplete()); - - QQmlCompiledData *data = tdata->compiledData(); - - paramTypes[i + 1] = data->metaTypeId; - - tdata->release(); - } else { - paramTypes[i + 1] = qmltype->typeId(); - } - } - } - } - - ((QQmlVMEMetaData *)dynamicData.data())->signalCount++; - - quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | - QQmlPropertyData::IsVMESignal; - if (paramCount) - flags |= QQmlPropertyData::HasArguments; - - QString signalName = stringAt(s->nameIndex); - if (seenSignals.contains(signalName)) - COMPILE_EXCEPTION(s, tr("Duplicate signal name: invalid override of property change signal or superclass signal")); - seenSignals.insert(signalName); - - cache->appendSignal(signalName, flags, effectiveMethodIndex++, - paramCount?paramTypes.constData():0, names); - } - - - // Dynamic slots - for (const QmlIR::Function *s = obj->firstFunction(); s; s = s->next) { - QQmlJS::AST::FunctionDeclaration *astFunction = s->functionDeclaration; - - quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction; - - if (astFunction->formals) - flags |= QQmlPropertyData::HasArguments; - - QString slotName = astFunction->name.toString(); - if (seenSignals.contains(slotName)) - COMPILE_EXCEPTION(s, tr("Duplicate method name: invalid override of property change signal or superclass signal")); - // Note: we don't append slotName to the seenSignals list, since we don't - // protect against overriding change signals or methods with properties. - - QList<QByteArray> parameterNames; - QQmlJS::AST::FormalParameterList *param = astFunction->formals; - while (param) { - parameterNames << param->name.toUtf8(); - param = param->next; - } - - cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames); - } - - - // Dynamic properties (except var and aliases) - int effectiveSignalIndex = cache->signalHandlerIndexCacheStart; - int propertyIdx = 0; - for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) { - - if (p->type == QV4::CompiledData::Property::Alias) - continue; - - int propertyType = 0; - int vmePropertyType = 0; - quint32 propertyFlags = 0; - - if (p->type == QV4::CompiledData::Property::Var) { - propertyType = QMetaType::QVariant; - vmePropertyType = QQmlVMEMetaData::VarPropertyType; - propertyFlags = QQmlPropertyData::IsVarProperty; - } else if (p->type < builtinTypeCount) { - propertyType = builtinTypes[p->type].metaType; - vmePropertyType = propertyType; - - if (p->type == QV4::CompiledData::Property::Variant) - propertyFlags |= QQmlPropertyData::IsQVariant; - } else { - Q_ASSERT(p->type == QV4::CompiledData::Property::CustomList || - p->type == QV4::CompiledData::Property::Custom); - - QQmlType *qmltype = 0; - if (!imports->resolveType(stringAt(p->customTypeNameIndex), &qmltype, 0, 0, 0)) { - COMPILE_EXCEPTION(p, tr("Invalid property type")); - } - - Q_ASSERT(qmltype); - if (qmltype->isComposite()) { - QQmlTypeData *tdata = enginePrivate->typeLoader.getType(qmltype->sourceUrl()); - Q_ASSERT(tdata); - Q_ASSERT(tdata->isComplete()); - - QQmlCompiledData *data = tdata->compiledData(); - - if (p->type == QV4::CompiledData::Property::Custom) { - propertyType = data->metaTypeId; - vmePropertyType = QMetaType::QObjectStar; - } else { - propertyType = data->listMetaTypeId; - vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >(); - } - - tdata->release(); - } else { - if (p->type == QV4::CompiledData::Property::Custom) { - propertyType = qmltype->typeId(); - vmePropertyType = QMetaType::QObjectStar; - } else { - propertyType = qmltype->qListTypeId(); - vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >(); - } - } - - if (p->type == QV4::CompiledData::Property::Custom) - propertyFlags |= QQmlPropertyData::IsQObjectDerived; - else - propertyFlags |= QQmlPropertyData::IsQList; - } - - if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && p->type != QV4::CompiledData::Property::CustomList) - propertyFlags |= QQmlPropertyData::IsWritable; - - - QString propertyName = stringAt(p->nameIndex); - if (propertyIdx == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName; - cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, - propertyType, effectiveSignalIndex); - - effectiveSignalIndex++; - - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType; - vmd->propertyCount++; - } - - // Alias property count. Actual data is setup in buildDynamicMetaAliases - ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount; - - // Dynamic slot data - comes after the property data - for (const QmlIR::Function *s = obj->firstFunction(); s; s = s->next) { - QQmlJS::AST::FunctionDeclaration *astFunction = s->functionDeclaration; - int formalsCount = 0; - QQmlJS::AST::FormalParameterList *param = astFunction->formals; - while (param) { - formalsCount++; - param = param->next; - } - - VMD::MethodData methodData = { /* runtimeFunctionIndex*/ 0, // ### - formalsCount, - /* s->location.start.line */0 }; // ### +} - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount); - vmd->methodCount++; - md = methodData; - } - return true; -} SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler) : QQmlCompilePass(typeCompiler) @@ -907,7 +308,7 @@ SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler) , qmlObjects(*typeCompiler->qmlObjects()) , imports(typeCompiler->imports()) , customParsers(typeCompiler->customParserCache()) - , resolvedTypes(*typeCompiler->resolvedTypes()) + , resolvedTypes(typeCompiler->resolvedTypes) , illegalNames(QV8Engine::get(QQmlEnginePrivate::get(typeCompiler->enginePrivate()))->illegalNames()) , propertyCaches(typeCompiler->propertyCaches()) { @@ -917,7 +318,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio { for (int objectIndex = 0; objectIndex < qmlObjects.count(); ++objectIndex) { const QmlIR::Object * const obj = qmlObjects.at(objectIndex); - QQmlPropertyCache *cache = propertyCaches.at(objectIndex); + QQmlPropertyCache *cache = propertyCaches->at(objectIndex); if (!cache) continue; if (QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex)) { @@ -941,7 +342,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio // Attached property? if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex); - QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(binding->propertyNameIndex); + auto *typeRef = resolvedTypes.value(binding->propertyNameIndex); QQmlType *type = typeRef ? typeRef->type : 0; if (!type) { if (imports->resolveType(propertyName, &type, 0, 0, 0)) { @@ -950,8 +351,8 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio Q_ASSERT(tdata); Q_ASSERT(tdata->isComplete()); - QQmlCompiledData *data = tdata->compiledData(); - type = QQmlMetaType::qmlType(data->metaTypeId); + auto compilationUnit = tdata->compilationUnit(); + type = QQmlMetaType::qmlType(compilationUnit->metaTypeId); tdata->release(); } @@ -989,7 +390,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio bool notInRevision = false; QQmlPropertyData *signal = resolver.signal(propertyName, ¬InRevision); if (signal) { - int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex); + int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex()); sigIndex = propertyCache->originalClone(sigIndex); bool unnamedParameter = false; @@ -1014,7 +415,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio const QString &originalPropertyName = stringAt(binding->propertyNameIndex); - QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); + auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); const QQmlType *type = typeRef ? typeRef->type : 0; if (type) { COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(originalPropertyName).arg(type->module()).arg(type->majorVersion()).arg(type->minorVersion())); @@ -1118,14 +519,14 @@ QQmlEnumTypeResolver::QQmlEnumTypeResolver(QQmlTypeCompiler *typeCompiler) , qmlObjects(*typeCompiler->qmlObjects()) , propertyCaches(typeCompiler->propertyCaches()) , imports(typeCompiler->imports()) - , resolvedTypes(typeCompiler->resolvedTypes()) + , resolvedTypes(&typeCompiler->resolvedTypes) { } bool QQmlEnumTypeResolver::resolveEnumBindings() { for (int i = 0; i < qmlObjects.count(); ++i) { - QQmlPropertyCache *propertyCache = propertyCaches.at(i); + QQmlPropertyCache *propertyCache = propertyCaches->at(i); if (!propertyCache) continue; const QmlIR::Object *obj = qmlObjects.at(i); @@ -1146,7 +547,7 @@ bool QQmlEnumTypeResolver::resolveEnumBindings() if (!pd) continue; - if (!pd->isEnum() && pd->propType != QMetaType::Int) + if (!pd->isEnum() && pd->propType() != QMetaType::Int) continue; if (!tryQualifiedEnumAssignment(obj, propertyCache, pd, binding)) @@ -1169,14 +570,14 @@ bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QS COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName.toString())); } binding->type = QV4::CompiledData::Binding::Type_Number; - binding->value.d = (double)enumValue; + binding->setNumberValueInternal((double)enumValue); binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum; return true; } bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, QmlIR::Binding *binding) { - bool isIntProp = (prop->propType == QMetaType::Int) && !prop->isEnum(); + bool isIntProp = (prop->propType() == QMetaType::Int) && !prop->isEnum(); if (!prop->isEnum() && !isIntProp) return true; @@ -1218,9 +619,9 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, int value = 0; bool ok = false; - QQmlCompiledData::TypeReference *tr = resolvedTypes->value(obj->inheritedTypeNameIndex); + auto *tr = resolvedTypes->value(obj->inheritedTypeNameIndex); if (type && tr && tr->type == type) { - QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex); + QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex()); // When these two match, we can short cut the search if (mprop.isFlagType()) { @@ -1311,20 +712,20 @@ QQmlAliasAnnotator::QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler) void QQmlAliasAnnotator::annotateBindingsToAliases() { for (int i = 0; i < qmlObjects.count(); ++i) { - QQmlPropertyCache *propertyCache = propertyCaches.at(i); + QQmlPropertyCache *propertyCache = propertyCaches->at(i); if (!propertyCache) continue; const QmlIR::Object *obj = qmlObjects.at(i); QmlIR::PropertyResolver resolver(propertyCache); - QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); + QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (!binding->isValueBinding()) continue; bool notInRevision = false; - QQmlPropertyData *pd = binding->propertyNameIndex != 0 ? resolver.property(stringAt(binding->propertyNameIndex), ¬InRevision) : defaultProperty; + QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), ¬InRevision) : defaultProperty; if (pd && pd->isAlias()) binding->flags |= QV4::CompiledData::Binding::IsBindingToAlias; } @@ -1343,21 +744,21 @@ void QQmlScriptStringScanner::scan() { const int scriptStringMetaType = qMetaTypeId<QQmlScriptString>(); for (int i = 0; i < qmlObjects.count(); ++i) { - QQmlPropertyCache *propertyCache = propertyCaches.at(i); + QQmlPropertyCache *propertyCache = propertyCaches->at(i); if (!propertyCache) continue; const QmlIR::Object *obj = qmlObjects.at(i); QmlIR::PropertyResolver resolver(propertyCache); - QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); + QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (binding->type != QV4::CompiledData::Binding::Type_Script) continue; bool notInRevision = false; - QQmlPropertyData *pd = binding->propertyNameIndex != 0 ? resolver.property(stringAt(binding->propertyNameIndex), ¬InRevision) : defaultProperty; - if (!pd || pd->propType != scriptStringMetaType) + QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), ¬InRevision) : defaultProperty; + if (!pd || pd->propType() != scriptStringMetaType) continue; QmlIR::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex); @@ -1376,13 +777,8 @@ QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *t , pool(typeCompiler->memoryPool()) , qmlObjects(typeCompiler->qmlObjects()) , indexOfRootObject(typeCompiler->rootObjectIndex()) - , _componentIndex(-1) - , _objectIndexToIdInScope(0) - , resolvedTypes(typeCompiler->resolvedTypes()) - , propertyCaches(typeCompiler->propertyCaches()) - , vmeMetaObjectData(typeCompiler->vmeMetaObjects()) - , objectIndexToIdForRoot(typeCompiler->objectIndexToIdForRoot()) - , objectIndexToIdPerComponent(typeCompiler->objectIndexToIdPerComponent()) + , resolvedTypes(&typeCompiler->resolvedTypes) + , propertyCaches(std::move(typeCompiler->takePropertyCaches())) { } @@ -1390,7 +786,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI { QmlIR::PropertyResolver propertyResolver(propertyCache); - QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); + QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (binding->type != QV4::CompiledData::Binding::Type_Object) @@ -1399,18 +795,18 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI continue; const QmlIR::Object *targetObject = qmlObjects->at(binding->value.objectIndex); - QQmlCompiledData::TypeReference *tr = resolvedTypes->value(targetObject->inheritedTypeNameIndex); + auto *tr = resolvedTypes->value(targetObject->inheritedTypeNameIndex); Q_ASSERT(tr); if (QQmlType *targetType = tr->type) { if (targetType->metaObject() == &QQmlComponent::staticMetaObject) continue; - } else if (tr->component) { - if (tr->component->rootPropertyCache->firstCppMetaObject() == &QQmlComponent::staticMetaObject) + } else if (tr->compilationUnit) { + if (tr->compilationUnit->rootPropertyCache()->firstCppMetaObject() == &QQmlComponent::staticMetaObject) continue; } QQmlPropertyData *pd = 0; - if (binding->propertyNameIndex != 0) { + if (binding->propertyNameIndex != quint32(0)) { bool notInRevision = false; pd = propertyResolver.property(stringAt(binding->propertyNameIndex), ¬InRevision); } else { @@ -1419,7 +815,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI if (!pd || !pd->isQObject()) continue; - QQmlPropertyCache *pc = enginePrivate->rawPropertyCacheForType(pd->propType); + QQmlPropertyCache *pc = enginePrivate->rawPropertyCacheForType(pd->propType()); const QMetaObject *mo = pc ? pc->firstCppMetaObject() : 0; while (mo) { if (mo == &QQmlComponent::staticMetaObject) @@ -1430,15 +826,20 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI if (!mo) continue; + // emulate "import Qml 2.0 as QmlInternals" and then wrap the component in "QmlInternals.Component {}" QQmlType *componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject); Q_ASSERT(componentType); + const QString qualifier = QStringLiteral("QmlInternals"); + + compiler->addImport(componentType->module(), qualifier, componentType->majorVersion(), componentType->minorVersion()); QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>(); - syntheticComponent->init(pool, compiler->registerString(QString::fromUtf8(componentType->typeName())), compiler->registerString(QString())); + syntheticComponent->init(pool, compiler->registerString(qualifier + QLatin1Char('.') + componentType->elementName()), compiler->registerString(QString())); syntheticComponent->location = binding->valueLocation; + syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent; if (!resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) { - QQmlCompiledData::TypeReference *typeRef = new QQmlCompiledData::TypeReference; + auto typeRef = new QV4::CompiledData::ResolvedTypeReference; typeRef->type = componentType; typeRef->majorVersion = componentType->majorVersion(); typeRef->minorVersion = componentType->minorVersion(); @@ -1449,7 +850,6 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI const int componentIndex = qmlObjects->count() - 1; // Keep property caches symmetric QQmlPropertyCache *componentCache = enginePrivate->cache(&QQmlComponent::staticMetaObject); - componentCache->addref(); propertyCaches.append(componentCache); QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>(); @@ -1462,7 +862,6 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI binding->value.objectIndex = componentIndex; componentRoots.append(componentIndex); - componentBoundaries.append(syntheticBinding->value.objectIndex); } } @@ -1474,7 +873,7 @@ bool QQmlComponentAndAliasResolver::resolve() // on the left hand side is of QQmlComponent type. const int objCountWithoutSynthesizedComponents = qmlObjects->count(); for (int i = 0; i < objCountWithoutSynthesizedComponents; ++i) { - const QmlIR::Object *obj = qmlObjects->at(i); + QmlIR::Object *obj = qmlObjects->at(i); QQmlPropertyCache *cache = propertyCaches.at(i); if (obj->inheritedTypeNameIndex == 0 && !cache) continue; @@ -1482,7 +881,7 @@ bool QQmlComponentAndAliasResolver::resolve() bool isExplicitComponent = false; if (obj->inheritedTypeNameIndex) { - QQmlCompiledData::TypeReference *tref = resolvedTypes->value(obj->inheritedTypeNameIndex); + auto *tref = resolvedTypes->value(obj->inheritedTypeNameIndex); Q_ASSERT(tref); if (tref->type && tref->type->metaObject() == &QQmlComponent::staticMetaObject) isExplicitComponent = true; @@ -1493,11 +892,11 @@ bool QQmlComponentAndAliasResolver::resolve() continue; } - componentRoots.append(i); + obj->flags |= QV4::CompiledData::Object::IsComponent; if (obj->functionCount() > 0) COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions.")); - if (obj->propertyCount() > 0) + if (obj->propertyCount() > 0 || obj->aliasCount() > 0) COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties.")); if (obj->signalCount() > 0) COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals.")); @@ -1515,65 +914,69 @@ bool QQmlComponentAndAliasResolver::resolve() if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object) COMPILE_EXCEPTION(obj, tr("Invalid component body specification")); - componentBoundaries.append(rootBinding->value.objectIndex); - } + // We are going to collect ids/aliases and resolve them for the root object as a separate + // last pass. + if (i != indexOfRootObject) + componentRoots.append(i); - std::sort(componentBoundaries.begin(), componentBoundaries.end()); + } for (int i = 0; i < componentRoots.count(); ++i) { - const QmlIR::Object *component = qmlObjects->at(componentRoots.at(i)); + QmlIR::Object *component = qmlObjects->at(componentRoots.at(i)); const QmlIR::Binding *rootBinding = component->firstBinding(); - _componentIndex = i; _idToObjectIndex.clear(); - _objectIndexToIdInScope = &(*objectIndexToIdPerComponent)[componentRoots.at(i)]; - _objectsWithAliases.clear(); if (!collectIdsAndAliases(rootBinding->value.objectIndex)) return false; - if (!resolveAliases()) + component->namedObjectsInComponent.allocate(pool, _idToObjectIndex); + + if (!resolveAliases(componentRoots.at(i))) return false; } // Collect ids and aliases for root - _componentIndex = -1; _idToObjectIndex.clear(); - _objectIndexToIdInScope = objectIndexToIdForRoot; _objectsWithAliases.clear(); collectIdsAndAliases(indexOfRootObject); - resolveAliases(); + QmlIR::Object *rootComponent = qmlObjects->at(indexOfRootObject); + rootComponent->namedObjectsInComponent.allocate(pool, _idToObjectIndex); + + if (!resolveAliases(indexOfRootObject)) + return false; // Implicit component insertion may have added objects and thus we also need // to extend the symmetric propertyCaches. - compiler->setPropertyCaches(propertyCaches); + compiler->setPropertyCaches(std::move(propertyCaches)); + compiler->setComponentRoots(componentRoots); return true; } bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex) { - const QmlIR::Object *obj = qmlObjects->at(objectIndex); + QmlIR::Object *obj = qmlObjects->at(objectIndex); - if (obj->idIndex != 0) { - if (_idToObjectIndex.contains(obj->idIndex)) { + if (obj->idNameIndex != 0) { + if (_idToObjectIndex.contains(obj->idNameIndex)) { recordError(obj->locationOfIdProperty, tr("id is not unique")); return false; } - _idToObjectIndex.insert(obj->idIndex, objectIndex); - _objectIndexToIdInScope->insert(objectIndex, _objectIndexToIdInScope->count()); + obj->id = _idToObjectIndex.count(); + _idToObjectIndex.insert(obj->idNameIndex, objectIndex); } - for (const QmlIR::Property *property = obj->firstProperty(); property; property = property->next) { - if (property->type == QV4::CompiledData::Property::Alias) { - _objectsWithAliases.append(objectIndex); - break; - } - } + if (obj->aliasCount() > 0) + _objectsWithAliases.append(objectIndex); + + // Stop at Component boundary + if (obj->flags & QV4::CompiledData::Object::IsComponent && objectIndex != compiler->rootObjectIndex()) + return true; for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (binding->type != QV4::CompiledData::Binding::Type_Object @@ -1581,10 +984,6 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex) && binding->type != QV4::CompiledData::Binding::Type_GroupProperty) continue; - // Stop at Component boundary - if (std::binary_search(componentBoundaries.constBegin(), componentBoundaries.constEnd(), binding->value.objectIndex)) - continue; - if (!collectIdsAndAliases(binding->value.objectIndex)) return false; } @@ -1592,257 +991,205 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex) return true; } -bool QQmlComponentAndAliasResolver::resolveAliases() +bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex) { - foreach (int objectIndex, _objectsWithAliases) { - const QmlIR::Object *obj = qmlObjects->at(objectIndex); + if (_objectsWithAliases.isEmpty()) + return true; - QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex); - Q_ASSERT(propertyCache); + QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> aliasCacheCreator(&propertyCaches, compiler); - int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count(); - int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count(); - int effectiveAliasIndex = 0; + bool atLeastOneAliasResolved; + do { + atLeastOneAliasResolved = false; + QVector<int> pendingObjects; - const QmlIR::Property *p = obj->firstProperty(); - for (int propertyIndex = 0; propertyIndex < obj->propertyCount(); ++propertyIndex, p = p->next) { - if (p->type != QV4::CompiledData::Property::Alias) - continue; + for (int objectIndex: qAsConst(_objectsWithAliases)) { - const int idIndex = p->aliasIdValueIndex; - const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1); - if (targetObjectIndex == -1) { - recordError(p->aliasLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex))); + QQmlCompileError error; + const auto result = resolveAliasesInObject(objectIndex, &error); + + if (error.isSet()) { + recordError(error); return false; } - const int targetId = _objectIndexToIdInScope->value(targetObjectIndex, -1); - Q_ASSERT(targetId != -1); - - const QString aliasPropertyValue = stringAt(p->aliasPropertyValueIndex); - - QStringRef property; - QStringRef subProperty; - - const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.')); - if (propertySeparator != -1) { - property = aliasPropertyValue.leftRef(propertySeparator); - subProperty = aliasPropertyValue.midRef(propertySeparator + 1); - } else - property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length()); - - int propIdx = -1; - int propType = 0; - int notifySignal = -1; - int flags = 0; - int type = 0; - bool writable = false; - bool resettable = false; - - quint32 propertyFlags = QQmlPropertyData::IsAlias; - - if (property.isEmpty()) { - const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex); - QQmlCompiledData::TypeReference *typeRef = resolvedTypes->value(targetObject->inheritedTypeNameIndex); - Q_ASSERT(typeRef); - - if (typeRef->type) - type = typeRef->type->typeId(); - else - type = typeRef->component->metaTypeId; - - flags |= QML_ALIAS_FLAG_PTR; - propertyFlags |= QQmlPropertyData::IsQObjectDerived; + + if (result == AllAliasesResolved) { + aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex); + atLeastOneAliasResolved = true; + } else if (result == SomeAliasesResolved) { + atLeastOneAliasResolved = true; + pendingObjects.append(objectIndex); } else { - QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex); - Q_ASSERT(targetCache); - QmlIR::PropertyResolver resolver(targetCache); + pendingObjects.append(objectIndex); + } + } + qSwap(_objectsWithAliases, pendingObjects); + } while (!_objectsWithAliases.isEmpty() && atLeastOneAliasResolved); - QQmlPropertyData *targetProperty = resolver.property(property.toString()); - if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) { - recordError(p->aliasLocation, tr("Invalid alias target location: %1").arg(property.toString())); - return false; - } + if (!atLeastOneAliasResolved && !_objectsWithAliases.isEmpty()) { + const QmlIR::Object *obj = qmlObjects->at(_objectsWithAliases.first()); + for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) { + if (!(alias->flags & QV4::CompiledData::Alias::Resolved)) { + recordError(alias->location, tr("Circular alias reference detected")); + return false; + } + } + } - propIdx = targetProperty->coreIndex; - type = targetProperty->propType; + return true; +} - writable = targetProperty->isWritable(); - resettable = targetProperty->isResettable(); - notifySignal = targetProperty->notifyIndex; +QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, QQmlCompileError *error) +{ + const QmlIR::Object * const obj = qmlObjects->at(objectIndex); + if (!obj->aliasCount()) + return AllAliasesResolved; - if (!subProperty.isEmpty()) { - const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(type); - if (!valueTypeMetaObject) { - recordError(p->aliasLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); - return false; - } + int numResolvedAliases = 0; + bool seenUnresolvedAlias = false; - propType = type; + for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next) { + if (alias->flags & QV4::CompiledData::Alias::Resolved) + continue; - int valueTypeIndex = - valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData()); - if (valueTypeIndex == -1) { - recordError(p->aliasLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); - return false; - } - Q_ASSERT(valueTypeIndex <= 0x0000FFFF); + seenUnresolvedAlias = true; - propIdx = QQmlPropertyData::encodeValueTypePropertyIndex(propIdx, valueTypeIndex); - if (valueTypeMetaObject->property(valueTypeIndex).isEnumType()) - type = QVariant::Int; - else - type = valueTypeMetaObject->property(valueTypeIndex).userType(); + const int idIndex = alias->idIndex; + const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1); + if (targetObjectIndex == -1) { + *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex))); + break; + } - } else { - if (targetProperty->isEnum()) { - type = QVariant::Int; - } else { - // Copy type flags - propertyFlags |= targetProperty->getFlags() & QQmlPropertyData::PropTypeFlagMask; + const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex); + Q_ASSERT(targetObject->id >= 0); + alias->targetObjectId = targetObject->id; + alias->aliasToLocalAlias = false; - if (targetProperty->isVarProperty()) - propertyFlags |= QQmlPropertyData::IsQVariant; + const QString aliasPropertyValue = stringAt(alias->propertyNameIndex); - if (targetProperty->isQObject()) - flags |= QML_ALIAS_FLAG_PTR; + QStringRef property; + QStringRef subProperty; + + const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.')); + if (propertySeparator != -1) { + property = aliasPropertyValue.leftRef(propertySeparator); + subProperty = aliasPropertyValue.midRef(propertySeparator + 1); + } else + property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length()); + + QQmlPropertyIndex propIdx; + + if (property.isEmpty()) { + alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject; + } else { + QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex); + Q_ASSERT(targetCache); + QmlIR::PropertyResolver resolver(targetCache); + + QQmlPropertyData *targetProperty = resolver.property(property.toString()); + + // If it's an alias that we haven't resolved yet, try again later. + if (!targetProperty) { + bool aliasPointsToOtherAlias = false; + int localAliasIndex = 0; + for (auto targetAlias = targetObject->aliasesBegin(), end = targetObject->aliasesEnd(); targetAlias != end; ++targetAlias, ++localAliasIndex) { + if (stringAt(targetAlias->nameIndex) == property) { + aliasPointsToOtherAlias = true; + break; } } - } - - QQmlVMEMetaData::AliasData aliasData = { targetId, propIdx, propType, flags, notifySignal }; + if (aliasPointsToOtherAlias) { + if (targetObjectIndex == objectIndex) { + alias->localAliasIndex = localAliasIndex; + alias->aliasToLocalAlias = true; + alias->flags |= QV4::CompiledData::Alias::Resolved; + ++numResolvedAliases; + continue; + } - typedef QQmlVMEMetaData VMD; - QByteArray &dynamicData = (*vmeMetaObjectData)[objectIndex]; - Q_ASSERT(!dynamicData.isEmpty()); - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - *(vmd->aliasData() + effectiveAliasIndex++) = aliasData; + // Try again later and resolve the target alias first. + _objectsWithAliases.append(objectIndex); + // restore + alias->idIndex = idIndex; + break; + } + } - Q_ASSERT(dynamicData.isDetached()); + if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) { + *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString())); + break; + } - if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && writable) - propertyFlags |= QQmlPropertyData::IsWritable; - else - propertyFlags &= ~QQmlPropertyData::IsWritable; + propIdx = QQmlPropertyIndex(targetProperty->coreIndex()); - if (resettable) - propertyFlags |= QQmlPropertyData::IsResettable; - else - propertyFlags &= ~QQmlPropertyData::IsResettable; + if (!subProperty.isEmpty()) { + const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(targetProperty->propType()); + if (!valueTypeMetaObject) { + *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); + break; + } - QString propertyName = stringAt(p->nameIndex); - if (propertyIndex == obj->indexOfDefaultProperty) propertyCache->_defaultPropertyName = propertyName; - propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, - type, effectiveSignalIndex++); + int valueTypeIndex = + valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData()); + if (valueTypeIndex == -1) { + *error = QQmlCompileError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString())); + break; + } + Q_ASSERT(valueTypeIndex <= 0x0000FFFF); + propIdx = QQmlPropertyIndex(propIdx.coreIndex(), valueTypeIndex); + } else { + if (targetProperty->isQObject()) + alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject; + } } + + alias->encodedMetaPropertyIndex = propIdx.toEncoded(); + alias->flags |= QV4::CompiledData::Alias::Resolved; + numResolvedAliases++; } - return true; + + if (numResolvedAliases == 0) + return seenUnresolvedAlias ? NoAliasResolved : AllAliasesResolved; + + return SomeAliasesResolved; } -QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler) +QQmlDeferredAndCustomParserBindingScanner::QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler) : QQmlCompilePass(typeCompiler) - , enginePrivate(typeCompiler->enginePrivate()) - , qmlUnit(typeCompiler->qmlUnit()) - , resolvedTypes(*typeCompiler->resolvedTypes()) - , customParsers(typeCompiler->customParserCache()) + , qmlObjects(typeCompiler->qmlObjects()) , propertyCaches(typeCompiler->propertyCaches()) - , objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent()) - , customParserBindingsPerObject(typeCompiler->customParserBindings()) + , customParsers(typeCompiler->customParserCache()) , _seenObjectWithId(false) { } -bool QQmlPropertyValidator::validate() -{ - _bindingPropertyDataPerObject.resize(qmlUnit->nObjects); - if (!validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0)) - return false; - compiler->setDeferredBindingsPerObject(_deferredBindingsPerObject); - compiler->setBindingPropertyDataPerObject(_bindingPropertyDataPerObject); - return true; -} - -const QQmlImports &QQmlPropertyValidator::imports() const +bool QQmlDeferredAndCustomParserBindingScanner::scanObject() { - return *compiler->imports(); + return scanObject(compiler->rootObjectIndex()); } -typedef QVarLengthArray<const QV4::CompiledData::Binding *, 8> GroupPropertyVector; - -struct BindingFinder -{ - bool operator()(quint32 name, const QV4::CompiledData::Binding *binding) const - { - return name < binding->propertyNameIndex; - } - bool operator()(const QV4::CompiledData::Binding *binding, quint32 name) const - { - return binding->propertyNameIndex < name; - } - bool operator()(const QV4::CompiledData::Binding *lhs, const QV4::CompiledData::Binding *rhs) const - { - return lhs->propertyNameIndex < rhs->propertyNameIndex; - } -}; - -bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const +bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex) { - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex); - if (obj->idIndex != 0) + QmlIR::Object *obj = qmlObjects->at(objectIndex); + if (obj->idNameIndex != 0) _seenObjectWithId = true; - if (isComponent(objectIndex)) { - Q_ASSERT(obj->nBindings == 1); - const QV4::CompiledData::Binding *componentBinding = obj->bindingTable(); + if (obj->flags & QV4::CompiledData::Object::IsComponent) { + Q_ASSERT(obj->bindingCount() == 1); + const QV4::CompiledData::Binding *componentBinding = obj->firstBinding(); Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object); - return validateObject(componentBinding->value.objectIndex, componentBinding); + return scanObject(componentBinding->value.objectIndex); } - QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex); + QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex); if (!propertyCache) return true; - QStringList deferredPropertyNames; - { - const QMetaObject *mo = propertyCache->firstCppMetaObject(); - const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames"); - if (namesIndex != -1) { - QMetaClassInfo classInfo = mo->classInfo(namesIndex); - deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(',')); - } - } - - QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex); - QList<const QV4::CompiledData::Binding*> customBindings; - - // Collect group properties first for sanity checking - // vector values are sorted by property name string index. - GroupPropertyVector groupProperties; - const QV4::CompiledData::Binding *binding = obj->bindingTable(); - for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) { - if (!binding->isGroupProperty()) - continue; - - if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) - continue; - - if (populatingValueTypeGroupProperty) { - recordError(binding->location, tr("Property assignment expected")); - return false; - } - - GroupPropertyVector::const_iterator pos = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder()); - groupProperties.insert(pos, binding); - } - - QBitArray customParserBindings(obj->nBindings); - QBitArray deferredBindings; - - QmlIR::PropertyResolver propertyResolver(propertyCache); - QString defaultPropertyName; QQmlPropertyData *defaultProperty = 0; - if (obj->indexOfDefaultProperty != -1) { + if (obj->indexOfDefaultPropertyOrAlias != -1) { QQmlPropertyCache *cache = propertyCache->parent(); defaultPropertyName = cache->defaultPropertyName(); defaultProperty = cache->defaultProperty(); @@ -1851,76 +1198,55 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD defaultProperty = propertyCache->defaultProperty(); } - QV4::CompiledData::BindingPropertyData collectedBindingPropertyData(obj->nBindings); + QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex); + + QmlIR::PropertyResolver propertyResolver(propertyCache); + + QStringList deferredPropertyNames; + { + const QMetaObject *mo = propertyCache->firstCppMetaObject(); + const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames"); + if (namesIndex != -1) { + QMetaClassInfo classInfo = mo->classInfo(namesIndex); + deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(',')); + } + } - binding = obj->bindingTable(); - for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) { + for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { + QQmlPropertyData *pd = 0; QString name = stringAt(binding->propertyNameIndex); if (customParser) { if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) { - customBindings << binding; - customParserBindings.setBit(i); + binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding; + obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings; continue; } } else if (QmlIR::IRBuilder::isSignalPropertyName(name) && !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) { - customBindings << binding; - customParserBindings.setBit(i); + obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings; + binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding; continue; } } - bool bindingToDefaultProperty = false; - bool isGroupProperty = instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty; - - bool notInRevision = false; - QQmlPropertyData *pd = 0; - if (!name.isEmpty()) { - if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression - || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) - pd = propertyResolver.signal(name, ¬InRevision); - else - pd = propertyResolver.property(name, ¬InRevision, isGroupProperty ? QmlIR::PropertyResolver::IgnoreRevision : QmlIR::PropertyResolver::CheckRevision); - - if (notInRevision) { - QString typeName = stringAt(obj->inheritedTypeNameIndex); - QQmlCompiledData::TypeReference *objectType = resolvedTypes.value(obj->inheritedTypeNameIndex); - if (objectType && objectType->type) { - COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(objectType->type->module()).arg(objectType->majorVersion).arg(objectType->minorVersion)); - } else { - COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name)); - } - } + if (name.isEmpty()) { + pd = defaultProperty; + name = defaultPropertyName; } else { - if (isGroupProperty) - COMPILE_EXCEPTION(binding, tr("Cannot assign a value directly to a grouped property")); - - pd = defaultProperty; - name = defaultPropertyName; - bindingToDefaultProperty = true; - } - - if (pd) - collectedBindingPropertyData[i] = pd; + if (name.constData()->isUpper()) + continue; - if (name.constData()->isUpper() && !binding->isAttachedProperty()) { - QQmlType *type = 0; - QQmlImportNamespace *typeNamespace = 0; - compiler->imports()->resolveType(stringAt(binding->propertyNameIndex), &type, 0, 0, &typeNamespace); - if (typeNamespace) - recordError(binding->location, tr("Invalid use of namespace")); - else - recordError(binding->location, tr("Invalid attached object assignment")); - return false; + bool notInRevision = false; + pd = propertyResolver.property(name, ¬InRevision, QmlIR::PropertyResolver::CheckRevision); } bool seenSubObjectWithId = false; if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) { qSwap(_seenObjectWithId, seenSubObjectWithId); - const bool subObjectValid = validateObject(binding->value.objectIndex, binding, pd && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType)); + const bool subObjectValid = scanObject(binding->value.objectIndex); qSwap(_seenObjectWithId, seenSubObjectWithId); if (!subObjectValid) return false; @@ -1930,538 +1256,28 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD if (!seenSubObjectWithId && !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) { - if (deferredBindings.isEmpty()) - deferredBindings.resize(obj->nBindings); - - deferredBindings.setBit(i); + binding->flags |= QV4::CompiledData::Binding::IsDeferredBinding; + obj->flags |= QV4::CompiledData::Object::HasDeferredBindings; } - // Signal handlers were resolved and checked earlier in the signal handler conversion pass. if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) continue; - if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { - if (instantiatingBinding && (instantiatingBinding->isAttachedProperty() || instantiatingBinding->isGroupProperty())) { - recordError(binding->location, tr("Attached properties cannot be used here")); - return false; - } - continue; - } - - if (pd) { - GroupPropertyVector::const_iterator assignedGroupProperty = std::lower_bound(groupProperties.constBegin(), groupProperties.constEnd(), binding->propertyNameIndex, BindingFinder()); - const bool assigningToGroupProperty = assignedGroupProperty != groupProperties.constEnd() && !(binding->propertyNameIndex < (*assignedGroupProperty)->propertyNameIndex); - - if (!pd->isWritable() - && !pd->isQList() - && !binding->isGroupProperty() - && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration) - ) { - - if (assigningToGroupProperty && binding->type < QV4::CompiledData::Binding::Type_Object) - recordError(binding->valueLocation, tr("Cannot assign a value directly to a grouped property")); - else - recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name)); - return false; - } - - if (!pd->isQList() && (binding->flags & QV4::CompiledData::Binding::IsListItem)) { - QString error; - if (pd->propType == qMetaTypeId<QQmlScriptString>()) - error = tr( "Cannot assign multiple values to a script property"); - else - error = tr( "Cannot assign multiple values to a singular property"); - recordError(binding->valueLocation, error); - return false; - } - - if (!bindingToDefaultProperty - && !binding->isGroupProperty() - && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment) - && assigningToGroupProperty) { - QV4::CompiledData::Location loc = binding->valueLocation; - if (loc < (*assignedGroupProperty)->valueLocation) - loc = (*assignedGroupProperty)->valueLocation; - - if (pd && QQmlValueTypeFactory::isValueType(pd->propType)) - recordError(loc, tr("Property has already been assigned a value")); - else - recordError(loc, tr("Cannot assign a value directly to a grouped property")); - return false; - } - - if (binding->type < QV4::CompiledData::Binding::Type_Script) { - if (!validateLiteralBinding(propertyCache, pd, binding)) - return false; - } else if (binding->type == QV4::CompiledData::Binding::Type_Object) { - if (!validateObjectBinding(pd, name, binding)) - return false; - } else if (binding->isGroupProperty()) { - if (QQmlValueTypeFactory::isValueType(pd->propType)) { - if (QQmlValueTypeFactory::metaObjectForMetaType(pd->propType)) { - if (!pd->isWritable()) { - recordError(binding->location, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name)); - return false; - } - } else { - recordError(binding->location, tr("Invalid grouped property access")); - return false; - } - } else { - if (!enginePrivate->propertyCacheForType(pd->propType)) { - recordError(binding->location, tr("Invalid grouped property access")); - return false; - } - } - } - } else { + if (!pd) { if (customParser) { - customBindings << binding; - customParserBindings.setBit(i); - continue; - } - if (bindingToDefaultProperty) { - COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent default property")); - } else { - COMPILE_EXCEPTION(binding, tr("Cannot assign to non-existent property \"%1\"").arg(name)); - } - } - } - - if (obj->idIndex) { - bool notInRevision = false; - collectedBindingPropertyData << propertyResolver.property(QStringLiteral("id"), ¬InRevision); - } - - if (customParser && !customBindings.isEmpty()) { - customParser->clearErrors(); - customParser->validator = this; - customParser->engine = enginePrivate; - customParser->imports = compiler->imports(); - customParser->verifyBindings(qmlUnit, customBindings); - customParser->validator = 0; - customParser->engine = 0; - customParser->imports = (QQmlImports*)0; - customParserBindingsPerObject->insert(objectIndex, customParserBindings); - const QList<QQmlError> parserErrors = customParser->errors(); - if (!parserErrors.isEmpty()) { - foreach (const QQmlError &error, parserErrors) - compiler->recordError(error); - return false; - } - } - - if (!deferredBindings.isEmpty()) - _deferredBindingsPerObject.insert(objectIndex, deferredBindings); - - _bindingPropertyDataPerObject[objectIndex] = collectedBindingPropertyData; - - return true; -} - -bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const -{ - if (property->isQList()) { - recordError(binding->valueLocation, tr("Cannot assign primitives to lists")); - return false; - } - - if (property->isEnum()) { - if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum) - return true; - - QString value = binding->valueAsString(qmlUnit); - QMetaProperty p = propertyCache->firstCppMetaObject()->property(property->coreIndex); - bool ok; - if (p.isFlagType()) { - p.enumerator().keysToValue(value.toUtf8().constData(), &ok); - } else - p.enumerator().keyToValue(value.toUtf8().constData(), &ok); - - if (!ok) { - recordError(binding->valueLocation, tr("Invalid property assignment: unknown enumeration")); - return false; - } - return true; - } - - switch (property->propType) { - case QMetaType::QVariant: - break; - case QVariant::String: { - if (!binding->evaluatesToString()) { - recordError(binding->valueLocation, tr("Invalid property assignment: string expected")); - return false; - } - } - break; - case QVariant::StringList: { - if (!binding->evaluatesToString()) { - recordError(binding->valueLocation, tr("Invalid property assignment: string or string list expected")); - return false; - } - } - break; - case QVariant::ByteArray: { - if (binding->type != QV4::CompiledData::Binding::Type_String) { - recordError(binding->valueLocation, tr("Invalid property assignment: byte array expected")); - return false; - } - } - break; - case QVariant::Url: { - if (binding->type != QV4::CompiledData::Binding::Type_String) { - recordError(binding->valueLocation, tr("Invalid property assignment: url expected")); - return false; - } - } - break; - case QVariant::UInt: { - if (binding->type == QV4::CompiledData::Binding::Type_Number) { - double d = binding->valueAsNumber(); - if (double(uint(d)) == d) - return true; - } - recordError(binding->valueLocation, tr("Invalid property assignment: unsigned int expected")); - return false; - } - break; - case QVariant::Int: { - if (binding->type == QV4::CompiledData::Binding::Type_Number) { - double d = binding->valueAsNumber(); - if (double(int(d)) == d) - return true; - } - recordError(binding->valueLocation, tr("Invalid property assignment: int expected")); - return false; - } - break; - case QMetaType::Float: { - if (binding->type != QV4::CompiledData::Binding::Type_Number) { - recordError(binding->valueLocation, tr("Invalid property assignment: number expected")); - return false; - } - } - break; - case QVariant::Double: { - if (binding->type != QV4::CompiledData::Binding::Type_Number) { - recordError(binding->valueLocation, tr("Invalid property assignment: number expected")); - return false; - } - } - break; - case QVariant::Color: { - bool ok = false; - QQmlStringConverters::rgbaFromString(binding->valueAsString(qmlUnit), &ok); - if (!ok) { - recordError(binding->valueLocation, tr("Invalid property assignment: color expected")); - return false; - } - } - break; -#ifndef QT_NO_DATESTRING - case QVariant::Date: { - bool ok = false; - QQmlStringConverters::dateFromString(binding->valueAsString(qmlUnit), &ok); - if (!ok) { - recordError(binding->valueLocation, tr("Invalid property assignment: date expected")); - return false; - } - } - break; - case QVariant::Time: { - bool ok = false; - QQmlStringConverters::timeFromString(binding->valueAsString(qmlUnit), &ok); - if (!ok) { - recordError(binding->valueLocation, tr("Invalid property assignment: time expected")); - return false; - } - } - break; - case QVariant::DateTime: { - bool ok = false; - QQmlStringConverters::dateTimeFromString(binding->valueAsString(qmlUnit), &ok); - if (!ok) { - recordError(binding->valueLocation, tr("Invalid property assignment: datetime expected")); - return false; - } - } - break; -#endif // QT_NO_DATESTRING - case QVariant::Point: { - bool ok = false; - QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok); - if (!ok) { - recordError(binding->valueLocation, tr("Invalid property assignment: point expected")); - return false; - } - } - break; - case QVariant::PointF: { - bool ok = false; - QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok); - if (!ok) { - recordError(binding->valueLocation, tr("Invalid property assignment: point expected")); - return false; - } - } - break; - case QVariant::Size: { - bool ok = false; - QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok); - if (!ok) { - recordError(binding->valueLocation, tr("Invalid property assignment: size expected")); - return false; - } - } - break; - case QVariant::SizeF: { - bool ok = false; - QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok); - if (!ok) { - recordError(binding->valueLocation, tr("Invalid property assignment: size expected")); - return false; - } - } - break; - case QVariant::Rect: { - bool ok = false; - QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok); - if (!ok) { - recordError(binding->valueLocation, tr("Invalid property assignment: rect expected")); - return false; - } - } - break; - case QVariant::RectF: { - bool ok = false; - QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok); - if (!ok) { - recordError(binding->valueLocation, tr("Invalid property assignment: point expected")); - return false; - } - } - break; - case QVariant::Bool: { - if (binding->type != QV4::CompiledData::Binding::Type_Boolean) { - recordError(binding->valueLocation, tr("Invalid property assignment: boolean expected")); - return false; - } - } - break; - case QVariant::Vector2D: { - struct { - float xp; - float yp; - } vec; - if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) { - recordError(binding->valueLocation, tr("Invalid property assignment: 2D vector expected")); - return false; - } - } - break; - case QVariant::Vector3D: { - struct { - float xp; - float yp; - float zy; - } vec; - if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) { - recordError(binding->valueLocation, tr("Invalid property assignment: 3D vector expected")); - return false; - } - } - break; - case QVariant::Vector4D: { - struct { - float xp; - float yp; - float zy; - float wp; - } vec; - if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) { - recordError(binding->valueLocation, tr("Invalid property assignment: 4D vector expected")); - return false; - } - } - break; - case QVariant::Quaternion: { - struct { - float wp; - float xp; - float yp; - float zp; - } vec; - if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(qmlUnit), &vec, sizeof(vec))) { - recordError(binding->valueLocation, tr("Invalid property assignment: quaternion expected")); - return false; - } - } - break; - case QVariant::RegExp: - recordError(binding->valueLocation, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax")); - return false; - default: { - // generate single literal value assignment to a list property if required - if (property->propType == qMetaTypeId<QList<qreal> >()) { - if (binding->type != QV4::CompiledData::Binding::Type_Number) { - recordError(binding->valueLocation, tr("Invalid property assignment: number or array of numbers expected")); - return false; - } - break; - } else if (property->propType == qMetaTypeId<QList<int> >()) { - bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number); - if (ok) { - double n = binding->valueAsNumber(); - if (double(int(n)) != n) - ok = false; - } - if (!ok) - recordError(binding->valueLocation, tr("Invalid property assignment: int or array of ints expected")); - break; - } else if (property->propType == qMetaTypeId<QList<bool> >()) { - if (binding->type != QV4::CompiledData::Binding::Type_Boolean) { - recordError(binding->valueLocation, tr("Invalid property assignment: bool or array of bools expected")); - return false; - } - break; - } else if (property->propType == qMetaTypeId<QList<QUrl> >()) { - if (binding->type != QV4::CompiledData::Binding::Type_String) { - recordError(binding->valueLocation, tr("Invalid property assignment: url or array of urls expected")); - return false; + obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings; + binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding; } - break; - } else if (property->propType == qMetaTypeId<QList<QString> >()) { - if (!binding->evaluatesToString()) { - recordError(binding->valueLocation, tr("Invalid property assignment: string or array of strings expected")); - return false; - } - break; - } else if (property->propType == qMetaTypeId<QJSValue>()) { - break; - } else if (property->propType == qMetaTypeId<QQmlScriptString>()) { - break; - } - - // otherwise, try a custom type assignment - QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType); - if (!converter) { - recordError(binding->valueLocation, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType)))); - return false; } } - break; - } - return true; -} - -/*! - Returns true if from can be assigned to a (QObject) property of type - to. -*/ -bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const -{ - QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to); - - while (fromMo) { - if (fromMo == toMo) - return true; - fromMo = fromMo->parent(); - } - return false; -} -bool QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const -{ - if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) { - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object); - - bool isValueSource = false; - bool isPropertyInterceptor = false; - - QQmlType *qmlType = 0; - const QV4::CompiledData::Object *targetObject = qmlUnit->objectAt(binding->value.objectIndex); - QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(targetObject->inheritedTypeNameIndex); - if (typeRef) { - QQmlPropertyCache *cache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); - const QMetaObject *mo = cache->firstCppMetaObject(); - while (mo && !qmlType) { - qmlType = QQmlMetaType::qmlType(mo); - mo = mo->superClass(); - } - Q_ASSERT(qmlType); - } - - if (qmlType) { - isValueSource = qmlType->propertyValueSourceCast() != -1; - isPropertyInterceptor = qmlType->propertyValueInterceptorCast() != -1; - } - - if (!isValueSource && !isPropertyInterceptor) { - recordError(binding->valueLocation, tr("\"%1\" cannot operate on \"%2\"").arg(stringAt(targetObject->inheritedTypeNameIndex)).arg(propertyName)); - return false; - } - - return true; - } - - if (QQmlMetaType::isInterface(property->propType)) { - // Can only check at instantiation time if the created sub-object successfully casts to the - // target interface. - return true; - } else if (property->propType == QMetaType::QVariant) { - // We can convert everything to QVariant :) - return true; - } else if (property->isQList()) { - const int listType = enginePrivate->listType(property->propType); - if (!QQmlMetaType::isInterface(listType)) { - QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex); - if (!canCoerce(listType, source)) { - recordError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName)); - return false; - } - } - return true; - } else if (isComponent(binding->value.objectIndex)) { - return true; - } else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) { - return true; - } else if (QQmlValueTypeFactory::isValueType(property->propType)) { - recordError(binding->location, tr("Unexpected object assignment")); - return false; - } else if (property->propType == qMetaTypeId<QQmlScriptString>()) { - recordError(binding->valueLocation, tr("Invalid property assignment: script expected")); - return false; - } else { - // We want to raw metaObject here as the raw metaobject is the - // actual property type before we applied any extensions that might - // effect the properties on the type, but don't effect assignability - QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType); - - // Will be true if the assgned type inherits propertyMetaObject - bool isAssignable = false; - // Determine isAssignable value - if (propertyMetaObject) { - QQmlPropertyCache *c = propertyCaches.at(binding->value.objectIndex); - while (c && !isAssignable) { - isAssignable |= c == propertyMetaObject; - c = c->parent(); - } - } - - if (!isAssignable) { - recordError(binding->valueLocation, tr("Cannot assign object to property")); - return false; - } - } return true; } QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen) : QQmlCompilePass(typeCompiler) - , objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent()) - , resolvedTypes(*typeCompiler->resolvedTypes()) + , resolvedTypes(typeCompiler->resolvedTypes) , customParsers(typeCompiler->customParserCache()) , qmlObjects(*typeCompiler->qmlObjects()) , propertyCaches(typeCompiler->propertyCaches()) @@ -2471,48 +1287,42 @@ QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR:: bool QQmlJSCodeGenerator::generateCodeForComponents() { - const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent = *compiler->objectIndexToIdPerComponent(); - for (QHash<int, QHash<int, int> >::ConstIterator component = objectIndexToIdPerComponent.constBegin(), end = objectIndexToIdPerComponent.constEnd(); - component != end; ++component) { - if (!compileComponent(component.key(), component.value())) + const QVector<quint32> &componentRoots = compiler->componentRoots(); + for (int i = 0; i < componentRoots.count(); ++i) { + if (!compileComponent(componentRoots.at(i))) return false; } - return compileComponent(compiler->rootObjectIndex(), *compiler->objectIndexToIdForRoot()); + return compileComponent(compiler->rootObjectIndex()); } -bool QQmlJSCodeGenerator::compileComponent(int contextObject, const QHash<int, int> &objectIndexToId) +bool QQmlJSCodeGenerator::compileComponent(int contextObject) { - if (isComponent(contextObject)) { - const QmlIR::Object *component = qmlObjects.at(contextObject); - Q_ASSERT(component->bindingCount() == 1); - const QV4::CompiledData::Binding *componentBinding = component->firstBinding(); + const QmlIR::Object *obj = qmlObjects.at(contextObject); + if (obj->flags & QV4::CompiledData::Object::IsComponent) { + Q_ASSERT(obj->bindingCount() == 1); + const QV4::CompiledData::Binding *componentBinding = obj->firstBinding(); Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object); contextObject = componentBinding->value.objectIndex; } QmlIR::JSCodeGen::ObjectIdMapping idMapping; - if (!objectIndexToId.isEmpty()) { - idMapping.reserve(objectIndexToId.count()); + idMapping.reserve(obj->namedObjectsInComponent.count); + for (int i = 0; i < obj->namedObjectsInComponent.count; ++i) { + const int objectIndex = obj->namedObjectsInComponent.at(i); + QmlIR::JSCodeGen::IdMapping m; + const QmlIR::Object *obj = qmlObjects.at(objectIndex); + m.name = stringAt(obj->idNameIndex); + m.idIndex = obj->id; + m.type = propertyCaches->at(objectIndex); - for (QHash<int, int>::ConstIterator idIt = objectIndexToId.constBegin(), end = objectIndexToId.constEnd(); - idIt != end; ++idIt) { + auto *tref = resolvedTypes.value(obj->inheritedTypeNameIndex); + if (tref && tref->isFullyDynamicType) + m.type = 0; - const int objectIndex = idIt.key(); - QmlIR::JSCodeGen::IdMapping m; - const QmlIR::Object *obj = qmlObjects.at(objectIndex); - m.name = stringAt(obj->idIndex); - m.idIndex = idIt.value(); - m.type = propertyCaches.at(objectIndex); - - QQmlCompiledData::TypeReference *tref = resolvedTypes.value(obj->inheritedTypeNameIndex); - if (tref && tref->isFullyDynamicType) - m.type = 0; - - idMapping << m; - } + idMapping << m; } - v4CodeGen->beginContextScope(idMapping, propertyCaches.at(contextObject)); + v4CodeGen->beginContextScope(idMapping, propertyCaches->at(contextObject)); if (!compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject)) return false; @@ -2522,12 +1332,12 @@ bool QQmlJSCodeGenerator::compileComponent(int contextObject, const QHash<int, i bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex) { - if (isComponent(objectIndex)) + QmlIR::Object *object = qmlObjects.at(objectIndex); + if (object->flags & QV4::CompiledData::Object::IsComponent) return true; - QmlIR::Object *object = qmlObjects.at(objectIndex); if (object->functionsAndExpressions->count > 0) { - QQmlPropertyCache *scopeObject = propertyCaches.at(scopeObjectIndex); + QQmlPropertyCache *scopeObject = propertyCaches->at(scopeObjectIndex); v4CodeGen->beginObjectScope(scopeObject); QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile; @@ -2546,8 +1356,7 @@ bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIn } QQmlJS::MemoryPool *pool = compiler->memoryPool(); - object->runtimeFunctionIndices = pool->New<QmlIR::FixedPoolArray<int> >(); - object->runtimeFunctionIndices->init(pool, runtimeFunctionIndices); + object->runtimeFunctionIndices.allocate(pool, runtimeFunctionIndices); } for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) { @@ -2580,20 +1389,20 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties() void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex) { - QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex); + QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex); if (!propertyCache) return; QmlIR::Object *object = qmlObjects.at(objectIndex); - QString defaultProperty = object->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName(); + QString defaultProperty = object->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName(); QmlIR::Binding *bindingsToReinsert = 0; QmlIR::Binding *tail = 0; QmlIR::Binding *previousBinding = 0; QmlIR::Binding *binding = object->firstBinding(); while (binding) { - if (binding->propertyNameIndex == 0 || stringAt(binding->propertyNameIndex) != defaultProperty) { + if (binding->propertyNameIndex == quint32(0) || stringAt(binding->propertyNameIndex) != defaultProperty) { previousBinding = binding; binding = binding->next; continue; @@ -2646,7 +1455,7 @@ void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBinding if (binding->type != QV4::CompiledData::Binding::Type_Script) continue; - const int irFunctionIndex = obj->runtimeFunctionIndices->at(binding->value.compiledScriptIndex); + const int irFunctionIndex = obj->runtimeFunctionIndices.at(binding->value.compiledScriptIndex); QV4::IR::Function *irFunction = jsModule->functions.at(irFunctionIndex); if (simplifyBinding(irFunction, binding)) { irFunctionsToRemove.append(irFunctionIndex); @@ -2757,7 +1566,7 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR: for (QV4::IR::BasicBlock *bb : function->basicBlocks()) { for (QV4::IR::Stmt *s : bb->statements()) { - s->accept(this); + visit(s); if (!_canSimplify) return false; } @@ -2927,22 +1736,41 @@ void QQmlIRFunctionCleanser::clean() foreach (QV4::IR::Function *function, module->functions) { for (QV4::IR::BasicBlock *block : function->basicBlocks()) { for (QV4::IR::Stmt *s : block->statements()) { - s->accept(this); + visit(s); } } } foreach (QmlIR::Object *obj, *compiler->qmlObjects()) { - if (!obj->runtimeFunctionIndices) - continue; - for (int i = 0; i < obj->runtimeFunctionIndices->count; ++i) - (*obj->runtimeFunctionIndices)[i] = newFunctionIndices[obj->runtimeFunctionIndices->at(i)]; + for (int i = 0; i < obj->runtimeFunctionIndices.count; ++i) + obj->runtimeFunctionIndices[i] = newFunctionIndices[obj->runtimeFunctionIndices.at(i)]; + } +} + +void QQmlIRFunctionCleanser::visit(QV4::IR::Stmt *s) +{ + + switch (s->stmtKind) { + case QV4::IR::Stmt::PhiStmt: + // nothing to do + break; + default: + STMT_VISIT_ALL_KINDS(s); + break; } } -void QQmlIRFunctionCleanser::visitClosure(QV4::IR::Closure *closure) +void QQmlIRFunctionCleanser::visit(QV4::IR::Expr *e) { - closure->value = newFunctionIndices.at(closure->value); + switch (e->exprKind) { + case QV4::IR::Expr::ClosureExpr: { + auto closure = e->asClosure(); + closure->value = newFunctionIndices.at(closure->value); + } break; + default: + EXPR_VISIT_ALL_KINDS(e); + break; + } } QT_END_NAMESPACE |