aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2021-09-11 15:51:02 +0200
committerChristian Tismer <tismer@stackless.com>2021-09-15 15:57:07 +0200
commitd0678ae7cac8f80a5b80042edb13335f438bb9ce (patch)
tree007f401ccdfc2075a9b9aef8e83829b469b46e94
parent203e8961ecd8b94211845f4f6519788e34dd3230 (diff)
PyPySide: Encapsulate type generation to be PyPy compatible
Type generation in PyPy is critical. When type creation calls PyType_Ready, PyPy freezes the current state of the type object. That has fatal effects, because with the Limited API, we need to patch some types a little _after_ creation. The functionality of this patch is still the same, but type creation is totally encapsulated, and we can do a different implementation for PyPy. [ChangeLog][PySide6] PyPySide: Type creation was completely encapsulated. The implementation can now be rewritten for PyPy. Task-number: PYSIDE-535 Change-Id: Iae0cadb15b631344ae76cea8c104d4b69941c2b0 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
-rw-r--r--sources/pyside6/libpyside/class_property.cpp5
-rw-r--r--sources/pyside6/libpyside/pysideproperty.cpp2
-rw-r--r--sources/pyside6/libpyside/pysidesignal.cpp9
-rw-r--r--sources/shiboken6/libshiboken/CMakeLists.txt2
-rw-r--r--sources/shiboken6/libshiboken/basewrapper.cpp64
-rw-r--r--sources/shiboken6/libshiboken/basewrapper.h7
-rw-r--r--sources/shiboken6/libshiboken/sbkenum.cpp7
-rw-r--r--sources/shiboken6/libshiboken/sbktypefactory.cpp130
-rw-r--r--sources/shiboken6/libshiboken/sbktypefactory.h61
-rw-r--r--sources/shiboken6/libshiboken/voidptr.cpp8
10 files changed, 212 insertions, 83 deletions
diff --git a/sources/pyside6/libpyside/class_property.cpp b/sources/pyside6/libpyside/class_property.cpp
index 63850be07..74ee79e4d 100644
--- a/sources/pyside6/libpyside/class_property.cpp
+++ b/sources/pyside6/libpyside/class_property.cpp
@@ -92,7 +92,7 @@ static PyType_Slot PyClassProperty_slots[] = {
};
static PyType_Spec PyClassProperty_spec = {
- "PySide6.QtCore.PyClassProperty",
+ "2:PySide6.QtCore.PyClassProperty",
sizeof(propertyobject),
0,
Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
@@ -105,8 +105,7 @@ PyTypeObject *PyClassPropertyTypeF()
if (type == nullptr) {
// Provide the same `tp_getset`, which is not inherited.
PyClassProperty_slots[0].pfunc = PyProperty_Type.tp_getset;
- type = reinterpret_cast<PyTypeObject *>(
- PyType_FromSpec(&PyClassProperty_spec));
+ type = SbkType_FromSpec(&PyClassProperty_spec);
}
return type;
}
diff --git a/sources/pyside6/libpyside/pysideproperty.cpp b/sources/pyside6/libpyside/pysideproperty.cpp
index 70c59a89a..9f9340e19 100644
--- a/sources/pyside6/libpyside/pysideproperty.cpp
+++ b/sources/pyside6/libpyside/pysideproperty.cpp
@@ -106,7 +106,7 @@ static PyType_Slot PySidePropertyType_slots[] = {
{Py_tp_getset, PySidePropertyType_getset},
{0, nullptr}
};
-// Dotted modulename is crucial for SbkType_FromSpec to work. Is this name right?
+
static PyType_Spec PySidePropertyType_spec = {
"2:PySide6.QtCore.Property",
sizeof(PySideProperty),
diff --git a/sources/pyside6/libpyside/pysidesignal.cpp b/sources/pyside6/libpyside/pysidesignal.cpp
index 2ecae7287..842311fae 100644
--- a/sources/pyside6/libpyside/pysidesignal.cpp
+++ b/sources/pyside6/libpyside/pysidesignal.cpp
@@ -165,14 +165,7 @@ static PyType_Spec PySideSignalType_spec = {
PyTypeObject *PySideSignalTypeF(void)
{
- static PyTypeObject *type = nullptr;
- if (!type) {
- type = reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&PySideSignalType_spec));
- PyTypeObject *hold = Py_TYPE(type);
- Py_TYPE(type) = PySideMetaSignalTypeF();
- Py_INCREF(Py_TYPE(type));
- Py_DECREF(hold);
- }
+ static auto *type = SbkType_FromSpecWithMeta(&PySideSignalType_spec, PySideMetaSignalTypeF());
return type;
}
diff --git a/sources/shiboken6/libshiboken/CMakeLists.txt b/sources/shiboken6/libshiboken/CMakeLists.txt
index b07f305a1..3e1b14594 100644
--- a/sources/shiboken6/libshiboken/CMakeLists.txt
+++ b/sources/shiboken6/libshiboken/CMakeLists.txt
@@ -54,6 +54,7 @@ sbkfeature_base.cpp
sbkmodule.cpp
sbkstring.cpp
sbkstaticstrings.cpp
+sbktypefactory.cpp
bindingmanager.cpp
threadstatesaver.cpp
shibokenbuffer.cpp
@@ -136,6 +137,7 @@ install(FILES
sbkmodule.h
sbkstring.h
sbkstaticstrings.h
+ sbktypefactory.h
shiboken.h
shibokenmacros.h
threadstatesaver.h
diff --git a/sources/shiboken6/libshiboken/basewrapper.cpp b/sources/shiboken6/libshiboken/basewrapper.cpp
index f72951dd1..0c2ac950e 100644
--- a/sources/shiboken6/libshiboken/basewrapper.cpp
+++ b/sources/shiboken6/libshiboken/basewrapper.cpp
@@ -251,14 +251,12 @@ static const char *SbkObject_SignatureStrings[] = {
PyTypeObject *SbkObject_TypeF(void)
{
- static PyTypeObject *type = nullptr;
- if (!type) {
- type = reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&SbkObject_Type_spec));
- Py_TYPE(type) = SbkObjectType_TypeF();
- Py_INCREF(Py_TYPE(type));
- type->tp_weaklistoffset = offsetof(SbkObject, weakreflist);
- type->tp_dictoffset = offsetof(SbkObject, ob_dict);
- }
+ static auto *type = SbkType_FromSpec_BMDWB(&SbkObject_Type_spec,
+ nullptr, // bases
+ SbkObjectType_TypeF(),
+ offsetof(SbkObject, ob_dict),
+ offsetof(SbkObject, weakreflist),
+ nullptr); // bufferprocs
return type;
}
@@ -606,51 +604,6 @@ PyObject *SbkDummyNew(PyTypeObject *type, PyObject *, PyObject *)
return nullptr;
}
-PyTypeObject *SbkType_FromSpec(PyType_Spec *spec)
-{
- return SbkType_FromSpecWithBases(spec, nullptr);
-}
-
-PyTypeObject *SbkType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
-{
- // PYSIDE-1286: Generate correct __module__ and __qualname__
- // The name field can now be extended by an "n:" prefix which is
- // the number of modules in the name. The default is 1.
- //
- // Example:
- // "2:mainmod.submod.mainclass.subclass"
- // results in
- // __module__ : "mainmod.submod"
- // __qualname__ : "mainclass.subclass"
- // __name__ : "subclass"
-
- PyType_Spec new_spec = *spec;
- const char *colon = strchr(spec->name, ':');
- assert(colon);
- int package_level = atoi(spec->name);
- const char *mod = new_spec.name = colon + 1;
-
- PyObject *obType = PyType_FromSpecWithBases(&new_spec, bases);
- if (obType == nullptr)
- return nullptr;
-
- const char *qual = mod;
- for (int idx = package_level; idx > 0; --idx) {
- const char *dot = strchr(qual, '.');
- if (!dot)
- break;
- qual = dot + 1;
- }
- int mlen = qual - mod - 1;
- Shiboken::AutoDecRef module(Shiboken::String::fromCString(mod, mlen));
- Shiboken::AutoDecRef qualname(Shiboken::String::fromCString(qual));
- if (PyObject_SetAttr(obType, Shiboken::PyMagicName::module(), module) < 0)
- return nullptr;
- if (PyObject_SetAttr(obType, Shiboken::PyMagicName::qualname(), qualname) < 0)
- return nullptr;
- return reinterpret_cast<PyTypeObject *>(obType);
-}
-
// PYSIDE-74: Fallback used in all types now.
PyObject *FallbackRichCompare(PyObject *self, PyObject *other, int op)
{
@@ -930,10 +883,7 @@ introduceWrapperType(PyObject *enclosingObject,
{
typeSpec->slots[0].pfunc = reinterpret_cast<void *>(baseType ? baseType : SbkObject_TypeF());
- auto *heaptype = SbkType_FromSpecWithBases(typeSpec, baseTypes);
- Py_TYPE(heaptype) = SbkObjectType_TypeF();
- Py_INCREF(Py_TYPE(heaptype));
- auto *type = reinterpret_cast<PyTypeObject *>(heaptype);
+ auto *type = SbkType_FromSpecBasesMeta(typeSpec, baseTypes, SbkObjectType_TypeF());
if (baseType) {
if (baseTypes) {
for (int i = 0; i < PySequence_Fast_GET_SIZE(baseTypes); ++i) {
diff --git a/sources/shiboken6/libshiboken/basewrapper.h b/sources/shiboken6/libshiboken/basewrapper.h
index 010870f55..2c8da098f 100644
--- a/sources/shiboken6/libshiboken/basewrapper.h
+++ b/sources/shiboken6/libshiboken/basewrapper.h
@@ -42,6 +42,7 @@
#include "sbkpython.h"
#include "shibokenmacros.h"
+#include "sbktypefactory.h"
#include <vector>
#include <string>
@@ -130,17 +131,13 @@ LIBSHIBOKEN_API PyObject *MakeQAppWrapper(PyTypeObject *type);
* PYSIDE-832: Use object_dealloc instead of nullptr.
*
* When moving to heaptypes, we were struck by a special default behavior of
- * PyType_FromSpecWithBases that inserts subtype_dealloc when tp_dealloc is
+ * PyType_FromSpec that inserts subtype_dealloc when tp_dealloc is
* nullptr. But the default before conversion to heaptypes was to assign
* object_dealloc. This seems to be a bug in the Limited API.
*/
/// PYSIDE-939: Replaced by Sbk_object_dealloc.
LIBSHIBOKEN_API PyObject *SbkDummyNew(PyTypeObject *type, PyObject *, PyObject *);
-/// PYSIDE-1286: Generate correct __module__ and __qualname__
-LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpec(PyType_Spec *);
-LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpecWithBases(PyType_Spec *, PyObject *);
-
/// PYSIDE-74: Fallback used in all types now.
LIBSHIBOKEN_API PyObject *FallbackRichCompare(PyObject *self, PyObject *other, int op);
diff --git a/sources/shiboken6/libshiboken/sbkenum.cpp b/sources/shiboken6/libshiboken/sbkenum.cpp
index bf9c80303..a6f65c7ab 100644
--- a/sources/shiboken6/libshiboken/sbkenum.cpp
+++ b/sources/shiboken6/libshiboken/sbkenum.cpp
@@ -675,7 +675,7 @@ newTypeWithName(const char *name,
PyType_Slot newslots[99] = {}; // enough but not too big for the stack
PyType_Spec newspec;
DeclaredEnumTypes::EnumEntry entry{strdup(name), nullptr};
- newspec.name = entry.name; // Note that SbkType_FromSpecWithBases might use a substring.
+ newspec.name = entry.name; // Note that SbkType_FromSpec might use a substring.
newspec.basicsize = SbkNewEnum_spec.basicsize;
newspec.itemsize = SbkNewEnum_spec.itemsize;
newspec.flags = SbkNewEnum_spec.flags;
@@ -693,9 +693,8 @@ newTypeWithName(const char *name,
static auto basetype = reinterpret_cast<PyObject *>(SbkEnum_TypeF());
Py_INCREF(basetype);
PyTuple_SetItem(bases, 0, basetype);
- auto *type = SbkType_FromSpecWithBases(&newspec, bases);
- entry.type = reinterpret_cast<PyTypeObject *>(type);
- Py_TYPE(type) = SbkEnumType_TypeF();
+ auto *type = SbkType_FromSpecBasesMeta(&newspec, bases, SbkEnumType_TypeF());
+ entry.type = type;
auto *enumType = reinterpret_cast<SbkEnumType *>(type);
auto *setp = PepType_SETP(enumType);
diff --git a/sources/shiboken6/libshiboken/sbktypefactory.cpp b/sources/shiboken6/libshiboken/sbktypefactory.cpp
new file mode 100644
index 000000000..bdde7598f
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbktypefactory.cpp
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "sbktypefactory.h"
+#include "shiboken.h"
+
+extern "C"
+{
+
+PyTypeObject *SbkType_FromSpec(PyType_Spec *spec)
+{
+ return SbkType_FromSpec_BMDWB(spec, nullptr, nullptr, 0, 0, nullptr);
+}
+
+PyTypeObject *SbkType_FromSpecWithMeta(PyType_Spec *spec, PyTypeObject *meta)
+{
+ return SbkType_FromSpec_BMDWB(spec, nullptr, meta, 0, 0, nullptr);
+}
+
+PyTypeObject *SbkType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
+{
+ return SbkType_FromSpec_BMDWB(spec, bases, nullptr, 0, 0, nullptr);
+}
+
+PyTypeObject *SbkType_FromSpecBasesMeta(PyType_Spec *spec, PyObject *bases, PyTypeObject *meta)
+{
+ return SbkType_FromSpec_BMDWB(spec, bases, meta, 0, 0, nullptr);
+}
+
+PyTypeObject *SbkType_FromSpec_BMDWB(PyType_Spec *spec,
+ PyObject *bases,
+ PyTypeObject *meta,
+ int dictoffset,
+ int weaklistoffset,
+ PyBufferProcs *bufferprocs)
+{
+ // PYSIDE-1286: Generate correct __module__ and __qualname__
+ // The name field can now be extended by an "n:" prefix which is
+ // the number of modules in the name. The default is 1.
+ //
+ // Example:
+ // "2:mainmod.submod.mainclass.subclass"
+ // results in
+ // __module__ : "mainmod.submod"
+ // __qualname__ : "mainclass.subclass"
+ // __name__ : "subclass"
+
+ PyType_Spec new_spec = *spec;
+ const char *colon = strchr(spec->name, ':');
+ assert(colon);
+ int package_level = atoi(spec->name);
+ const char *mod = new_spec.name = colon + 1;
+
+ PyObject *obType = PyType_FromSpecWithBases(&new_spec, bases);
+ if (obType == nullptr)
+ return nullptr;
+
+ const char *qual = mod;
+ for (int idx = package_level; idx > 0; --idx) {
+ const char *dot = strchr(qual, '.');
+ if (!dot)
+ break;
+ qual = dot + 1;
+ }
+ int mlen = qual - mod - 1;
+ Shiboken::AutoDecRef module(Shiboken::String::fromCString(mod, mlen));
+ Shiboken::AutoDecRef qualname(Shiboken::String::fromCString(qual));
+ if (PyObject_SetAttr(obType, Shiboken::PyMagicName::module(), module) < 0)
+ return nullptr;
+ if (PyObject_SetAttr(obType, Shiboken::PyMagicName::qualname(), qualname) < 0)
+ return nullptr;
+
+ auto *type = reinterpret_cast<PyTypeObject *>(obType);
+
+ if (meta) {
+ PyTypeObject *hold = Py_TYPE(type);
+ Py_TYPE(type) = meta;
+ Py_INCREF(Py_TYPE(type));
+ if (hold->tp_flags & Py_TPFLAGS_HEAPTYPE)
+ Py_DECREF(hold);
+ }
+
+ if (dictoffset)
+ type->tp_dictoffset = dictoffset;
+ if (weaklistoffset)
+ type->tp_weaklistoffset = weaklistoffset;
+ if (bufferprocs)
+ PepType_AS_BUFFER(type) = bufferprocs;
+
+ PyType_Modified(type);
+ return type;
+}
+
+} //extern "C"
diff --git a/sources/shiboken6/libshiboken/sbktypefactory.h b/sources/shiboken6/libshiboken/sbktypefactory.h
new file mode 100644
index 000000000..092c168b6
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbktypefactory.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SBKTYPEFACTORY_H
+#define SBKTYPEFACTORY_H
+
+#include "sbkpython.h"
+
+extern "C"
+{
+
+LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpec(PyType_Spec *);
+LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpecWithMeta(PyType_Spec *, PyTypeObject *);
+LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpecWithBases(PyType_Spec *, PyObject *);
+LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpecBasesMeta(PyType_Spec *, PyObject *, PyTypeObject *);
+LIBSHIBOKEN_API PyTypeObject *SbkType_FromSpec_BMDWB(PyType_Spec *spec,
+ PyObject *bases,
+ PyTypeObject *meta,
+ int dictoffset,
+ int weaklistoffset,
+ PyBufferProcs *bufferprocs);
+
+} //extern "C"
+
+#endif // SBKTYPEFACTORY_H
diff --git a/sources/shiboken6/libshiboken/voidptr.cpp b/sources/shiboken6/libshiboken/voidptr.cpp
index ff6f6cfd5..f0161d282 100644
--- a/sources/shiboken6/libshiboken/voidptr.cpp
+++ b/sources/shiboken6/libshiboken/voidptr.cpp
@@ -318,11 +318,9 @@ static PyType_Spec SbkVoidPtrType_spec = {
PyTypeObject *SbkVoidPtrTypeF(void)
{
- static PyTypeObject *type = nullptr;
- if (!type) {
- type = SbkType_FromSpec(&SbkVoidPtrType_spec);
- PepType_AS_BUFFER(type) = &SbkVoidPtrObjectBufferProc;
- }
+ static PyTypeObject *type = SbkType_FromSpec_BMDWB(&SbkVoidPtrType_spec,
+ nullptr, nullptr, 0, 0,
+ &SbkVoidPtrObjectBufferProc);
return type;
}