[PySide] [Stackless] PySide problem, take #2: typeobject clash

Christian Tismer tismer at stackless.com
Tue Oct 22 21:42:22 CEST 2013


On 22.10.13 18:27, Christian Tismer wrote:
> On 22.10.13 16:24, John Ehresman wrote:
>>> On 21.10.13 22:10, John Ehresman wrote:
>>>>
>>>> I think I see the problem; to me, at least, it's useful to see the
>>>> stackless version of object.h at
>>>> http://www.stackless.com/browser/Include/object.h  It looks like
>>>> stackless moves the fields defined in PyHeapTypeObject into
>>>> PyTypeObject, adds at least one additional field, and then #define's
>>>> PyHeapTypeObject to PyTypeObject.  This leads to two problems, which
>>>> are somewhat separable --
>>>>
>>>> 1) When compiling, there is no ht_type field in PyHeapTypeObject. This
>>>> is what Christian's patch addresses.
>>
>> Wouldn't it be possible to use something like the following in 
>> shiboken's basewrapper.h (untested code below):
>>
>> /// PyTypeObject extended with C++ multiple inheritance information.
>> #ifndef STACKLESS
>>
>> struct LIBSHIBOKEN_API SbkObjectType
>> {
>>     PyHeapTypeObject super;
>>     SbkObjectTypePrivate* d;
>> };
>>
>> #else // STACKLESS
>>
>> // Work around stackless's modification of PyTypeObject and 
>> PyHeapTypeObject
>> struct LIBSHIBOKEN_API SbkObjectType
>> {
>>     struct {
>>         PyTypeObject ht_type;
>>     } super;
>>     SbkObjectTypePrivate* d;
>> };
>>
>> #endif
>>
>> This would have the advantage of not sprinkling macros across the 
>> code base.  It does not address the binary compatibility problem.
>
> Hmm, good idea!
> That would really be a minimal patch with much less ugliness and clutter.
> Well, not sure yet if I want to try that really right now...maybe

Tried this -- does not work.
While a good idea, the introduced differences are too big to go away with
this simple trick.
The thing breaks in for instance

> /Users/tismer/src/pyside-setup/pyside_build/py2.7-qt4.8.5-64bit-release/pyside/PySide/QtCore/PySide/QtCore/qbitarray_wrapper.cpp:1626:38: 
> error: no member named 'as_number' in 'SbkObjectType::<anonymous 
> struct at 
> /Users/tismer/src/pyside-setup/pyside_install/py2.7-qt4.8.5-64bit-release/include/shiboken/basewrapper.h:99:5>'
>     memset(&Sbk_QBitArray_Type.super.as_number, 0, 
> sizeof(PyNumberMethods));
>             ~~~~~~~~~~~~~~~~~~~~~~~~ ^

The problem is difficult because in stackless object.h we have at the 
end of typeobject:

415	#ifdef STACKLESS

416	    /* we need the extended structure right here */
417	    PyNumberMethods as_number;
418	    PyMappingMethods as_mapping;
419	    PySequenceMethods as_sequence; /* as_sequence comes after as_mapping,
420	                                      so that the mapping wins when both
421	                                      the mapping and the sequence define
422	                                      a given operator (e.g. __getitem__).
423	                                      see add_operators() in typeobject.c . */
424	    PyBufferProcs as_buffer;
425	    PyObject *ht_name, *ht_slots;
426	    slp_methodflags slpflags;
427	#endif
428	} PyTypeObject;

These fields are embedded into typeobject, without the ht_type around it.

I tried the following:

// Work around stackless's modification of PyTypeObject and PyHeapTypeObject
struct LIBSHIBOKEN_API SbkObjectType
{
     union {
         struct {
             PyTypeObject ht_type;
         } super;
         PyTypeObject super;
     };
     SbkObjectTypePrivate* d;
};

but that doesn't work, because "super" may not occur twice.

A possible, but even more ugly solution would be to do a union,
where we have the following layout:

