diff options
author | Christian Tismer <tismer@stackless.com> | 2021-09-11 15:51:02 +0200 |
---|---|---|
committer | Christian Tismer <tismer@stackless.com> | 2021-09-15 15:57:07 +0200 |
commit | d0678ae7cac8f80a5b80042edb13335f438bb9ce (patch) | |
tree | 007f401ccdfc2075a9b9aef8e83829b469b46e94 | |
parent | 203e8961ecd8b94211845f4f6519788e34dd3230 (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.cpp | 5 | ||||
-rw-r--r-- | sources/pyside6/libpyside/pysideproperty.cpp | 2 | ||||
-rw-r--r-- | sources/pyside6/libpyside/pysidesignal.cpp | 9 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/CMakeLists.txt | 2 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/basewrapper.cpp | 64 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/basewrapper.h | 7 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/sbkenum.cpp | 7 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/sbktypefactory.cpp | 130 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/sbktypefactory.h | 61 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/voidptr.cpp | 8 |
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; } |