Skip to content

Commit 2f0658b

Browse files
committed
PEP 384-8-HT-4: Successful Restart using PyType_FromSpec
Status on 2018-05-04 macOS subset build: Python 2: all works. Python 3 release (PEP): all works. Python 3 debug: untested. This version supports Python 2 with a backport of PyType_FromSpec. This fourth step is a complete rewrite of the former approach. The last approach did not really work, because the creation of heaptypes has certain assumptions which cannot be circumvented without breaking the API. . The new attempt is very promising since it already works without errors for pysidesignal.cpp . I will continue this in the hope that no new problems arise. Note: This code works currently only on Python 3. To support Python 2, either the old structures must be re-added, or we must implement the PyType_FromSpec function. (Problem: 'slot'-keyword!) Task-number: PYSIDE-595 Change-Id: I05abe542fc82fa51b5c881ca1cda756fb12bf090
1 parent d029c17 commit 2f0658b

File tree

6 files changed

+1021
-194
lines changed

6 files changed

+1021
-194
lines changed

sources/pyside2/libpyside/pysidesignal.cpp

Lines changed: 65 additions & 194 deletions
Original file line numberDiff line numberDiff line change
@@ -93,166 +93,75 @@ static PyObject* signalCall(PyObject*, PyObject*, PyObject*);
9393

9494
static PyObject* metaSignalCheck(PyObject*, PyObject*);
9595

96-
static PyMappingMethods Signal_as_mapping = {
97-
0,
98-
signalGetItem,
99-
0
100-
};
96+
97+
// PYSIDE-595: Avoid trouble by keeping everything as it was.
98+
// The automatically added tp_dealloc is wrong, because the code
99+
// took care about this, already.
100+
// We can refine this later if we want.
101+
static void
102+
dummyDealloc(PyObject *)
103+
{}
101104

102105
static PyMethodDef Signal_methods[] = {
103106
{"__instancecheck__", (PyCFunction)metaSignalCheck, METH_O, NULL},
104107
{0, 0, 0, 0}
105108
};
106109