// Work around stackless's modification of PyTypeObject and PyHeapTypeObject
struct LIBSHIBOKEN_API SbkObjectType
{
     union {
         struct {
             PyTypeObject ht_type;
         };
         <insert all of the object fields here, loong list>
     } super;
     SbkObjectTypePrivate* d;
};


I tried this modification and it works!
Unfortunately with verbose copying of all fields...
This is a bit ugly, but could be made better by a little script that extracts
all the fields from object.h and builds an include file dynamically.

I have the impression that changing it this way would make the patch even worse.
And all the things that have now my macroes, will eventually change, anyway,
when we go to Version 2 with runtime compatibile layout.

On the other hand:
I could put this whole craziness into stackless itself. That would then
work without changing PySide at all, just recompile...

What do you think?

cheers - Chris

(patch attached)

-- 
Christian Tismer             :^)   <mailto:tismer at stackless.com>
Software Consulting          :     Have a break! Take a ride on Python's
Karl-Liebknecht-Str. 121     :    *Starship* http://starship.python.net/
14482 Potsdam                :     PGP key -> http://pgp.uni-mainz.de
phone +49 173 24 18 776  fax +49 (30) 700143-0023
PGP 0x57F3BF04       9064 F4E1 D754 C2FF 1619  305B C09C 5A3B 57F3 BF04
       whom do you want to sponsor today?   http://www.stackless.com/

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/pyside/attachments/20131022/e3c3a065/attachment.html>
-------------- next part --------------
From 26dbbe41fcda3cc2d16baed6c0268f97e4f2451c Mon Sep 17 00:00:00 2001
From: Christian Tismer <tismer at stackless.com>
Date: Sun, 20 Oct 2013 21:19:15 +0200
Subject: [PATCH] combined stackless patch

About this patch
----------------

This is a minimal patch that makes compilation of PySide work with
Stackless Python. It involves PySide and Shiboken, so the one cannot go
without the other. The change ids are:

Shiboken:
Change-Id: I9f713dbadaee8227bc27b932a5623325c98020a9

PySide:
Change-Id: I636a086e57eb5b02ef1918ecdafd70676eb544ba

The problem was the different layout of frames in stackless, where the
field "ht_type" does not exist. Instead, stackless always uses the extended
type, and all fields are accessible without "ht_type".

For more details about the structure differences, see
http://stackless.com/browser/Include/object.h

I introduced a few macros which put these differences into a central place:
    sbkpython.h
and made sure that this file is always included, also in all generated files.
This is actually just syntactic sugar: The generated code is identical for
CPython.

Tested to build correctly on OS X with

stackless on python 2.7.5
plain python 2.7.5
plain python 3.3

Migration of this patch
-----------------------

The reason that I wrote this was to convince myself that Stackless Python
and PySide can work together. As mentioned on the mailing list, this is just
a proof of concept. The real solution is to change PySide in a way that the
same binaries work with CPython and Stackless Python.

As soon as I can come up with a better solution that works without an extra
compilation, I will migrate to a new patch. I know it can be done, because some
other well-known project already does it.

At the moment I'm happy that this works, and I would like to be able to tell
people that they can use this interims solution to work with Stackless PySide
at all.

Cheers - Chris

Change-Id: I9f713dbadaee8227bc27b932a5623325c98020a9
---
 libshiboken/basewrapper.h | 120 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 120 insertions(+)

diff --git a/libshiboken/basewrapper.h b/libshiboken/basewrapper.h
index 7885c50..d9c6cfb 100644
--- a/libshiboken/basewrapper.h
+++ b/libshiboken/basewrapper.h
@@ -81,13 +81,133 @@ extern LIBSHIBOKEN_API SbkObjectType SbkObject_Type;
 
 
 struct SbkObjectTypePrivate;
+
 /// PyTypeObject extended with C++ multiple inheritance information.
+#ifndef STACKLESS
+
 struct LIBSHIBOKEN_API SbkObjectType
 {
     PyHeapTypeObject super;
     SbkObjectTypePrivate* d;
 };
 
