From fb377763ac3eea4010c7a501b8363ca46874a5b3 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 11 Dec 2013 13:44:56 +0100 Subject: [PATCH] [new compiler] Fix signal handlers for properties declared in the same object We need to generate the property caches before we can try converting the signal handler expressions in the AST to function declarations, as that conversion requires looking up the signal signature / meta-data from the property cache. This in turn requires rewriting the property cache generator code to operate on the data structure we have before creating the QV4::CompiledData. Change-Id: I0d1c59d947f36171b4eb89f47a2e1ff1bc493c6f Reviewed-by: Lars Knoll --- src/qml/compiler/qqmlcodegenerator.cpp | 10 +++- src/qml/compiler/qqmlcodegenerator_p.h | 2 + src/qml/qml/qqmlobjectcreator.cpp | 86 +++++++++++++++++++--------------- src/qml/qml/qqmlobjectcreator_p.h | 8 ++-- src/qml/qml/qqmltypeloader.cpp | 79 ++++++++++++++++--------------- 5 files changed, 103 insertions(+), 82 deletions(-) diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp index 19ccb6d..a4da07a 100644 --- a/src/qml/compiler/qqmlcodegenerator.cpp +++ b/src/qml/compiler/qqmlcodegenerator.cpp @@ -736,6 +736,10 @@ bool QQmlCodeGenerator::visit(AST::UiSourceElement *node) if (AST::FunctionDeclaration *funDecl = AST::cast(node->sourceElement)) { _functions << funDecl; Function *f = New(); + f->functionDeclaration = funDecl; + AST::SourceLocation loc = funDecl->firstSourceLocation(); + f->location.line = loc.startLine; + f->location.column = loc.startColumn; f->index = _functions.size() - 1; _object->functions->append(f); } else { @@ -1616,14 +1620,16 @@ SignalHandlerConverter::SignalHandlerConverter(QQmlEnginePrivate *enginePrivate, bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations() { - foreach (QmlObject *obj, parsedQML->objects) { + for (int objectIndex = 0; objectIndex < parsedQML->objects.count(); ++objectIndex) { + QmlObject * const obj = parsedQML->objects.at(objectIndex); QString elementName = stringAt(obj->inheritedTypeNameIndex); if (elementName.isEmpty()) continue; QQmlCompiledData::TypeReference &tr = unit->resolvedTypes[obj->inheritedTypeNameIndex]; if (tr.type && tr.type->customParser()) continue; - QQmlPropertyCache *cache = tr.createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); + QQmlPropertyCache *cache = unit->propertyCaches.value(objectIndex); + Q_ASSERT(cache); if (!convertSignalHandlerExpressionsToFunctionDeclarations(obj, elementName, cache)) return false; } diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h index 83ff716..18193ee 100644 --- a/src/qml/compiler/qqmlcodegenerator_p.h +++ b/src/qml/compiler/qqmlcodegenerator_p.h @@ -135,6 +135,8 @@ struct Binding : public QV4::CompiledData::Binding struct Function { + AST::FunctionDeclaration *functionDeclaration; + QV4::CompiledData::Location location; int index; // index in parsedQML::functions Function *next; }; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index e6bf36b..69ccd4c 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -77,6 +77,14 @@ QQmlCompilePass::QQmlCompilePass(const QUrl &url, const QV4::CompiledData::QmlUn { } +QQmlCompilePass::QQmlCompilePass(const QUrl &url, const QStringList &stringTable) + : url(url) + , qmlUnit(0) + , stringTable(stringTable) +{ + +} + void QQmlCompilePass::recordError(const QV4::CompiledData::Location &location, const QString &description) { QQmlError error; @@ -95,32 +103,32 @@ void QQmlCompilePass::recordError(const QV4::CompiledData::Location &location, c static QAtomicInt classIndexCounter(0); -QQmlPropertyCacheCreator::QQmlPropertyCacheCreator(QQmlEnginePrivate *enginePrivate, const QV4::CompiledData::QmlUnit *unit, const QUrl &url, const QQmlImports *imports, +QQmlPropertyCacheCreator::QQmlPropertyCacheCreator(QQmlEnginePrivate *enginePrivate, const QStringList &stringTable, const QUrl &url, const QQmlImports *imports, QHash *resolvedTypes) - : QQmlCompilePass(url, unit) + : QQmlCompilePass(url, stringTable) , enginePrivate(enginePrivate) , imports(imports) , resolvedTypes(resolvedTypes) { } -bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQmlPropertyCache **resultCache, QByteArray *vmeMetaObjectData) +bool QQmlPropertyCacheCreator::create(const QtQml::QmlObject *obj, QQmlPropertyCache **resultCache, QByteArray *vmeMetaObjectData) { Q_ASSERT(!stringAt(obj->inheritedTypeNameIndex).isEmpty()); QQmlCompiledData::TypeReference typeRef = resolvedTypes->value(obj->inheritedTypeNameIndex); QQmlPropertyCache *baseTypeCache = typeRef.createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); Q_ASSERT(baseTypeCache); - if (obj->nProperties == 0 && obj->nSignals == 0 && obj->nFunctions == 0) { + if (obj->properties->count == 0 && obj->qmlSignals->count == 0 && obj->functions->count == 0) { *resultCache = baseTypeCache; vmeMetaObjectData->clear(); return true; } QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(QQmlEnginePrivate::get(enginePrivate), - obj->nProperties, - obj->nFunctions + obj->nProperties + obj->nSignals, - obj->nSignals + obj->nProperties); + obj->properties->count, + obj->functions->count + obj->properties->count + obj->qmlSignals->count, + obj->qmlSignals->count + obj->properties->count); *resultCache = cache; vmeMetaObjectData->clear(); @@ -177,9 +185,7 @@ bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQml int aliasCount = 0; int varPropCount = 0; - const QV4::CompiledData::Property *p = obj->propertyTable(); - for (quint32 i = 0; i < obj->nProperties; ++i, ++p) { - + for (QtQml::QmlProperty *p = obj->properties->first; p; p = p->next) { if (p->type == QV4::CompiledData::Property::Alias) aliasCount++; else if (p->type == QV4::CompiledData::Property::Var) @@ -196,8 +202,8 @@ bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQml typedef QQmlVMEMetaData VMD; QByteArray &dynamicData = *vmeMetaObjectData = QByteArray(sizeof(QQmlVMEMetaData) - + obj->nProperties * sizeof(VMD::PropertyData) - + obj->nFunctions * sizeof(VMD::MethodData) + + obj->properties->count * sizeof(VMD::PropertyData) + + obj->functions->count * sizeof(VMD::MethodData) + aliasCount * sizeof(VMD::AliasData), 0); int effectivePropertyIndex = cache->propertyIndexCacheStart; @@ -233,8 +239,7 @@ bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQml if (ii == NSS_Var && varPropCount == 0) continue; else if (ii == NSS_Alias && aliasCount == 0) continue; - const QV4::CompiledData::Property *p = obj->propertyTable(); - for (quint32 i = 0; i < obj->nProperties; ++i, ++p) { + for (QtQml::QmlProperty *p = obj->properties->first; p; p = p->next) { if ((ii == NSS_Normal && (p->type == QV4::CompiledData::Property::Alias || p->type == QV4::CompiledData::Property::Var)) || ((ii == NSS_Var) && (p->type != QV4::CompiledData::Property::Var)) || @@ -252,9 +257,8 @@ bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQml } // Dynamic signals - for (uint i = 0; i < obj->nSignals; ++i) { - const QV4::CompiledData::Signal *s = obj->signalAt(i); - const int paramCount = s->nParameters; + for (QtQml::Signal *s = obj->qmlSignals->first; s; s = s->next) { + const int paramCount = s->parameters->count; QList names; QVarLengthArray paramTypes(paramCount?(paramCount + 1):0); @@ -262,8 +266,8 @@ bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQml if (paramCount) { paramTypes[0] = paramCount; - for (int i = 0; i < paramCount; ++i) { - const QV4::CompiledData::Parameter *param = s->parameterAt(i); + QtQml::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 @@ -311,27 +315,26 @@ bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQml // Dynamic slots - const quint32 *functionIndex = obj->functionOffsetTable(); - for (quint32 i = 0; i < obj->nFunctions; ++i, ++functionIndex) { - const QV4::CompiledData::Function *s = qmlUnit->header.functionAt(*functionIndex); - int paramCount = s->nFormals; + for (QtQml::Function *s = obj->functions->first; s; s = s->next) { + AST::FunctionDeclaration *astFunction = s->functionDeclaration; quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction; - if (paramCount) + if (astFunction->formals) flags |= QQmlPropertyData::HasArguments; - QString slotName = stringAt(s->nameIndex); + 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. - const quint32 *formalsIndices = s->formalsTable(); QList parameterNames; - parameterNames.reserve(paramCount); - for (int i = 0; i < paramCount; ++i) - parameterNames << stringAt(formalsIndices[i]).toUtf8(); + AST::FormalParameterList *param = astFunction->formals; + while (param) { + parameterNames << param->name.toUtf8(); + param = param->next; + } cache->appendMethod(slotName, flags, effectiveMethodIndex++, parameterNames); } @@ -339,8 +342,8 @@ bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQml // Dynamic properties (except var and aliases) int effectiveSignalIndex = cache->signalHandlerIndexCacheStart; - /* const QV4::CompiledData::Property* */ p = obj->propertyTable(); - for (quint32 i = 0; i < obj->nProperties; ++i, ++p) { + int propertyIdx = 0; + for (QtQml::QmlProperty *p = obj->properties->first; p; p = p->next, ++propertyIdx) { if (p->type == QV4::CompiledData::Property::Alias || p->type == QV4::CompiledData::Property::Var) @@ -403,7 +406,7 @@ bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQml QString propertyName = stringAt(p->nameIndex); - if (i == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName; + if (propertyIdx == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName; cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, propertyType, effectiveSignalIndex); @@ -415,8 +418,8 @@ bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQml } // Now do var properties - /* const QV4::CompiledData::Property* */ p = obj->propertyTable(); - for (quint32 i = 0; i < obj->nProperties; ++i, ++p) { + propertyIdx = 0; + for (QtQml::QmlProperty *p = obj->properties->first; p; p = p->next, ++propertyIdx) { if (p->type != QV4::CompiledData::Property::Var) continue; @@ -431,7 +434,7 @@ bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQml ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++; QString propertyName = stringAt(p->nameIndex); - if (i == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName; + if (propertyIdx == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName; cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, QMetaType::QVariant, effectiveSignalIndex); @@ -442,12 +445,17 @@ bool QQmlPropertyCacheCreator::create(const QV4::CompiledData::Object *obj, QQml ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount; // Dynamic slot data - comes after the property data - /*const quint32* */functionIndex = obj->functionOffsetTable(); - for (quint32 i = 0; i < obj->nFunctions; ++i, ++functionIndex) { - const QV4::CompiledData::Function *s = qmlUnit->header.functionAt(*functionIndex); + for (QtQml::Function *s = obj->functions->first; s; s = s->next) { + AST::FunctionDeclaration *astFunction = s->functionDeclaration; + int formalsCount = 0; + AST::FormalParameterList *param = astFunction->formals; + while (param) { + formalsCount++; + param = param->next; + } VMD::MethodData methodData = { /* runtimeFunctionIndex*/ 0, // ### - int(s->nFormals), + formalsCount, /* s->location.start.line */0 }; // ### VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index e33e47e..d395f02 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -54,25 +54,27 @@ class QQmlAbstractBinding; struct QQmlCompilePass { QQmlCompilePass(const QUrl &url, const QV4::CompiledData::QmlUnit *unit); + QQmlCompilePass(const QUrl &url, const QStringList &stringTable); QList errors; + QString stringAt(int idx) const { return qmlUnit ? qmlUnit->header.stringAt(idx): stringTable.at(idx); } protected: - QString stringAt(int idx) const { return qmlUnit->header.stringAt(idx); } void recordError(const QV4::CompiledData::Location &location, const QString &description); const QUrl url; const QV4::CompiledData::QmlUnit *qmlUnit; + const QStringList stringTable; }; class QQmlPropertyCacheCreator : public QQmlCompilePass { Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreator) public: - QQmlPropertyCacheCreator(QQmlEnginePrivate *enginePrivate, const QV4::CompiledData::QmlUnit *qmlUnit, + QQmlPropertyCacheCreator(QQmlEnginePrivate *enginePrivate, const QStringList &stringTable, const QUrl &url, const QQmlImports *imports, QHash *resolvedTypes); - bool create(const QV4::CompiledData::Object *obj, QQmlPropertyCache **cache, QByteArray *vmeMetaObjectData); + bool create(const QtQml::QmlObject *obj, QQmlPropertyCache **cache, QByteArray *vmeMetaObjectData); protected: QQmlEnginePrivate *enginePrivate; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 1a4c8f0..5b6d914 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2338,6 +2338,46 @@ void QQmlTypeData::compile() m_compiledData->resolvedTypes.insert(resolvedType.key(), ref); } + // Build property caches and VME meta object data + + const int objectCount = parsedQML->objects.count(); + m_compiledData->datas.reserve(objectCount); + m_compiledData->propertyCaches.reserve(objectCount); + + QQmlPropertyCacheCreator propertyCacheBuilder(enginePrivate, + parsedQML->jsGenerator.strings, m_compiledData->url, + &m_imports, &m_compiledData->resolvedTypes); + + for (int i = 0; i < objectCount; ++i) { + const QtQml::QmlObject *obj = parsedQML->objects.at(i); + + QByteArray vmeMetaObjectData; + QQmlPropertyCache *propertyCache = 0; + + // If the object has no type, then it's probably a nested object definition as part + // of a group property. + const bool objectHasType = !propertyCacheBuilder.stringAt(obj->inheritedTypeNameIndex).isEmpty(); + if (objectHasType) { + if (!propertyCacheBuilder.create(obj, &propertyCache, &vmeMetaObjectData)) { + setError(propertyCacheBuilder.errors); + m_compiledData->release(); + m_compiledData = 0; + return; + } + } + + m_compiledData->datas << vmeMetaObjectData; + if (propertyCache) + propertyCache->addref(); + m_compiledData->propertyCaches << propertyCache; + + if (i == parsedQML->indexOfRootObject) { + Q_ASSERT(propertyCache); + m_compiledData->rootPropertyCache = propertyCache; + propertyCache->addref(); + } + } + { SignalHandlerConverter converter(QQmlEnginePrivate::get(engine), parsedQML.data(), @@ -2399,46 +2439,9 @@ void QQmlTypeData::compile() QList errors; - // Build property caches and VME meta object data - - m_compiledData->datas.reserve(qmlUnit->nObjects); - m_compiledData->propertyCaches.reserve(qmlUnit->nObjects); - - QQmlPropertyCacheCreator propertyCacheBuilder(enginePrivate, - qmlUnit, m_compiledData->url, - &m_imports, &m_compiledData->resolvedTypes); - - for (quint32 i = 0; i < qmlUnit->nObjects; ++i) { - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i); - - QByteArray vmeMetaObjectData; - QQmlPropertyCache *propertyCache = 0; - - // If the object has no type, then it's probably a nested object definition as part - // of a group property. - const bool objectHasType = !parsedQML->jsGenerator.strings.at(obj->inheritedTypeNameIndex).isEmpty(); - if (objectHasType) { - if (!propertyCacheBuilder.create(obj, &propertyCache, &vmeMetaObjectData)) { - errors << propertyCacheBuilder.errors; - break; - } - } - - m_compiledData->datas << vmeMetaObjectData; - if (propertyCache) - propertyCache->addref(); - m_compiledData->propertyCaches << propertyCache; - - if (i == qmlUnit->indexOfRootObject) { - Q_ASSERT(propertyCache); - m_compiledData->rootPropertyCache = propertyCache; - propertyCache->addref(); - } - } - // Resolve component boundaries and aliases - if (errors.isEmpty()) { + { // Scan for components, determine their scopes and resolve aliases within the scope. QQmlComponentAndAliasResolver resolver(m_compiledData->url, m_compiledData->qmlUnit, m_compiledData->resolvedTypes, m_compiledData->propertyCaches, &m_compiledData->datas, &m_compiledData->objectIndexToIdForRoot, &m_compiledData->objectIndexToIdPerComponent); -- 2.7.4