diff options
| author | Christian Tismer <tismer@stackless.com> | 2023-10-08 18:20:39 +0200 |
|---|---|---|
| committer | Christian Tismer <tismer@stackless.com> | 2023-10-09 11:32:10 +0200 |
| commit | 8b9d69fac87cb18777e33103512c8592edd05ff4 (patch) | |
| tree | b862eb3fc03a5d4a4fe87087eeff839c8ad83803 | |
| parent | 65ac5d41a68dac51f85976e22ad2379d659f2f8e (diff) | |
shiboken: Get rid of tp_dict in general
It is a long due task to finally remove the direct access
to type object fields.
With Python 3.12, direct access to tp_dict became
problematic. We use that as a reason to start removing
the direct access in favor of function calls.
Task-number: PYSIDE-2230
Change-Id: I6f8a7479ab0afdbef14d4661f66c3588f3a578aa
Pick-to: 6.2 6.5 6.6
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
| -rw-r--r-- | sources/pyside6/libpyside/dynamicqmetaobject.cpp | 6 | ||||
| -rw-r--r-- | sources/pyside6/libpyside/feature_select.cpp | 40 | ||||
| -rw-r--r-- | sources/pyside6/libpyside/pysidesignal.cpp | 3 | ||||
| -rw-r--r-- | sources/shiboken6/generator/shiboken/cppgenerator_container.cpp | 3 | ||||
| -rw-r--r-- | sources/shiboken6/libshiboken/basewrapper.cpp | 3 | ||||
| -rw-r--r-- | sources/shiboken6/libshiboken/bindingmanager.cpp | 6 | ||||
| -rw-r--r-- | sources/shiboken6/libshiboken/pep384impl.cpp | 12 | ||||
| -rw-r--r-- | sources/shiboken6/libshiboken/pep384impl.h | 4 | ||||
| -rw-r--r-- | sources/shiboken6/libshiboken/sbkcontainer.cpp | 6 | ||||
| -rw-r--r-- | sources/shiboken6/libshiboken/sbkenum.cpp | 8 | ||||
| -rw-r--r-- | sources/shiboken6/libshiboken/sbkfeature_base.cpp | 15 | ||||
| -rw-r--r-- | sources/shiboken6/libshiboken/sbktypefactory.cpp | 7 |
12 files changed, 74 insertions, 39 deletions
diff --git a/sources/pyside6/libpyside/dynamicqmetaobject.cpp b/sources/pyside6/libpyside/dynamicqmetaobject.cpp index 691e66ddc..b7fbc7661 100644 --- a/sources/pyside6/libpyside/dynamicqmetaobject.cpp +++ b/sources/pyside6/libpyside/dynamicqmetaobject.cpp @@ -585,7 +585,8 @@ void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type) // Leave the properties to be registered after signals because they may depend on // notify signals. for (PyTypeObject *baseType : basesToCheck) { - PyObject *attrs = baseType->tp_dict; + AutoDecRef tpDict(PepType_GetDict(baseType)); + PyObject *attrs = tpDict.object(); PyObject *key = nullptr; PyObject *value = nullptr; Py_ssize_t pos = 0; @@ -617,7 +618,8 @@ void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type) // Signals and slots should be separated, unless the types are modified, later. // We check for this using "is_sorted()". Sorting no longer happens at all. for (PyTypeObject *baseType : basesToCheck) { - PyObject *attrs = baseType->tp_dict; + AutoDecRef tpDict(PepType_GetDict(baseType)); + PyObject *attrs = tpDict.object(); PyObject *key = nullptr; PyObject *value = nullptr; Py_ssize_t pos = 0; diff --git a/sources/pyside6/libpyside/feature_select.cpp b/sources/pyside6/libpyside/feature_select.cpp index ec15e6d0a..3f8e38870 100644 --- a/sources/pyside6/libpyside/feature_select.cpp +++ b/sources/pyside6/libpyside/feature_select.cpp @@ -162,7 +162,7 @@ static bool replaceClassDict(PyTypeObject *type) * This is mandatory for all type dicts when they are touched. */ ensureNewDictType(); - auto *dict = type->tp_dict; + AutoDecRef dict(PepType_GetDict(type)); auto *ob_ndt = reinterpret_cast<PyObject *>(new_dict_type); auto *new_dict = PyObject_CallObject(ob_ndt, nullptr); if (new_dict == nullptr || PyDict_Update(new_dict, dict) < 0) @@ -173,8 +173,8 @@ static bool replaceClassDict(PyTypeObject *type) setNextDict(new_dict, new_dict); // We have now an exact copy of the dict with a new type. // Replace `__dict__` which usually has refcount 1 (but see cyclic_test.py) - Py_DECREF(type->tp_dict); - type->tp_dict = new_dict; + Py_DECREF(PepType_GetDict(type)); + PepType_SetDict(type, new_dict); return true; } @@ -184,7 +184,7 @@ static bool addNewDict(PyTypeObject *type, int select_id) * Add a new dict to the ring and set it as `type->tp_dict`. * A 'false' return is fatal. */ - auto *dict = type->tp_dict; + AutoDecRef dict(PepType_GetDict(type)); auto *ob_ndt = reinterpret_cast<PyObject *>(new_dict_type); auto *new_dict = PyObject_CallObject(ob_ndt, nullptr); if (new_dict == nullptr) @@ -194,7 +194,7 @@ static bool addNewDict(PyTypeObject *type, int select_id) auto next_dict = nextInCircle(dict); setNextDict(dict, new_dict); setNextDict(new_dict, next_dict); - type->tp_dict = new_dict; + PepType_SetDict(type, new_dict); return true; } @@ -204,18 +204,19 @@ static inline bool moveToFeatureSet(PyTypeObject *type, int select_id) * Rotate the ring to the given `select_id` and return `true`. * If not found, stay at the current position and return `false`. */ - auto *initial_dict = type->tp_dict; + AutoDecRef tpDict(PepType_GetDict(type)); + auto *initial_dict = tpDict.object(); auto *dict = initial_dict; do { int current_id = getSelectId(dict); // This works because small numbers are singleton objects. if (current_id == select_id) { - type->tp_dict = dict; + PepType_SetDict(type, dict); return true; } dict = nextInCircle(dict); } while (dict != initial_dict); - type->tp_dict = initial_dict; + PepType_SetDict(type, initial_dict); return false; } @@ -234,8 +235,7 @@ static bool createNewFeatureSet(PyTypeObject *type, int select_id) Q_UNUSED(ok); assert(ok); - AutoDecRef prev_dict(type->tp_dict); - Py_INCREF(prev_dict); // keep the first ref unchanged + AutoDecRef prev_dict(PepType_GetDict(type)); if (!addNewDict(type, select_id)) return false; int id = select_id; @@ -245,13 +245,14 @@ static bool createNewFeatureSet(PyTypeObject *type, int select_id) for (int idx = id; *proc != nullptr; ++proc, idx >>= 1) { if (idx & 1) { // clear the tp_dict that will get new content - PyDict_Clear(type->tp_dict); + AutoDecRef tpDict(PepType_GetDict(type)); + PyDict_Clear(tpDict); // let the proc re-fill the tp_dict if (!(*proc)(type, prev_dict, id)) return false; // if there is still a step, prepare `prev_dict` if (idx >> 1) { - prev_dict.reset(PyDict_Copy(type->tp_dict)); + prev_dict.reset(PyDict_Copy(tpDict.object())); if (prev_dict.isNull()) return false; } @@ -267,7 +268,8 @@ static inline void SelectFeatureSetSubtype(PyTypeObject *type, int select_id) * every subclass until no more subclasses or reaching the wanted id. */ static const auto *pyTypeType_tp_dict = PepType_GetDict(&PyType_Type); - if (Py_TYPE(type->tp_dict) == Py_TYPE(pyTypeType_tp_dict)) { + AutoDecRef tpDict(PepType_GetDict(type)); + if (Py_TYPE(tpDict.object()) == Py_TYPE(pyTypeType_tp_dict)) { // On first touch, we initialize the dynamic naming. // The dict type will be replaced after the first call. if (!replaceClassDict(type)) { @@ -322,7 +324,8 @@ static inline void SelectFeatureSet(PyTypeObject *type) * Shiboken will assign it via a public hook of `basewrapper.cpp`. */ static const auto *pyTypeType_tp_dict = PepType_GetDict(&PyType_Type); - if (Py_TYPE(type->tp_dict) == Py_TYPE(pyTypeType_tp_dict)) { + AutoDecRef tpDict(PepType_GetDict(type)); + if (Py_TYPE(tpDict.object()) == Py_TYPE(pyTypeType_tp_dict)) { // We initialize the dynamic features by using our own dict type. if (!replaceClassDict(type)) { Py_FatalError("failed to replace class dict!"); @@ -456,7 +459,8 @@ static PyObject *methodWithNewName(PyTypeObject *type, static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, int /* id */) { PyMethodDef *meth = type->tp_methods; - PyObject *lower_dict = type->tp_dict; + AutoDecRef tpDict(PepType_GetDict(type)); + PyObject *lower_dict = tpDict.object(); // PYSIDE-1702: A user-defined class in Python has no internal method list. // We are not going to change anything. @@ -632,7 +636,8 @@ static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, in */ PyMethodDef *meth = type->tp_methods; - PyObject *prop_dict = type->tp_dict; + AutoDecRef tpDict(PepType_GetDict(type)); + PyObject *prop_dict = tpDict.object(); // The empty `tp_dict` gets populated by the previous dict. if (PyDict_Update(prop_dict, prev_dict) < 0) @@ -765,7 +770,8 @@ static bool patch_property_impl() #define SIMILAR_FEATURE(xx) \ static bool feature_##xx##_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int /* id */) \ { \ - PyObject *dict = type->tp_dict; \ + AutoDecRef tpDict(PepType_GetDict(type)); \ + PyObject *dict = tpDict.object(); \ if (PyDict_Update(dict, prev_dict) < 0) \ return false; \ if (PyDict_SetItemString(dict, "fake_feature_" #xx, Py_None) < 0) \ diff --git a/sources/pyside6/libpyside/pysidesignal.cpp b/sources/pyside6/libpyside/pysidesignal.cpp index 64eb62b76..073e7c2ff 100644 --- a/sources/pyside6/libpyside/pysidesignal.cpp +++ b/sources/pyside6/libpyside/pysidesignal.cpp @@ -1100,7 +1100,8 @@ static typename T::value_type join(T t, const char *sep) static void _addSignalToWrapper(PyTypeObject *wrapperType, const char *signalName, PySideSignal *signal) { - auto typeDict = wrapperType->tp_dict; + AutoDecRef tpDict(PepType_GetDict(wrapperType)); + auto typeDict = tpDict.object(); PyObject *homonymousMethod; if ((homonymousMethod = PyDict_GetItemString(typeDict, signalName))) { Py_INCREF(homonymousMethod); diff --git a/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp b/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp index 7e46cdd02..f746ea714 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp +++ b/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp @@ -221,7 +221,8 @@ CppGenerator::OpaqueContainerData s << "static inline PyTypeObject *" << typeCreationFName << "()\n{\n" << indent << "auto *result = reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&" << specName << "));\nPy_INCREF(Py_True);\n" - << "PyDict_SetItem(result->tp_dict, " + << "Shiboken::AutoDecRef tpDict(PepType_GetDict(result));\n" + << "PyDict_SetItem(tpDict.object(), " "Shiboken::PyMagicName::opaque_container(), Py_True);\n" << "return result;\n" << outdent << "}\n\n"; diff --git a/sources/shiboken6/libshiboken/basewrapper.cpp b/sources/shiboken6/libshiboken/basewrapper.cpp index 66104123f..adeaf6487 100644 --- a/sources/shiboken6/libshiboken/basewrapper.cpp +++ b/sources/shiboken6/libshiboken/basewrapper.cpp @@ -111,7 +111,8 @@ type_set_doc(PyTypeObject *type, PyObject *value, void * /* context */) if (!check_set_special_type_attr(type, value, "__doc__")) return -1; PyType_Modified(type); - return PyDict_SetItem(type->tp_dict, Shiboken::PyMagicName::doc(), value); + Shiboken::AutoDecRef tpDict(PepType_GetDict(type)); + return PyDict_SetItem(tpDict.object(), Shiboken::PyMagicName::doc(), value); } // PYSIDE-908: The function PyType_Modified does not work in PySide, so we need to diff --git a/sources/shiboken6/libshiboken/bindingmanager.cpp b/sources/shiboken6/libshiboken/bindingmanager.cpp index 459efab59..cdb3c311b 100644 --- a/sources/shiboken6/libshiboken/bindingmanager.cpp +++ b/sources/shiboken6/libshiboken/bindingmanager.cpp @@ -330,8 +330,10 @@ PyObject *BindingManager::getOverride(const void *cptr, // The last class in the mro (size - 1) is the base Python object class which should not be tested also. for (int idx = 1; idx < size - 1; ++idx) { auto *parent = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx)); - if (parent->tp_dict) { - defaultMethod = PyDict_GetItem(parent->tp_dict, pyMethodName); + AutoDecRef tpDict(PepType_GetDict(parent)); + auto *parentDict = tpDict.object(); + if (parentDict) { + defaultMethod = PyDict_GetItem(parentDict, pyMethodName); if (defaultMethod) { defaultFound = true; if (function != defaultMethod) diff --git a/sources/shiboken6/libshiboken/pep384impl.cpp b/sources/shiboken6/libshiboken/pep384impl.cpp index 888fbdf5d..348c62120 100644 --- a/sources/shiboken6/libshiboken/pep384impl.cpp +++ b/sources/shiboken6/libshiboken/pep384impl.cpp @@ -115,6 +115,8 @@ check_PyTypeObject_valid() PyObject *d = PyObject_GetAttr(obtype, Shiboken::PyMagicName::dictoffset()); long probe_tp_dictoffset = PyLong_AsLong(d); PyObject *probe_tp_mro = PyObject_GetAttr(obtype, Shiboken::PyMagicName::mro()); + Shiboken::AutoDecRef tpDict(PepType_GetDict(check)); + auto *checkDict = tpDict.object(); if (false || strcmp(probe_tp_name, check->tp_name) != 0 || probe_tp_basicsize != check->tp_basicsize @@ -131,8 +133,8 @@ check_PyTypeObject_valid() || probe_tp_methods != check->tp_methods || probe_tp_getset != check->tp_getset || probe_tp_base != typetype->tp_base - || !PyDict_Check(check->tp_dict) - || !PyDict_GetItemString(check->tp_dict, "dummy") + || !PyDict_Check(checkDict) + || !PyDict_GetItemString(checkDict, "dummy") || probe_tp_descr_get != check->tp_descr_get || probe_tp_descr_set != check->tp_descr_set || probe_tp_dictoffset != typetype->tp_dictoffset @@ -1064,6 +1066,12 @@ PyObject *PepType_GetDict(PyTypeObject *type) #endif // Py_LIMITED_API } +int PepType_SetDict(PyTypeObject *type, PyObject *dict) +{ + type->tp_dict = dict; + return 0; +} + /*************************************************************************** * * PYSIDE-535: The enum/flag error diff --git a/sources/shiboken6/libshiboken/pep384impl.h b/sources/shiboken6/libshiboken/pep384impl.h index 883825f80..0a6e9a1a6 100644 --- a/sources/shiboken6/libshiboken/pep384impl.h +++ b/sources/shiboken6/libshiboken/pep384impl.h @@ -548,6 +548,10 @@ extern LIBSHIBOKEN_API int PepRuntime_38_flag; LIBSHIBOKEN_API PyObject *PepType_GetDict(PyTypeObject *type); +// This function does not exist as PyType_SetDict. But because tp_dict +// is no longer considered to be accessible, we treat it as such. +LIBSHIBOKEN_API int PepType_SetDict(PyTypeObject *type, PyObject *dict); + /***************************************************************************** * * Module Initialization diff --git a/sources/shiboken6/libshiboken/sbkcontainer.cpp b/sources/shiboken6/libshiboken/sbkcontainer.cpp index 13c9f1a29..40fb48527 100644 --- a/sources/shiboken6/libshiboken/sbkcontainer.cpp +++ b/sources/shiboken6/libshiboken/sbkcontainer.cpp @@ -8,9 +8,11 @@ namespace Shiboken { bool isOpaqueContainer(PyObject *o) { + if (!o) + return false; + Shiboken::AutoDecRef tpDict(PepType_GetDict(o->ob_type)); return o != nullptr && o != Py_None - && PyDict_Contains(o->ob_type->tp_dict, - Shiboken::PyMagicName::opaque_container()) == 1; + && PyDict_Contains(tpDict.object(), Shiboken::PyMagicName::opaque_container()) == 1; } } // Shiboken diff --git a/sources/shiboken6/libshiboken/sbkenum.cpp b/sources/shiboken6/libshiboken/sbkenum.cpp index ced75f094..d39369979 100644 --- a/sources/shiboken6/libshiboken/sbkenum.cpp +++ b/sources/shiboken6/libshiboken/sbkenum.cpp @@ -148,10 +148,11 @@ static PyObject *missing_func(PyObject * /* self */ , PyObject *args) if (!PyLong_Check(value)) Py_RETURN_NONE; auto *type = reinterpret_cast<PyTypeObject *>(klass); - auto *sbk_missing = PyDict_GetItem(type->tp_dict, _sbk_missing); + AutoDecRef tpDict(PepType_GetDict(type)); + auto *sbk_missing = PyDict_GetItem(tpDict.object(), _sbk_missing); if (!sbk_missing) { sbk_missing = PyDict_New(); - PyDict_SetItem(type->tp_dict, _sbk_missing, sbk_missing); + PyDict_SetItem(tpDict.object(), _sbk_missing, sbk_missing); } // See if the value is already in the dict. AutoDecRef val_str(PyObject_CallMethod(value, "__str__", nullptr)); @@ -248,7 +249,8 @@ PyObject *newItem(PyTypeObject *enumType, EnumValueType itemValue, return PyObject_CallFunction(obEnumType, "L", itemValue); static PyObject *const _member_map_ = String::createStaticString("_member_map_"); - auto *member_map = PyDict_GetItem(enumType->tp_dict, _member_map_); + AutoDecRef tpDict(PepType_GetDict(enumType)); + auto *member_map = PyDict_GetItem(tpDict.object(), _member_map_); if (!(member_map && PyDict_Check(member_map))) return nullptr; auto *result = PyDict_GetItemString(member_map, itemName); diff --git a/sources/shiboken6/libshiboken/sbkfeature_base.cpp b/sources/shiboken6/libshiboken/sbkfeature_base.cpp index f33e58e9a..0c8f6d3fc 100644 --- a/sources/shiboken6/libshiboken/sbkfeature_base.cpp +++ b/sources/shiboken6/libshiboken/sbkfeature_base.cpp @@ -23,7 +23,8 @@ extern "C" // int currentSelectId(PyTypeObject *type) { - PyObject *PyId = PyObject_GetAttr(type->tp_dict, PyName::select_id()); + AutoDecRef tpDict(PepType_GetDict(type)); + PyObject *PyId = PyObject_GetAttr(tpDict.object(), PyName::select_id()); if (PyId == nullptr) { PyErr_Clear(); return 0x00; @@ -235,7 +236,8 @@ static PyObject *lookupUnqualifiedOrOldEnum(PyTypeObject *type, PyObject *name) * We first need to look into the current opcode of the bytecode to find * out if we have a call like above or just a type lookup. */ - auto *flagType = PyDict_GetItem(type_base->tp_dict, rename); + AutoDecRef tpDict(PepType_GetDict(type_base)); + auto *flagType = PyDict_GetItem(tpDict.object(), rename); if (currentOpcode_Is_CallMethNoArgs()) return replaceNoArgWithZero(flagType); Py_INCREF(flagType); @@ -244,7 +246,8 @@ static PyObject *lookupUnqualifiedOrOldEnum(PyTypeObject *type, PyObject *name) } bool useFakeShortcuts = !(Enum::enumOption & Enum::ENOPT_NO_FAKESHORTCUT); if (useFakeShortcuts) { - auto *dict = type_base->tp_dict; + AutoDecRef tpDict(PepType_GetDict(type_base)); + auto *dict = tpDict.object(); PyObject *key, *value; Py_ssize_t pos = 0; while (PyDict_Next(dict, &pos, &key, &value)) { @@ -334,12 +337,14 @@ PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void * /* context */) /* * This is the override for getting a dict. */ - auto dict = type->tp_dict; + AutoDecRef tpDict(PepType_GetDict(type)); + auto dict = tpDict.object();; if (dict == nullptr) Py_RETURN_NONE; if (SelectFeatureSet != nullptr) { SelectFeatureSet(type); - dict = type->tp_dict; + tpDict.reset(PepType_GetDict(type)); + dict = tpDict.object(); } return PyDictProxy_New(dict); } diff --git a/sources/shiboken6/libshiboken/sbktypefactory.cpp b/sources/shiboken6/libshiboken/sbktypefactory.cpp index 559e72263..b4a0fda9c 100644 --- a/sources/shiboken6/libshiboken/sbktypefactory.cpp +++ b/sources/shiboken6/libshiboken/sbktypefactory.cpp @@ -130,9 +130,10 @@ PyTypeObject *SbkType_FromSpec_BMDWB(PyType_Spec *spec, // PyType_Ready too early. (at least in PyPy, which caused pretty long debugging.) auto *ht = reinterpret_cast<PyHeapTypeObject *>(type); ht->ht_qualname = qualname; - if (PyDict_SetItem(type->tp_dict, Shiboken::PyMagicName::qualname(), qualname)) + AutoDecRef tpDict(PepType_GetDict(type)); + if (PyDict_SetItem(tpDict.object(), Shiboken::PyMagicName::qualname(), qualname)) return nullptr; - if (PyDict_SetItem(type->tp_dict, Shiboken::PyMagicName::module(), module)) + if (PyDict_SetItem(tpDict.object(), Shiboken::PyMagicName::module(), module)) return nullptr; PyType_Ready(type); #else @@ -361,7 +362,7 @@ _PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) /// Here is the only change needed: Do not finalize type creation. // if (PyType_Ready(type) < 0) // goto fail; - type->tp_dict = PyDict_New(); + PepType_SetDict(type, PyDict_New()); /// This is not found in PyPy: // if (type->tp_dictoffset) { // res->ht_cached_keys = _PyDict_NewKeysForClass(); |
