From b4d4e077340e7a1c031be15415410c20adc74887 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 5 Jul 2019 10:04:08 +0200 Subject: Centralize property & signal parameter type handling at compilation time Collect all that code in the Parameter class, which allows for future re-use for function parameters and return types. Change-Id: Ib9dfec9313dc3938634f9ce3a2e5a3a59a7135d9 Reviewed-by: Ulf Hermann --- src/qml/compiler/qqmlirbuilder.cpp | 156 ++++++++++++++++++----------------- src/qml/compiler/qqmlirbuilder_p.h | 14 ++-- src/qml/compiler/qv4compileddata_p.h | 10 ++- 3 files changed, 96 insertions(+), 84 deletions(-) (limited to 'src/qml/compiler') diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 1891f31f13..a1c0e97ccc 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -63,6 +63,72 @@ using namespace QmlIR; return false; \ } +bool Parameter::init(QV4::Compiler::JSUnitGenerator *stringGenerator, const QString ¶meterName, + const QString &typeName) +{ + nameIndex = stringGenerator->registerString(parameterName); + type.indexIsBuiltinType = false; + type.typeNameIndexOrBuiltinType = 0; + auto builtinType = stringToBuiltinType(typeName); + if (builtinType == QV4::CompiledData::BuiltinType::InvalidBuiltin) { + if (typeName.isEmpty() || !typeName.at(0).isUpper()) + return false; + type.indexIsBuiltinType = false; + type.typeNameIndexOrBuiltinType = stringGenerator->registerString(typeName); + Q_ASSERT(quint32(stringGenerator->getStringId(typeName)) < (1u << 31)); + } else { + type.indexIsBuiltinType = true; + type.typeNameIndexOrBuiltinType = static_cast(builtinType); + Q_ASSERT(quint32(builtinType) < (1u << 31)); + } + return true; +} + +QV4::CompiledData::BuiltinType Parameter::stringToBuiltinType(const QString &typeName) +{ + static const struct TypeNameToType { + const char *name; + size_t nameLength; + QV4::CompiledData::BuiltinType type; + } propTypeNameToTypes[] = { + { "int", strlen("int"), QV4::CompiledData::BuiltinType::Int }, + { "bool", strlen("bool"), QV4::CompiledData::BuiltinType::Bool }, + { "double", strlen("double"), QV4::CompiledData::BuiltinType::Real }, + { "real", strlen("real"), QV4::CompiledData::BuiltinType::Real }, + { "string", strlen("string"), QV4::CompiledData::BuiltinType::String }, + { "url", strlen("url"), QV4::CompiledData::BuiltinType::Url }, + { "color", strlen("color"), QV4::CompiledData::BuiltinType::Color }, + // Internally QTime, QDate and QDateTime are all supported. + // To be more consistent with JavaScript we expose only + // QDateTime as it matches closely with the Date JS type. + // We also call it "date" to match. + // { "time", strlen("time"), Property::Time }, + // { "date", strlen("date"), Property::Date }, + { "date", strlen("date"), QV4::CompiledData::BuiltinType::DateTime }, + { "rect", strlen("rect"), QV4::CompiledData::BuiltinType::Rect }, + { "point", strlen("point"), QV4::CompiledData::BuiltinType::Point }, + { "size", strlen("size"), QV4::CompiledData::BuiltinType::Size }, + { "font", strlen("font"), QV4::CompiledData::BuiltinType::Font }, + { "vector2d", strlen("vector2d"), QV4::CompiledData::BuiltinType::Vector2D }, + { "vector3d", strlen("vector3d"), QV4::CompiledData::BuiltinType::Vector3D }, + { "vector4d", strlen("vector4d"), QV4::CompiledData::BuiltinType::Vector4D }, + { "quaternion", strlen("quaternion"), QV4::CompiledData::BuiltinType::Quaternion }, + { "matrix4x4", strlen("matrix4x4"), QV4::CompiledData::BuiltinType::Matrix4x4 }, + { "variant", strlen("variant"), QV4::CompiledData::BuiltinType::Variant }, + { "var", strlen("var"), QV4::CompiledData::BuiltinType::Var } + }; + static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) / + sizeof(propTypeNameToTypes[0]); + + for (int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) { + const TypeNameToType *t = propTypeNameToTypes + typeIndex; + if (typeName == QLatin1String(t->name, static_cast(t->nameLength))) { + return t->type; + } + } + return QV4::CompiledData::BuiltinType::InvalidBuiltin; +} + void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QQmlJS::AST::SourceLocation &loc) { inheritedTypeNameIndex = typeNameIndex; @@ -247,7 +313,7 @@ QStringList Signal::parameterStringList(const QV4::Compiler::StringTableGenerato { QStringList result; result.reserve(parameters->count); - for (SignalParameter *param = parameters->first; param; param = param->next) + for (Parameter *param = parameters->first; param; param = param->next) result << stringPool->stringForIndex(param->nameIndex); return result; } @@ -764,40 +830,6 @@ bool IRBuilder::visit(QQmlJS::AST::UiEnumDeclaration *node) bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) { - static const struct TypeNameToType { - const char *name; - size_t nameLength; - QV4::CompiledData::BuiltinType type; - } propTypeNameToTypes[] = { - { "int", strlen("int"), QV4::CompiledData::BuiltinType::Int }, - { "bool", strlen("bool"), QV4::CompiledData::BuiltinType::Bool }, - { "double", strlen("double"), QV4::CompiledData::BuiltinType::Real }, - { "real", strlen("real"), QV4::CompiledData::BuiltinType::Real }, - { "string", strlen("string"), QV4::CompiledData::BuiltinType::String }, - { "url", strlen("url"), QV4::CompiledData::BuiltinType::Url }, - { "color", strlen("color"), QV4::CompiledData::BuiltinType::Color }, - // Internally QTime, QDate and QDateTime are all supported. - // To be more consistent with JavaScript we expose only - // QDateTime as it matches closely with the Date JS type. - // We also call it "date" to match. - // { "time", strlen("time"), Property::Time }, - // { "date", strlen("date"), Property::Date }, - { "date", strlen("date"), QV4::CompiledData::BuiltinType::DateTime }, - { "rect", strlen("rect"), QV4::CompiledData::BuiltinType::Rect }, - { "point", strlen("point"), QV4::CompiledData::BuiltinType::Point }, - { "size", strlen("size"), QV4::CompiledData::BuiltinType::Size }, - { "font", strlen("font"), QV4::CompiledData::BuiltinType::Font }, - { "vector2d", strlen("vector2d"), QV4::CompiledData::BuiltinType::Vector2D }, - { "vector3d", strlen("vector3d"), QV4::CompiledData::BuiltinType::Vector3D }, - { "vector4d", strlen("vector4d"), QV4::CompiledData::BuiltinType::Vector4D }, - { "quaternion", strlen("quaternion"), QV4::CompiledData::BuiltinType::Quaternion }, - { "matrix4x4", strlen("matrix4x4"), QV4::CompiledData::BuiltinType::Matrix4x4 }, - { "variant", strlen("variant"), QV4::CompiledData::BuiltinType::Variant }, - { "var", strlen("var"), QV4::CompiledData::BuiltinType::Var } - }; - static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) / - sizeof(propTypeNameToTypes[0]); - if (node->type == QQmlJS::AST::UiPublicMember::Signal) { Signal *signal = New(); QString signalName = node->name.toString(); @@ -807,7 +839,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) signal->location.line = loc.startLine; signal->location.column = loc.startColumn; - signal->parameters = New >(); + signal->parameters = New >(); QQmlJS::AST::UiParameterList *p = node->parameters; while (p) { @@ -818,38 +850,13 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) return false; } - const TypeNameToType *type = nullptr; - for (int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) { - const TypeNameToType *t = propTypeNameToTypes + typeIndex; - if (memberType == QLatin1String(t->name, static_cast(t->nameLength))) { - type = t; - break; - } - } - - SignalParameter *param = New(); - - if (!type) { - if (memberType.at(0).isUpper()) { - // Must be a QML object type. - // Lazily determine type during compilation. - param->indexIsBuiltinType = false; - param->typeNameIndexOrBuiltinType = registerString(memberType); - Q_ASSERT(quint32(jsGenerator->getStringId(memberType)) < (1u << 31)); - } else { - QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: "); - errStr.append(memberType); - recordError(node->typeToken, errStr); - return false; - } - } else { - // the parameter is a known basic type - param->indexIsBuiltinType = true; - param->typeNameIndexOrBuiltinType = static_cast(type->type); - Q_ASSERT(quint32(type->type) < (1u << 31)); + Parameter *param = New(); + if (!param->init(jsGenerator, p->name.toString(), memberType)) { + QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: "); + errStr.append(memberType); + recordError(node->typeToken, errStr); + return false; } - - param->nameIndex = registerString(p->name.toString()); signal->parameters->append(param); p = p->next; } @@ -875,15 +882,10 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) Property *property = New(); property->isReadOnly = node->isReadonlyMember; - bool typeFound = false; - - for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) { - const TypeNameToType *t = propTypeNameToTypes + ii; - if (memberType == QLatin1String(t->name, static_cast(t->nameLength))) { - property->setBuiltinType(t->type); - typeFound = true; - } - } + QV4::CompiledData::BuiltinType builtinPropertyType = Parameter::stringToBuiltinType(memberType); + bool typeFound = builtinPropertyType != QV4::CompiledData::BuiltinType::InvalidBuiltin; + if (typeFound) + property->setBuiltinType(builtinPropertyType); if (!typeFound && memberType.at(0).isUpper()) { const QStringRef &typeModifier = node->typeModifier; @@ -1696,7 +1698,7 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen signalToWrite->nParameters = s->parameters->count; QV4::CompiledData::Parameter *parameterToWrite = reinterpret_cast(signalPtr + sizeof(*signalToWrite)); - for (SignalParameter *param = s->parameters->first; param; param = param->next, ++parameterToWrite) + for (Parameter *param = s->parameters->first; param; param = param->next, ++parameterToWrite) *parameterToWrite = *param; int size = QV4::CompiledData::Signal::calculateSize(s->parameters->count); diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index cf47bea4db..2b8d7dfcce 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -216,22 +216,26 @@ struct Enum }; -struct SignalParameter : public QV4::CompiledData::Parameter +struct Parameter : public QV4::CompiledData::Parameter { - SignalParameter *next; + Parameter *next; + + bool init(QV4::Compiler::JSUnitGenerator *stringGenerator, const QString ¶meterName, const QString &typeName); + + static QV4::CompiledData::BuiltinType stringToBuiltinType(const QString &typeName); }; struct Signal { int nameIndex; QV4::CompiledData::Location location; - PoolList *parameters; + PoolList *parameters; QStringList parameterStringList(const QV4::Compiler::StringTableGenerator *stringPool) const; int parameterCount() const { return parameters->count; } - PoolList::Iterator parametersBegin() const { return parameters->begin(); } - PoolList::Iterator parametersEnd() const { return parameters->end(); } + PoolList::Iterator parametersBegin() const { return parameters->begin(); } + PoolList::Iterator parametersEnd() const { return parameters->end(); } Signal *next; }; diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index f3d5de3db1..1ee5c6a195 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -608,15 +608,21 @@ enum class BuiltinType : unsigned int { Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion, InvalidBuiltin }; -struct Parameter +struct ParameterType { - quint32_le nameIndex; union { quint32 _dummy; quint32_le_bitfield<0, 1> indexIsBuiltinType; quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType; }; }; +static_assert(sizeof(ParameterType) == 4, "ParameterType structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); + +struct Parameter +{ + quint32_le nameIndex; + ParameterType type; +}; static_assert(sizeof(Parameter) == 8, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); struct Signal -- cgit v1.2.3