+#else // STACKLESS
+
+// Work around stackless's modification of PyTypeObject and PyHeapTypeObject
+struct LIBSHIBOKEN_API SbkObjectType
+{
+    union {
+        struct {
+            PyTypeObject ht_type;
+        };
+        struct {
+            PyObject_VAR_HEAD
+            const char *tp_name; /* For printing, in format "<module>.<name>" */
+            Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
+            
+            /* Methods to implement standard operations */
+            
+            destructor tp_dealloc;
+            printfunc tp_print;
+            getattrfunc tp_getattr;
+            setattrfunc tp_setattr;
+            void *tp_reserved; /* formerly known as tp_compare */
+            reprfunc tp_repr;
+            
+            /* Method suites for standard classes */
+            
+            PyNumberMethods *tp_as_number;
+            PySequenceMethods *tp_as_sequence;
+            PyMappingMethods *tp_as_mapping;
+            
+            /* More standard operations (here for binary compatibility) */
+            
+            hashfunc tp_hash;
+            ternaryfunc tp_call;
+            reprfunc tp_str;
+            getattrofunc tp_getattro;
+            setattrofunc tp_setattro;
+            
+            /* Functions to access object as input/output buffer */
+            PyBufferProcs *tp_as_buffer;
+            
+            /* Flags to define presence of optional/expanded features */
+            long tp_flags;
+            
+            const char *tp_doc; /* Documentation string */
+            
+            /* Assigned meaning in release 2.0 */
+            /* call function for all accessible objects */
+            traverseproc tp_traverse;
+            
+            /* delete references to contained objects */
+            inquiry tp_clear;
+            
+            /* Assigned meaning in release 2.1 */
+            /* rich comparisons */
+            richcmpfunc tp_richcompare;
+            
+            /* weak reference enabler */
+            Py_ssize_t tp_weaklistoffset;
+            
+            /* Iterators */
+            getiterfunc tp_iter;
+            iternextfunc tp_iternext;
+            
+            /* Attribute descriptor and subclassing stuff */
+            struct PyMethodDef *tp_methods;
+            struct PyMemberDef *tp_members;
+            struct PyGetSetDef *tp_getset;
+            struct _typeobject *tp_base;
+            PyObject *tp_dict;
+            descrgetfunc tp_descr_get;
+            descrsetfunc tp_descr_set;
+            Py_ssize_t tp_dictoffset;
+            initproc tp_init;
+            allocfunc tp_alloc;
+            newfunc tp_new;
+            freefunc tp_free; /* Low-level free-memory routine */
+            inquiry tp_is_gc; /* For PyObject_IS_GC */
+            PyObject *tp_bases;
+            PyObject *tp_mro; /* method resolution order */
+            PyObject *tp_cache;
+            PyObject *tp_subclasses;
+            PyObject *tp_weaklist;
+            destructor tp_del;
+            
+            /* Type attribute cache version tag. Added in version 2.6 */
+            unsigned int tp_version_tag;
+            
+#ifdef COUNT_ALLOCS
+            /* these must be last and never explicitly initialized */
+            Py_ssize_t tp_allocs;
+            Py_ssize_t tp_frees;
+            Py_ssize_t tp_maxalloc;
+            struct _typeobject *tp_prev;
+            struct _typeobject *tp_next;
+#endif
+#ifdef STACKLESS
+            /* we need the extended structure right here */
+            PyNumberMethods as_number;
+            PyMappingMethods as_mapping;
+            PySequenceMethods as_sequence; /* as_sequence comes after as_mapping,
+                                            so that the mapping wins when both
+                                            the mapping and the sequence define
+                                            a given operator (e.g. __getitem__).
+                                            see add_operators() in typeobject.c . */
+            PyBufferProcs as_buffer;
+            PyObject *ht_name, *ht_slots, *ht_qualname;
+            struct _dictkeysobject *ht_cached_keys;
+            /* here are optional user slots, followed by the members. */
+            slp_methodflags slpflags;
+#endif
+        };
+    } super;
+    SbkObjectTypePrivate* d;
+};
+
+#endif
+
 LIBSHIBOKEN_API PyObject* SbkObjectTpNew(PyTypeObject* subtype, PyObject*, PyObject*);
 
 } // extern "C"
-- 
1.7.11.1



More information about the PySide mailing list