107-
static void
108-
dummy_dealloc(PyObject *)
109-
{
110-
111-
}
112-
// this function is only temporarily here.
113-
PyTypeObject *initHeaptype(PyTypeObject *type)
114-
{
115-
PyTypeObject *ret;
116-
117-
if (PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
118-
type->tp_flags &= ~Py_TPFLAGS_HEAPTYPE;
119-
type->tp_flags |= Py_TPFLAGS_BASETYPE;
120-
if (PyType_Ready(type) < 0)
121-
return nullptr;
122-
PyObject *args = Py_BuildValue("(s(OO){})", type->tp_name, type, &PyBaseObject_Type);
123-
PyTypeObject *meta = &PyType_Type;
124-
PyType_Ready(meta);
125-
ret = reinterpret_cast<PyTypeObject *>(
126-
PyType_Type.tp_new(meta, args, nullptr));
127-
if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC) &&
128-
ret->tp_flags & Py_TPFLAGS_HAVE_GC) {
129-
fprintf(stderr, "%s has grown GC, error in sight!\n", ret->tp_name);
130-
ret->tp_flags &= ~Py_TPFLAGS_HAVE_GC;
131-
ret->tp_free = PyObject_Del;
132-
ret->tp_dealloc = dummy_dealloc;
133-
}
134-
}
135-
else
136-
ret = type;
137-
return ret;
138-
}
139-
140-
// this one has no problems with heaptype conversion
141-
static PyTypeObject PySideSignalMetaType = {
142-
PyVarObject_HEAD_INIT(0, 0)
143-
/*tp_name*/ "PySide2.QtCore.MetaSignal",
144-
/*tp_basicsize*/ sizeof(PyHeapTypeObject),
145-
/*tp_itemsize*/ 0,
146-
/*tp_dealloc*/ 0,
147-
/*tp_print*/ 0,
148-
/*tp_getattr*/ 0,
149-
/*tp_setattr*/ 0,
150-
/*tp_compare*/ 0,
151-
/*tp_repr*/ 0,
152-
/*tp_as_number*/ 0,
153-
/*tp_as_sequence*/ 0,
154-
/*tp_as_mapping*/ 0,
155-
/*tp_hash*/ 0,
156-
/*tp_call*/ 0,
157-
/*tp_str*/ 0,
158-
/*tp_getattro*/ 0,
159-
/*tp_setattro*/ 0,
160-
/*tp_as_buffer*/ 0,
161-
/*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HEAPTYPE,
162-
/*tp_doc*/ 0,
163-
/*tp_traverse*/ 0,
164-
/*tp_clear*/ 0,
165-
/*tp_richcompare*/ 0,
166-
/*tp_weaklistoffset*/ 0,
167-
/*tp_iter*/ 0,
168-
/*tp_iternext*/ 0,
169-
/*tp_methods*/ Signal_methods,
170-
/*tp_members*/ 0,
171-
/*tp_getset*/ 0,
172-
/*tp_base*/ &PyType_Type,
173-
/*tp_dict*/ 0,
174-
/*tp_descr_get*/ 0,
175-
/*tp_descr_set*/ 0,
176-
/*tp_dictoffset*/ 0,
177-
/*tp_init*/ 0,
178-
/*tp_alloc*/ 0,
179-
/*tp_new*/ 0,
180-
/*tp_free*/ PyObject_GC_Del,
181-
/*tp_is_gc*/ 0,
182-
/*tp_bases*/ 0,
183-
/*tp_mro*/ 0,
184-
/*tp_cache*/ 0,
185-
/*tp_subclasses*/ 0,
186-
/*tp_weaklist*/ 0,
187-
/*tp_del*/ 0,
188-
/*tp_version_tag*/ 0
110+
static PyType_Slot PySideSignalMetaType_slots[] = {
111+
{Py_tp_methods, (void *)Signal_methods},
112+
{Py_tp_base, (void *)&PyType_Type},
113+
{Py_tp_free, (void *)PyObject_GC_Del},
114+
{Py_tp_dealloc, (void *)dummyDealloc},
115+
{0, 0}
116+
};
117+
static PyType_Spec PySideSignalMetaType_spec = {
118+
"PySide2.QtCore.MetaSignal",
119+
sizeof(PyHeapTypeObject),
120+
0,
121+
Py_TPFLAGS_DEFAULT,
122+
PySideSignalMetaType_slots,
189123
};
190124

125+
191126
PyTypeObject *PySideSignalMetaTypeF(void)
192127
{
193128
static PyTypeObject *type = nullptr;
194-
if (type == nullptr)
195-
type = initHeaptype(&PySideSignalMetaType);
129+
if (type == nullptr) {
130+
PyObject *bases = Py_BuildValue("(O)", &PyType_Type);
131+
type = (PyTypeObject *)PyType_FromSpecWithBases(&PySideSignalMetaType_spec, bases);
132+
Py_XDECREF(bases);
133+
}
196134
return type;
197135
}
198136

199-
// Problems with heaptype!
200-
static PyTypeObject PySideSignalType = {
201-
PyVarObject_HEAD_INIT(nullptr, 0)
202-
/*tp_name*/ "PySide2.QtCore." SIGNAL_CLASS_NAME,
203-
/*tp_basicsize*/ sizeof(PySideSignal),
204-
/*tp_itemsize*/ 0,
205-
/*tp_dealloc*/ 0,
206-
/*tp_print*/ 0,
207-
/*tp_getattr*/ 0,
208-
/*tp_setattr*/ 0,
209-
/*tp_compare*/ 0,
210-
/*tp_repr*/ 0,
211-
/*tp_as_number*/ 0,
212-
/*tp_as_sequence*/ 0,
213-
/*tp_as_mapping*/ &Signal_as_mapping,
214-
/*tp_hash*/ 0,
215-
/*tp_call*/ signalCall,
216-
/*tp_str*/ signalToString,
217-
/*tp_getattro*/ 0,
218-
/*tp_setattro*/ 0,
219-
/*tp_as_buffer*/ 0,
220-
/*tp_flags*/ Py_TPFLAGS_DEFAULT/*|Py_TPFLAGS_HEAPTYPE*/,
221-
/*tp_doc*/ SIGNAL_CLASS_NAME,
222-
/*tp_traverse*/ 0,
223-
/*tp_clear*/ 0,
224-
/*tp_richcompare*/ 0,
225-
/*tp_weaklistoffset*/ 0,
226-
/*tp_iter*/ 0,
227-
/*tp_iternext*/ 0,
228-
/*tp_methods*/ 0,
229-
/*tp_members*/ 0,
230-
/*tp_getset*/ 0,
231-
/*tp_base*/ 0,
232-
/*tp_dict*/ 0,
233-
/*tp_descr_get*/ 0,
234-
/*tp_descr_set*/ 0,
235-
/*tp_dictoffset*/ 0,
236-
/*tp_init*/ signalTpInit,
237-
/*tp_alloc*/ 0,
238-
/*tp_new*/ PyType_GenericNew,
239-
/*tp_free*/ signalFree,
240-
/*tp_is_gc*/ 0,
241-
/*tp_bases*/ 0,
242-
/*tp_mro*/ 0,
243-
/*tp_cache*/ 0,
244-
/*tp_subclasses*/ 0,
245-
/*tp_weaklist*/ 0,
246-
/*tp_del*/ 0,
247-
/*tp_version_tag*/ 0
137+
static PyType_Slot PySideSignalType_slots[] = {
138+
{Py_mp_subscript, (void *)signalGetItem},
139+
{Py_tp_call, (void *)signalCall},
140+
{Py_tp_str, (void *)signalToString},
141+
{Py_tp_init, (void *)signalTpInit},
142+
{Py_tp_new, (void *)PyType_GenericNew},
143+
{Py_tp_free, (void *)signalFree},
144+
{Py_tp_dealloc, (void *)dummyDealloc},
145+
{0, 0}
146+
};
147+
static PyType_Spec PySideSignalType_spec = {
148+
"PySide2.QtCore." SIGNAL_CLASS_NAME,
149+
sizeof(PySideSignal),
150+
0,
151+
Py_TPFLAGS_DEFAULT,
152+
PySideSignalType_slots,
248153
};
249154

155+
250156
PyTypeObject *PySideSignalTypeF(void)
251157
{
252158
static PyTypeObject *type = nullptr;
253159
if (type == nullptr) {
254-
Py_TYPE(&PySideSignalType) = PySideSignalMetaTypeF();
255-
type = initHeaptype(&PySideSignalType);
160+
type = (PyTypeObject *)PyType_FromSpec(&PySideSignalType_spec);
161+
PyTypeObject *hold = Py_TYPE(type);
162+
Py_TYPE(type) = PySideSignalMetaTypeF();
163+
Py_INCREF(Py_TYPE(type));
164+
Py_DECREF(hold);
256165
}
257166
return type;
258167
}
@@ -264,68 +173,30 @@ static PyMethodDef SignalInstance_methods[] = {
264173
{0, 0, 0, 0} /* Sentinel */
265174
};
266175

267-
static PyMappingMethods SignalInstance_as_mapping = {
176+
static PyType_Slot PySideSignalInstanceType_slots[] = {
177+
//{Py_tp_as_mapping, (void *)&SignalInstance_as_mapping},
178+
{Py_mp_subscript, (void *)signalInstanceGetItem},
179+
{Py_tp_call, (void *)signalInstanceCall},
180+
{Py_tp_methods, (void *)SignalInstance_methods},
181+
{Py_tp_new, (void *)PyType_GenericNew},
182+
{Py_tp_free, (void *)signalInstanceFree},
183+
{Py_tp_dealloc, (void *)dummyDealloc},
184+
{0, 0}
185+
};
186+
static PyType_Spec PySideSignalInstanceType_spec = {
187+
"PySide2.QtCore." SIGNAL_INSTANCE_NAME,
188+
sizeof(PySideSignalInstance),
268189
0,
269-
signalInstanceGetItem,
270-
0
190+
Py_TPFLAGS_DEFAULT,
191+
PySideSignalInstanceType_slots,
271192
};
272193

273-
// Problems with heaptype!
274-
static PyTypeObject PySideSignalInstanceType = {
275-
PyVarObject_HEAD_INIT(0, 0)
276-
/*tp_name*/ "PySide2.QtCore." SIGNAL_INSTANCE_NAME,
277-
/*tp_basicsize*/ sizeof(PySideSignalInstance),
278-
/*tp_itemsize*/ 0,
279-
/*tp_dealloc*/ 0,
280-
/*tp_print*/ 0,
281-
/*tp_getattr*/ 0,
282-
/*tp_setattr*/ 0,
283-
/*tp_compare*/ 0,
284-
/*tp_repr*/ 0,
285-
/*tp_as_number*/ 0,
286-
/*tp_as_sequence*/ 0,
287-
/*tp_as_mapping*/ &SignalInstance_as_mapping,
288-
/*tp_hash*/ 0,
289-
/*tp_call*/ signalInstanceCall,
290-
/*tp_str*/ 0,
291-
/*tp_getattro*/ 0,
292-
/*tp_setattro*/ 0,
293-
/*tp_as_buffer*/ 0,
294-
/*tp_flags*/ Py_TPFLAGS_DEFAULT/*|Py_TPFLAGS_HEAPTYPE*/,
295-
/*tp_doc*/ SIGNAL_INSTANCE_NAME,
296-
/*tp_traverse*/ 0,
297-
/*tp_clear*/ 0,
298-
/*tp_richcompare*/ 0,
299-
/*tp_weaklistoffset*/ 0,
300-
/*tp_iter*/ 0,
301-
/*tp_iternext*/ 0,
302-
/*tp_methods*/ SignalInstance_methods,
303-
/*tp_members*/ 0,
304-
/*tp_getset*/ 0,
305-
/*tp_base*/ 0,
306-
/*tp_dict*/ 0,
307-
/*tp_descr_get*/ 0,
308-
/*tp_descr_set*/ 0,
309-
/*tp_dictoffset*/ 0,
310-
/*tp_init*/ 0,
311-
/*tp_alloc*/ 0,
312-
/*tp_new*/ PyType_GenericNew,
313-
/*tp_free*/ signalInstanceFree,
314-
/*tp_is_gc*/ 0,
315-
/*tp_bases*/ 0,
316-
/*tp_mro*/ 0,
317-
/*tp_cache*/ 0,
318-
/*tp_subclasses*/ 0,
319-
/*tp_weaklist*/ 0,
320-
/*tp_del*/ 0,
321-
/*tp_version_tag*/ 0
322-
};
323194

324195
PyTypeObject *PySideSignalInstanceTypeF(void)
325196
{
326197
static PyTypeObject *type = nullptr;
327198
if (type == nullptr)
328-
type = initHeaptype(&PySideSignalInstanceType);
199+
type = (PyTypeObject *)PyType_FromSpec(&PySideSignalInstanceType_spec);
329200
return type;
330201
}
331202

sources/shiboken2/libshiboken/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ signature.cpp
5050
qapp_macro.cpp
5151
pep384resolve.cpp
5252
voidptr.cpp
53+
typespec.cpp
5354
)
5455

5556
get_numpy_location()
@@ -94,6 +95,7 @@ install(FILES
9495
signature.h
9596
qapp_macro.h
9697
voidptr.h
98+
typespec.h
9799
"${CMAKE_CURRENT_BINARY_DIR}/sbkversion.h"
98100
DESTINATION include/shiboken2${shiboken2_SUFFIX})
99101
install(TARGETS libshiboken EXPORT shiboken2

sources/shiboken2/libshiboken/basewrapper.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,6 +1391,7 @@ void deallocData(SbkObject* self, bool cleanup)
13911391
}
13921392
delete self->d; // PYSIDE-205: always delete d.
13931393
Py_XDECREF(self->ob_dict);
1394+
13941395
// PYSIDE-571: qApp is no longer allocated.
13951396
if (PyObject_IS_GC((PyObject*)self))
13961397
Py_TYPE(self)->tp_free(self);

sources/shiboken2/libshiboken/sbkpython.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include "python25compat.h"
4848
#include "shibokenmacros.h"
4949
#include "pep384resolve.h"
50+
#include "typespec.h"
5051

5152
#if PY_MAJOR_VERSION >= 3
5253
#define IS_PY3K

0 commit comments

Comments
 (0)