From 4ed39bed4e119792a8da9445691ba16d5beac30a Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Sun, 3 Aug 2014 13:14:17 +0200 Subject: moc: Move the property access code to the qt_static_metacall That way we will be able to access property of objects that are not QObject (Q_GADGET) Change-Id: Ib8ef6e52fc621e0b0d6530f82b1aa205f1ed5fd9 Reviewed-by: Simon Hausmann Reviewed-by: Thiago Macieira --- src/corelib/kernel/qmetaobject.cpp | 29 +++- src/corelib/kernel/qmetaobject_p.h | 4 +- src/tools/moc/generator.cpp | 295 ++++++++++++++++++++----------------- 3 files changed, 188 insertions(+), 140 deletions(-) diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index b54cb0c344..f351f228fd 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Olivier Goffart ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -2837,8 +2838,13 @@ QVariant QMetaProperty::read(const QObject *object) const // Try to register the type and try again before reporting an error. int registerResult = -1; void *argv[] = { ®isterResult }; - QMetaObject::metacall(const_cast(object), QMetaObject::RegisterPropertyMetaType, - idx + mobj->propertyOffset(), argv); + if ((priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall) && mobj->d.static_metacall) { + mobj->d.static_metacall(const_cast(object), QMetaObject::RegisterPropertyMetaType, + idx, argv); + } else { + QMetaObject::metacall(const_cast(object), QMetaObject::RegisterPropertyMetaType, + idx + mobj->propertyOffset(), argv); + } if (registerResult == -1) { qWarning("QMetaProperty::read: Unable to handle unregistered datatype '%s' for property '%s::%s'", typeName, mobj->className(), name()); return QVariant(); @@ -2861,8 +2867,12 @@ QVariant QMetaProperty::read(const QObject *object) const value = QVariant(t, (void*)0); argv[0] = value.data(); } - QMetaObject::metacall(const_cast(object), QMetaObject::ReadProperty, - idx + mobj->propertyOffset(), argv); + if (priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall) { + mobj->d.static_metacall(const_cast(object), QMetaObject::ReadProperty, idx, argv); + } else { + QMetaObject::metacall(const_cast(object), QMetaObject::ReadProperty, + idx + mobj->propertyOffset(), argv); + } if (status != -1) return value; @@ -2932,7 +2942,11 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const argv[0] = &v; else argv[0] = v.data(); - QMetaObject::metacall(object, QMetaObject::WriteProperty, idx + mobj->propertyOffset(), argv); + if (priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall) + mobj->d.static_metacall(object, QMetaObject::WriteProperty, idx, argv); + else + QMetaObject::metacall(object, QMetaObject::WriteProperty, idx + mobj->propertyOffset(), argv); + return status; } @@ -2949,7 +2963,10 @@ bool QMetaProperty::reset(QObject *object) const if (!object || !mobj || !isResettable()) return false; void *argv[] = { 0 }; - QMetaObject::metacall(object, QMetaObject::ResetProperty, idx + mobj->propertyOffset(), argv); + if (priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall) + mobj->d.static_metacall(object, QMetaObject::ResetProperty, idx, argv); + else + QMetaObject::metacall(object, QMetaObject::ResetProperty, idx + mobj->propertyOffset(), argv); return true; } diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h index c08838e456..45fe56ec8a 100644 --- a/src/corelib/kernel/qmetaobject_p.h +++ b/src/corelib/kernel/qmetaobject_p.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Olivier Goffart ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -98,7 +99,8 @@ enum MethodFlags { enum MetaObjectFlags { DynamicMetaObject = 0x01, - RequiresVariantMetaObject = 0x02 + RequiresVariantMetaObject = 0x02, + PropertyAccessInStaticMetaCall = 0x04 // since Qt 5.5, property code is in the static metacall }; enum MetaDataFlags { diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index b9c46300e4..acc635c5ca 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -359,7 +359,13 @@ void Generator::generateCode() fprintf(out, " %4d, %4d, // constructors\n", isConstructible ? cdef->constructorList.count() : 0, isConstructible ? index : 0); - fprintf(out, " %4d, // flags\n", 0); + int flags = 0; + if (cdef->hasQGadget) { + // Ideally, all the classes could have that flag. But this broke classes generated + // by qdbusxml2cpp which generate code that require that we call qt_metacall for properties + flags |= PropertyAccessInStaticMetaCall; + } + fprintf(out, " %4d, // flags\n", flags); fprintf(out, " %4d, // signalCount\n", cdef->signalList.count()); @@ -425,7 +431,8 @@ void Generator::generateCode() // // Generate internal qt_static_metacall() function // - const bool hasStaticMetaCall = (cdef->hasQObject || !cdef->methodList.isEmpty()) && !isQt; + const bool hasStaticMetaCall = !isQt && + (cdef->hasQObject || !cdef->methodList.isEmpty() || !cdef->propertyList.isEmpty()); if (hasStaticMetaCall) generateStaticMetacall(); @@ -920,10 +927,6 @@ void Generator::generateMetacall() } if (cdef->propertyList.size()) { - bool needGet = false; - bool needTempVarForGet = false; - bool needSet = false; - bool needReset = false; bool needDesignable = false; bool needScriptable = false; bool needStored = false; @@ -931,132 +934,21 @@ void Generator::generateMetacall() bool needUser = false; for (int i = 0; i < cdef->propertyList.size(); ++i) { const PropertyDef &p = cdef->propertyList.at(i); - needGet |= !p.read.isEmpty() || !p.member.isEmpty(); - if (!p.read.isEmpty() || !p.member.isEmpty()) - needTempVarForGet |= (p.gspec != PropertyDef::PointerSpec - && p.gspec != PropertyDef::ReferenceSpec); - - needSet |= !p.write.isEmpty() || (!p.member.isEmpty() && !p.constant); - needReset |= !p.reset.isEmpty(); needDesignable |= p.designable.endsWith(')'); needScriptable |= p.scriptable.endsWith(')'); needStored |= p.stored.endsWith(')'); needEditable |= p.editable.endsWith(')'); needUser |= p.user.endsWith(')'); } - fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n "); + fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n "); if (needElse) - fprintf(out, " else "); - fprintf(out, "if (_c == QMetaObject::ReadProperty) {\n"); - if (needGet) { - if (needTempVarForGet) - fprintf(out, " void *_v = _a[0];\n"); - fprintf(out, " switch (_id) {\n"); - for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { - const PropertyDef &p = cdef->propertyList.at(propindex); - if (p.read.isEmpty() && p.member.isEmpty()) - continue; - QByteArray prefix; - if (p.inPrivateClass.size()) { - prefix = p.inPrivateClass; - prefix.append("->"); - } - if (p.gspec == PropertyDef::PointerSpec) - fprintf(out, " case %d: _a[0] = const_cast(reinterpret_cast(%s%s())); break;\n", - propindex, prefix.constData(), p.read.constData()); - else if (p.gspec == PropertyDef::ReferenceSpec) - fprintf(out, " case %d: _a[0] = const_cast(reinterpret_cast(&%s%s())); break;\n", - propindex, prefix.constData(), p.read.constData()); - else if (cdef->enumDeclarations.value(p.type, false)) - fprintf(out, " case %d: *reinterpret_cast(_v) = QFlag(%s%s()); break;\n", - propindex, prefix.constData(), p.read.constData()); - else if (!p.read.isEmpty()) - fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s(); break;\n", - propindex, p.type.constData(), prefix.constData(), p.read.constData()); - else - fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s; break;\n", - propindex, p.type.constData(), prefix.constData(), p.member.constData()); - } - fprintf(out, " default: break;\n"); - fprintf(out, " }\n"); - } - + fprintf(out, "else "); fprintf(out, - " _id -= %d;\n" - " }", cdef->propertyList.count()); - - fprintf(out, " else "); - fprintf(out, "if (_c == QMetaObject::WriteProperty) {\n"); - - if (needSet) { - fprintf(out, " void *_v = _a[0];\n"); - fprintf(out, " switch (_id) {\n"); - for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { - const PropertyDef &p = cdef->propertyList.at(propindex); - if (p.constant) - continue; - if (p.write.isEmpty() && p.member.isEmpty()) - continue; - QByteArray prefix; - if (p.inPrivateClass.size()) { - prefix = p.inPrivateClass; - prefix.append("->"); - } - if (cdef->enumDeclarations.value(p.type, false)) { - fprintf(out, " case %d: %s%s(QFlag(*reinterpret_cast(_v))); break;\n", - propindex, prefix.constData(), p.write.constData()); - } else if (!p.write.isEmpty()) { - fprintf(out, " case %d: %s%s(*reinterpret_cast< %s*>(_v)); break;\n", - propindex, prefix.constData(), p.write.constData(), p.type.constData()); - } else { - fprintf(out, " case %d:\n", propindex); - fprintf(out, " if (%s%s != *reinterpret_cast< %s*>(_v)) {\n", - prefix.constData(), p.member.constData(), p.type.constData()); - fprintf(out, " %s%s = *reinterpret_cast< %s*>(_v);\n", - prefix.constData(), p.member.constData(), p.type.constData()); - if (!p.notify.isEmpty() && p.notifyId != -1) { - const FunctionDef &f = cdef->signalList.at(p.notifyId); - if (f.arguments.size() == 0) - fprintf(out, " Q_EMIT %s();\n", p.notify.constData()); - else if (f.arguments.size() == 1 && f.arguments.at(0).normalizedType == p.type) - fprintf(out, " Q_EMIT %s(%s%s);\n", - p.notify.constData(), prefix.constData(), p.member.constData()); - } - fprintf(out, " }\n"); - fprintf(out, " break;\n"); - } - } - fprintf(out, " default: break;\n"); - fprintf(out, " }\n"); - } - - fprintf(out, - " _id -= %d;\n" - " }", cdef->propertyList.count()); - - fprintf(out, " else "); - fprintf(out, "if (_c == QMetaObject::ResetProperty) {\n"); - if (needReset) { - fprintf(out, " switch (_id) {\n"); - for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { - const PropertyDef &p = cdef->propertyList.at(propindex); - if (!p.reset.endsWith(')')) - continue; - QByteArray prefix; - if (p.inPrivateClass.size()) { - prefix = p.inPrivateClass; - prefix.append("->"); - } - fprintf(out, " case %d: %s%s; break;\n", - propindex, prefix.constData(), p.reset.constData()); - } - fprintf(out, " default: break;\n"); - fprintf(out, " }\n"); - } - fprintf(out, - " _id -= %d;\n" - " }", cdef->propertyList.count()); + "if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty\n" + " || _c == QMetaObject::ResetProperty || _c == QMetaObject::RegisterPropertyMetaType) {\n" + " qt_static_metacall(this, _c, _id, _a);\n" + " _id -= %d;\n }", cdef->propertyList.count()); fprintf(out, " else "); fprintf(out, "if (_c == QMetaObject::QueryPropertyDesignable) {\n"); @@ -1154,16 +1046,6 @@ void Generator::generateMetacall() " _id -= %d;\n" " }", cdef->propertyList.count()); - fprintf(out, " else "); - fprintf(out, "if (_c == QMetaObject::RegisterPropertyMetaType) {\n"); - fprintf(out, " if (_id < %d)\n", cdef->propertyList.size()); - - if (automaticPropertyMetaTypesHelper().isEmpty()) - fprintf(out, " *reinterpret_cast(_a[0]) = -1;\n"); - else - fprintf(out, " qt_static_metacall(this, _c, _id, _a);\n"); - fprintf(out, " _id -= %d;\n }", cdef->propertyList.size()); - fprintf(out, "\n#endif // QT_NO_PROPERTIES"); } if (methodList.size() || cdef->signalList.size() || cdef->propertyList.size()) @@ -1382,6 +1264,153 @@ void Generator::generateStaticMetacall() needElse = true; } + if (!cdef->propertyList.empty()) { + bool needGet = false; + bool needTempVarForGet = false; + bool needSet = false; + bool needReset = false; + for (int i = 0; i < cdef->propertyList.size(); ++i) { + const PropertyDef &p = cdef->propertyList.at(i); + needGet |= !p.read.isEmpty() || !p.member.isEmpty(); + if (!p.read.isEmpty() || !p.member.isEmpty()) + needTempVarForGet |= (p.gspec != PropertyDef::PointerSpec + && p.gspec != PropertyDef::ReferenceSpec); + + needSet |= !p.write.isEmpty() || (!p.member.isEmpty() && !p.constant); + needReset |= !p.reset.isEmpty(); + } + fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n "); + + if (needElse) + fprintf(out, "else "); + fprintf(out, "if (_c == QMetaObject::ReadProperty) {\n"); + if (needGet) { + if (cdef->hasQObject) { +#ifndef QT_NO_DEBUG + fprintf(out, " Q_ASSERT(staticMetaObject.cast(_o));\n"); +#endif + fprintf(out, " %s *_t = static_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData()); + } else { + fprintf(out, " %s *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData()); + } + if (needTempVarForGet) + fprintf(out, " void *_v = _a[0];\n"); + fprintf(out, " switch (_id) {\n"); + for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { + const PropertyDef &p = cdef->propertyList.at(propindex); + if (p.read.isEmpty() && p.member.isEmpty()) + continue; + QByteArray prefix = "_t->"; + if (p.inPrivateClass.size()) { + prefix += p.inPrivateClass + "->"; + } + if (p.gspec == PropertyDef::PointerSpec) + fprintf(out, " case %d: _a[0] = const_cast(reinterpret_cast(%s%s())); break;\n", + propindex, prefix.constData(), p.read.constData()); + else if (p.gspec == PropertyDef::ReferenceSpec) + fprintf(out, " case %d: _a[0] = const_cast(reinterpret_cast(&%s%s())); break;\n", + propindex, prefix.constData(), p.read.constData()); + else if (cdef->enumDeclarations.value(p.type, false)) + fprintf(out, " case %d: *reinterpret_cast(_v) = QFlag(%s%s()); break;\n", + propindex, prefix.constData(), p.read.constData()); + else if (!p.read.isEmpty()) + fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s(); break;\n", + propindex, p.type.constData(), prefix.constData(), p.read.constData()); + else + fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s; break;\n", + propindex, p.type.constData(), prefix.constData(), p.member.constData()); + } + fprintf(out, " default: break;\n"); + fprintf(out, " }\n"); + } + + fprintf(out, " }"); + + fprintf(out, " else "); + fprintf(out, "if (_c == QMetaObject::WriteProperty) {\n"); + + if (needSet) { + if (cdef->hasQObject) { +#ifndef QT_NO_DEBUG + fprintf(out, " Q_ASSERT(staticMetaObject.cast(_o));\n"); +#endif + fprintf(out, " %s *_t = static_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData()); + } else { + fprintf(out, " %s *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData()); + } + fprintf(out, " void *_v = _a[0];\n"); + fprintf(out, " switch (_id) {\n"); + for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { + const PropertyDef &p = cdef->propertyList.at(propindex); + if (p.constant) + continue; + if (p.write.isEmpty() && p.member.isEmpty()) + continue; + QByteArray prefix = "_t->"; + if (p.inPrivateClass.size()) { + prefix += p.inPrivateClass + "->"; + } + if (cdef->enumDeclarations.value(p.type, false)) { + fprintf(out, " case %d: %s%s(QFlag(*reinterpret_cast(_v))); break;\n", + propindex, prefix.constData(), p.write.constData()); + } else if (!p.write.isEmpty()) { + fprintf(out, " case %d: %s%s(*reinterpret_cast< %s*>(_v)); break;\n", + propindex, prefix.constData(), p.write.constData(), p.type.constData()); + } else { + fprintf(out, " case %d:\n", propindex); + fprintf(out, " if (%s%s != *reinterpret_cast< %s*>(_v)) {\n", + prefix.constData(), p.member.constData(), p.type.constData()); + fprintf(out, " %s%s = *reinterpret_cast< %s*>(_v);\n", + prefix.constData(), p.member.constData(), p.type.constData()); + if (!p.notify.isEmpty() && p.notifyId != -1) { + const FunctionDef &f = cdef->signalList.at(p.notifyId); + if (f.arguments.size() == 0) + fprintf(out, " Q_EMIT _t->%s();\n", p.notify.constData()); + else if (f.arguments.size() == 1 && f.arguments.at(0).normalizedType == p.type) + fprintf(out, " Q_EMIT _t->%s(%s%s);\n", + p.notify.constData(), prefix.constData(), p.member.constData()); + } + fprintf(out, " }\n"); + fprintf(out, " break;\n"); + } + } + fprintf(out, " default: break;\n"); + fprintf(out, " }\n"); + } + + fprintf(out, " }"); + + fprintf(out, " else "); + fprintf(out, "if (_c == QMetaObject::ResetProperty) {\n"); + if (needReset) { + if (cdef->hasQObject) { +#ifndef QT_NO_DEBUG + fprintf(out, " Q_ASSERT(staticMetaObject.cast(_o));\n"); +#endif + fprintf(out, " %s *_t = static_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData()); + } else { + fprintf(out, " %s *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData()); + } + fprintf(out, " switch (_id) {\n"); + for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { + const PropertyDef &p = cdef->propertyList.at(propindex); + if (!p.reset.endsWith(')')) + continue; + QByteArray prefix = "_t->"; + if (p.inPrivateClass.size()) { + prefix += p.inPrivateClass + "->"; + } + fprintf(out, " case %d: %s%s; break;\n", + propindex, prefix.constData(), p.reset.constData()); + } + fprintf(out, " default: break;\n"); + fprintf(out, " }\n"); + } + fprintf(out, " }"); + fprintf(out, "\n#endif // QT_NO_PROPERTIES"); + needElse = true; + } + if (needElse) fprintf(out, "\n"); -- cgit v1.2.3