[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-bindings
Subject:    [Kde-bindings] KDE/kdebindings/generator/generators/smoke
From:       Arno Rehn <kde () arnorehn ! de>
Date:       2010-06-10 23:33:27
Message-ID: 20100610233327.E804BAC8D3 () svn ! kde ! org
[Download RAW message or body]

SVN commit 1136866 by arnorehn:

Fix this long-standing bug in SMOKE:

Previously, a method call through SMOKE would always call a specific implementation, \
even though dynamic dispatch would be the correct calling way. The problem was to \
distinguish between cases where dynamic dispatch is the correct way of calling and \
cases where that specific method and nothing else should be called.

This is now fixed in the following way: if an object is created through smoke (i.e. \
it's really an x_Foo class), then we DO NOT use dynamic dispatch, so calls to the \
parent implemenation of a method will work.

However, if the object is not an x_Foo class (i.e. it was returned by some other \
method), then we use dynamic dispatch, so internal classes that are not wrapped by \
the bindings will still work (e.g. subclasses of KPluginFactory, KParts::Part, \
etc...).

A virtual method call now looks like this:

        // virtual const QMetaObject* metaObject() const
        if (typeid(*this) == typeid(x_QObject)) {
            const QMetaObject* xret = ((const \
x_QObject*)this)->QObject::metaObject();  x[0].s_class = (void*)xret;
        } else {
            const QMetaObject* xret = ((const x_QObject*)this)->metaObject();
            x[0].s_class = (void*)xret;
        }

The overhead for the typeid() calls should be minimal. The information is either \
provided at compile time or directly retrieved from the vtable.

CCMAIL: kde-bindings@kde.org

 M  +1 -0      globals.h  
 M  +42 -14    writeClasses.cpp  


--- trunk/KDE/kdebindings/generator/generators/smoke/globals.h #1136865:1136866
@@ -86,6 +86,7 @@
     void write(const QList<QString>& keys);
 
 private:
+    QString generateMethodBody(const QString& indent, const QString& className, \
const QString& smokeClassName, const Method& meth, int index, bool dynamicDispatch, \
                QSet< QString >& includes);
     void generateMethod(QTextStream& out, const QString& className, const QString& \
                smokeClassName, const Method& meth, int index, QSet<QString>& \
                includes);
     void generateGetAccessor(QTextStream& out, const QString& className, const \
                Field& field, const Type* type, int index);
     void generateSetAccessor(QTextStream& out, const QString& className, const \
                Field& field, const Type* type, int index);
--- trunk/KDE/kdebindings/generator/generators/smoke/writeClasses.cpp \
#1136865:1136866 @@ -91,16 +91,14 @@
     }
 }
 
-void SmokeClassFiles::generateMethod(QTextStream& out, const QString& className, \
                const QString& smokeClassName,
-                                     const Method& meth, int index, QSet<QString>& \
includes) +QString SmokeClassFiles::generateMethodBody(const QString& indent, const \
QString& className, const QString& smokeClassName, const Method& meth, +              \
int index, bool dynamicDispatch, QSet<QString>& includes)  {
-    out << "    ";
-    if ((meth.flags() & Method::Static) || meth.isConstructor())
-        out << "static ";
-    out << QString("void x_%1(Smoke::Stack x) {\n").arg(index);
-    out << "        // " << meth.toString() << "\n";
-    out << "        ";
+    QString methodBody;
+    QTextStream out(&methodBody);
     
+    out << indent;
+
     if (meth.isConstructor()) {
         out << smokeClassName << "* xret = new " << smokeClassName << "(";
     } else {
@@ -123,8 +121,8 @@
                 out << "this->";
             }
         }
-        if (!(meth.flags() & Method::PureVirtual) && !(meth.flags() & \
                Method::DynamicDispatch) && !func) {
-            // dynamic dispatch for virtuals
+        if (!dynamicDispatch && !func) {
+            // dynamic dispatch not wanted, call with 'this->Foo::method()'
             out << className << "::";
         } else if (func) {
             if (!func->nameSpace().isEmpty())
@@ -159,8 +157,7 @@
         out << "(" << typeName << ")" << "x[" << j + 1 << "]." << field;
     }
     
-    // if the method has any other default parameters, append them here as values, \
                so 
-    
+    // if the method has any other default parameters, append them here as values
     if (!meth.remainingDefaultValues().isEmpty()) {
         const QStringList& defaultParams = meth.remainingDefaultValues();
         if (meth.parameters().count() > 0)
@@ -170,13 +167,44 @@
     
     out << ");\n";
     if (meth.type() != Type::Void) {
-        out << "        x[0]." << Util::stackItemField(meth.type()) << " = " << \
Util::assignmentString(meth.type(), "xret") << ";\n"; +        out << indent << \
"x[0]." << Util::stackItemField(meth.type()) << " = " << \
Util::assignmentString(meth.type(), "xret") << ";\n";  } else {
-        out << "        (void)x; // noop (for compiler warning)\n";
+        out << indent << "(void)x; // noop (for compiler warning)\n";
     }
     
+    return methodBody;
+}
+
+void SmokeClassFiles::generateMethod(QTextStream& out, const QString& className, \
const QString& smokeClassName, +                                     const Method& \
meth, int index, QSet<QString>& includes) +{
+    out << "    ";
+    if ((meth.flags() & Method::Static) || meth.isConstructor())
+        out << "static ";
+    out << QString("void x_%1(Smoke::Stack x) {\n").arg(index);
+    out << "        // " << meth.toString() << "\n";
+
+    bool dynamicDispatch = ((meth.flags() & Method::PureVirtual) || (meth.flags() & \
Method::DynamicDispatch)); +
+    if (dynamicDispatch || \
!Util::virtualMethodsForClass(meth.getClass()).contains(&meth)) { +        // This is \
either already flagged as dynamic dispatch or just a normal method. We can generate a \
normal method call for it. +
+        out << generateMethodBody("        ",   // indent
+                                  className, smokeClassName, meth, index, \
dynamicDispatch, includes); +    } else {
+        // This is a virtual method. To know whether we should call with dynamic \
dispatch, we need a bit of RTTI magic. +        includes.insert("typeinfo");
+        out << "        if (typeid(*this) == typeid(" << smokeClassName << ")) {\n"; \
// +        out << generateMethodBody("            ",   // indent
+                                  className, smokeClassName, meth, index, false, \
includes); +        out << "        } else {\n";
+        out << generateMethodBody("            ",   // indent
+                                  className, smokeClassName, meth, index, true, \
includes);  out << "    }\n";
+    }
     
+    out << "    }\n";
+    
     // If the constructor was generated from another one with default parameteres, \
                we don't need to explicitly create
     // it here again. The x_* call will append the default parameters at the end and \
                thus choose the right constructor.
     if (meth.isConstructor() && meth.remainingDefaultValues().isEmpty()) {
_______________________________________________
Kde-bindings mailing list
Kde-bindings@kde.org
https://mail.kde.org/mailman/listinfo/kde-bindings


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic