diff options
| -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" |
