diff options
| author | Christian Tismer <tismer@stackless.com> | 2021-04-18 18:58:18 +0200 |
|---|---|---|
| committer | Christian Tismer <tismer@stackless.com> | 2021-10-28 13:46:50 +0200 |
| commit | 8fbf601619b5291885d3b160b95aba860b1d57d6 (patch) | |
| tree | 2737bcabea0f6f52e1e06f0a387cf6361df27951 | |
| parent | 5f44fd68e351e28b90636f34556628f5cda134a9 (diff) | |
PyPySide: finish the PyType_FromSpec patch
PySide has been prepared for the inclusion of PyPy by
centralizing all PyType_FromSpec related functions.
It was the original plan to leave sbktypefactory as it
is now, but PyPy has a delay of one or two versions until
the updated type handling will be implemented.
The support for PyType_Modified will come, and it will
even work with our feature switching. But not now!
Therefore, the current slightly hackish solution will
be checked in that solves the timing problems of type
creation by an own re-implementation.
As soon as possible, this version will be reverted.
Task-number: PYSIDE-535
Change-Id: I56330f354edff0453607c1e580a10f620ba10209
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
| -rw-r--r-- | sources/shiboken6/libshiboken/sbktypefactory.cpp | 266 |
1 files changed, 261 insertions, 5 deletions
diff --git a/sources/shiboken6/libshiboken/sbktypefactory.cpp b/sources/shiboken6/libshiboken/sbktypefactory.cpp index b560cdb95..08d6775f4 100644 --- a/sources/shiboken6/libshiboken/sbktypefactory.cpp +++ b/sources/shiboken6/libshiboken/sbktypefactory.cpp @@ -68,6 +68,16 @@ PyTypeObject *SbkType_FromSpecBasesMeta(PyType_Spec *spec, PyObject *bases, PyTy return SbkType_FromSpec_BMDWBD(spec, bases, meta, 0, 0, nullptr, nullptr); } +#ifdef PYPY_VERSION + +static PyObject *_PyType_FromSpecWithBases(PyType_Spec *, PyObject *); + +#else + +#define _PyType_FromSpecWithBases PyType_FromSpecWithBases + +#endif // PYPY_VERSION + PyTypeObject *SbkType_FromSpec_BMDWBD(PyType_Spec *spec, PyObject *bases, PyTypeObject *meta, @@ -93,7 +103,7 @@ PyTypeObject *SbkType_FromSpec_BMDWBD(PyType_Spec *spec, int package_level = atoi(spec->name); const char *mod = new_spec.name = colon + 1; - PyObject *obType = PyType_FromSpecWithBases(&new_spec, bases); + PyObject *obType = _PyType_FromSpecWithBases(&new_spec, bases); if (obType == nullptr) return nullptr; @@ -107,10 +117,6 @@ PyTypeObject *SbkType_FromSpec_BMDWBD(PyType_Spec *spec, 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); @@ -131,8 +137,258 @@ PyTypeObject *SbkType_FromSpec_BMDWBD(PyType_Spec *spec, if (dict_add) PyDict_Update(reinterpret_cast<PyObject *>(type->tp_dict), dict_add); +#ifdef PYPY_VERSION + // PYSIDE-535: Careful: Using PyObject_SetAttr would have the side-effect of calling + // 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)) + return nullptr; + if (PyDict_SetItem(type->tp_dict, Shiboken::PyMagicName::module(), module)) + return nullptr; + PyType_Ready(type); +#else + if (PyObject_SetAttr(obType, Shiboken::PyMagicName::module(), module) < 0) + return nullptr; + if (PyObject_SetAttr(obType, Shiboken::PyMagicName::qualname(), qualname) < 0) + return nullptr; PyType_Modified(type); +#endif return type; } +#ifdef PYPY_VERSION + +///////////////////////////////////////////////////////////////////////////// +// +// Reimplementation of `PyType_FromSpecWithBases` +// +// This is almost the original code from Python 3.7 with a few changes. +// Especially the call to `PyType_Ready` is deferred until the needed +// post-actions are carried out in `SbkType_FromSpec_BMDWBD`. +// +// FIXME remove ASAP. +// Version is not clear, yet. Current version == 7.3.6 +// + +static const short slotoffsets[] = { + -1, /* invalid slot */ +/* Generated by typeslots.py */ +0, +0, +offsetof(PyHeapTypeObject, as_mapping.mp_ass_subscript), +offsetof(PyHeapTypeObject, as_mapping.mp_length), +offsetof(PyHeapTypeObject, as_mapping.mp_subscript), +offsetof(PyHeapTypeObject, as_number.nb_absolute), +offsetof(PyHeapTypeObject, as_number.nb_add), +offsetof(PyHeapTypeObject, as_number.nb_and), +offsetof(PyHeapTypeObject, as_number.nb_bool), +offsetof(PyHeapTypeObject, as_number.nb_divmod), +offsetof(PyHeapTypeObject, as_number.nb_float), +offsetof(PyHeapTypeObject, as_number.nb_floor_divide), +offsetof(PyHeapTypeObject, as_number.nb_index), +offsetof(PyHeapTypeObject, as_number.nb_inplace_add), +offsetof(PyHeapTypeObject, as_number.nb_inplace_and), +offsetof(PyHeapTypeObject, as_number.nb_inplace_floor_divide), +offsetof(PyHeapTypeObject, as_number.nb_inplace_lshift), +offsetof(PyHeapTypeObject, as_number.nb_inplace_multiply), +offsetof(PyHeapTypeObject, as_number.nb_inplace_or), +offsetof(PyHeapTypeObject, as_number.nb_inplace_power), +offsetof(PyHeapTypeObject, as_number.nb_inplace_remainder), +offsetof(PyHeapTypeObject, as_number.nb_inplace_rshift), +offsetof(PyHeapTypeObject, as_number.nb_inplace_subtract), +offsetof(PyHeapTypeObject, as_number.nb_inplace_true_divide), +offsetof(PyHeapTypeObject, as_number.nb_inplace_xor), +offsetof(PyHeapTypeObject, as_number.nb_int), +offsetof(PyHeapTypeObject, as_number.nb_invert), +offsetof(PyHeapTypeObject, as_number.nb_lshift), +offsetof(PyHeapTypeObject, as_number.nb_multiply), +offsetof(PyHeapTypeObject, as_number.nb_negative), +offsetof(PyHeapTypeObject, as_number.nb_or), +offsetof(PyHeapTypeObject, as_number.nb_positive), +offsetof(PyHeapTypeObject, as_number.nb_power), +offsetof(PyHeapTypeObject, as_number.nb_remainder), +offsetof(PyHeapTypeObject, as_number.nb_rshift), +offsetof(PyHeapTypeObject, as_number.nb_subtract), +offsetof(PyHeapTypeObject, as_number.nb_true_divide), +offsetof(PyHeapTypeObject, as_number.nb_xor), +offsetof(PyHeapTypeObject, as_sequence.sq_ass_item), +offsetof(PyHeapTypeObject, as_sequence.sq_concat), +offsetof(PyHeapTypeObject, as_sequence.sq_contains), +offsetof(PyHeapTypeObject, as_sequence.sq_inplace_concat), +offsetof(PyHeapTypeObject, as_sequence.sq_inplace_repeat), +offsetof(PyHeapTypeObject, as_sequence.sq_item), +offsetof(PyHeapTypeObject, as_sequence.sq_length), +offsetof(PyHeapTypeObject, as_sequence.sq_repeat), +offsetof(PyHeapTypeObject, ht_type.tp_alloc), +offsetof(PyHeapTypeObject, ht_type.tp_base), +offsetof(PyHeapTypeObject, ht_type.tp_bases), +offsetof(PyHeapTypeObject, ht_type.tp_call), +offsetof(PyHeapTypeObject, ht_type.tp_clear), +offsetof(PyHeapTypeObject, ht_type.tp_dealloc), +offsetof(PyHeapTypeObject, ht_type.tp_del), +offsetof(PyHeapTypeObject, ht_type.tp_descr_get), +offsetof(PyHeapTypeObject, ht_type.tp_descr_set), +offsetof(PyHeapTypeObject, ht_type.tp_doc), +offsetof(PyHeapTypeObject, ht_type.tp_getattr), +offsetof(PyHeapTypeObject, ht_type.tp_getattro), +offsetof(PyHeapTypeObject, ht_type.tp_hash), +offsetof(PyHeapTypeObject, ht_type.tp_init), +offsetof(PyHeapTypeObject, ht_type.tp_is_gc), +offsetof(PyHeapTypeObject, ht_type.tp_iter), +offsetof(PyHeapTypeObject, ht_type.tp_iternext), +offsetof(PyHeapTypeObject, ht_type.tp_methods), +offsetof(PyHeapTypeObject, ht_type.tp_new), +offsetof(PyHeapTypeObject, ht_type.tp_repr), +offsetof(PyHeapTypeObject, ht_type.tp_richcompare), +offsetof(PyHeapTypeObject, ht_type.tp_setattr), +offsetof(PyHeapTypeObject, ht_type.tp_setattro), +offsetof(PyHeapTypeObject, ht_type.tp_str), +offsetof(PyHeapTypeObject, ht_type.tp_traverse), +offsetof(PyHeapTypeObject, ht_type.tp_members), +offsetof(PyHeapTypeObject, ht_type.tp_getset), +offsetof(PyHeapTypeObject, ht_type.tp_free), +offsetof(PyHeapTypeObject, as_number.nb_matrix_multiply), +offsetof(PyHeapTypeObject, as_number.nb_inplace_matrix_multiply), +offsetof(PyHeapTypeObject, as_async.am_await), +offsetof(PyHeapTypeObject, as_async.am_aiter), +offsetof(PyHeapTypeObject, as_async.am_anext), +offsetof(PyHeapTypeObject, ht_type.tp_finalize), +}; + +static PyTypeObject * +best_base(PyObject *bases) +{ + // We always have only one base + return reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(bases, 0)); +} + +static PyObject * +_PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) +{ + PyHeapTypeObject *res = reinterpret_cast<PyHeapTypeObject *>( + PyType_GenericAlloc(&PyType_Type, 0)); + PyTypeObject *type, *base; + PyObject *modname; + char *s; + char *res_start = reinterpret_cast<char *>(res); + PyType_Slot *slot; + + if (res == nullptr) + return nullptr; + + if (spec->name == nullptr) { + PyErr_SetString(PyExc_SystemError, + "Type spec does not define the name field."); + goto fail; + } + + /* Set the type name and qualname */ + s = strrchr(const_cast<char *>(spec->name), '.'); + if (s == nullptr) + s = (char*)spec->name; + else + s++; + + type = &res->ht_type; + /* The flags must be initialized early, before the GC traverses us */ + type->tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE; + res->ht_name = PyUnicode_FromString(s); + if (!res->ht_name) + goto fail; + res->ht_qualname = res->ht_name; + Py_INCREF(res->ht_qualname); + type->tp_name = spec->name; + + /* Adjust for empty tuple bases */ + if (!bases) { + base = &PyBaseObject_Type; + /* See whether Py_tp_base(s) was specified */ + for (slot = spec->slots; slot->slot; slot++) { + if (slot->slot == Py_tp_base) + base = reinterpret_cast<PyTypeObject *>(slot->pfunc); + else if (slot->slot == Py_tp_bases) { + bases = reinterpret_cast<PyObject *>(slot->pfunc); + Py_INCREF(bases); + } + } + if (!bases) + bases = PyTuple_Pack(1, base); + if (!bases) + goto fail; + } + else + Py_INCREF(bases); + + /* Calculate best base, and check that all bases are type objects */ + base = best_base(bases); + if (base == nullptr) { + goto fail; + } + + /* Initialize essential fields */ + type->tp_as_async = &res->as_async; + type->tp_as_number = &res->as_number; + type->tp_as_sequence = &res->as_sequence; + type->tp_as_mapping = &res->as_mapping; + type->tp_as_buffer = &res->as_buffer; + /* Set tp_base and tp_bases */ + type->tp_bases = bases; + bases = nullptr; + Py_INCREF(base); + type->tp_base = base; + + type->tp_basicsize = spec->basicsize; + type->tp_itemsize = spec->itemsize; + + for (slot = spec->slots; slot->slot; slot++) { + if (slot->slot == Py_tp_base || slot->slot == Py_tp_bases) + /* Processed above */ + continue; + *reinterpret_cast<void **>(res_start + slotoffsets[slot->slot]) = slot->pfunc; + + /* need to make a copy of the docstring slot, which usually + points to a static string literal */ + if (slot->slot == Py_tp_doc) { + const char *old_doc = reinterpret_cast<char *>(slot->pfunc); + //_PyType_DocWithoutSignature(type->tp_name, slot->pfunc); + size_t len = strlen(old_doc)+1; + char *tp_doc = reinterpret_cast<char *>(PyObject_MALLOC(len)); + if (tp_doc == nullptr) { + type->tp_doc = nullptr; + PyErr_NoMemory(); + goto fail; + } + memcpy(tp_doc, old_doc, len); + type->tp_doc = tp_doc; + } + } + if (type->tp_dealloc == nullptr) { + /* It's a heap type, so needs the heap types' dealloc. + subtype_dealloc will call the base type's tp_dealloc, if + necessary. */ + type->tp_dealloc = _PyPy_subtype_dealloc; + } + + /// Here is the only change needed: Do not finalize type creation. + // if (PyType_Ready(type) < 0) + // goto fail; + type->tp_dict = PyDict_New(); + /// This is not found in PyPy: + // if (type->tp_dictoffset) { + // res->ht_cached_keys = _PyDict_NewKeysForClass(); + // } + + /* Set type.__module__ */ + /// Removed __module__ handling, already implemented. + + return (PyObject*)res; + + fail: + Py_DECREF(res); + return nullptr; +} + +#endif // PYPY_VERSION + } //extern "C" |
