From 7965cb39169dc66daf780cacc4d78f317560b36c Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 1 Feb 2023 09:27:30 +0100 Subject: [PATCH 01/17] Establish global state --- Modules/_collectionsmodule.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 9d8aef1e677157..c2d231d2773bc8 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -75,6 +75,13 @@ static PyTypeObject tuplegetter_type; * Checking for d.len == 0 is the intended way to see whether d is empty. */ +typedef struct { +} collections_state; + +static collections_state global_state; + +#define GLOBAL_STATE() (&global_state) + typedef struct BLOCK { struct BLOCK *leftlink; PyObject *data[BLOCKLEN]; From 3d7fd7ccdefe6188fd8bec4a0df7af58019e372e Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 1 Feb 2023 09:39:45 +0100 Subject: [PATCH 02/17] Add module level helpers --- Modules/_collectionsmodule.c | 47 +++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index c2d231d2773bc8..75edb8c922d6c6 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -2540,6 +2540,24 @@ static PyTypeObject tuplegetter_type = { /* module level code ********************************************************/ +static int +collections_traverse(PyObject *module, visitproc visit, void *arg) +{ + return 0; +} + +static int +collections_clear(PyObject *module) +{ + return 0; +} + +static void +collections_free(void *module) +{ + collections_clear((PyObject *)module); +} + PyDoc_STRVAR(collections_doc, "High performance data structures.\n\ - deque: ordered collection accessible from endpoints only\n\ @@ -2551,6 +2569,18 @@ static struct PyMethodDef collections_methods[] = { {NULL, NULL} /* sentinel */ }; +#define ADD_TYPE(mod, spec, type) \ + do { \ + type = (PyTypeObject *)PyType_FromModuleAndSpec(mod, spec, NULL); \ + if (type == NULL) { \ + return -1; \ + } \ + if (PyModule_AddType(mod, type) < 0) { \ + return -1; \ + } \ + return 0; \ + } while (0) + static int collections_exec(PyObject *module) { PyTypeObject *typelist[] = { @@ -2579,15 +2609,14 @@ static struct PyModuleDef_Slot collections_slots[] = { }; static struct PyModuleDef _collectionsmodule = { - PyModuleDef_HEAD_INIT, - "_collections", - collections_doc, - 0, - collections_methods, - collections_slots, - NULL, - NULL, - NULL + .m_base = PyModuleDef_HEAD_INIT, + .m_name = "_collections", + .m_doc = collections_doc, + .m_methods = collections_methods, + .m_slots = collections_slots, + .m_traverse = collections_traverse, + .m_clear = collections_clear, + .m_free = collections_free, }; PyMODINIT_FUNC From 868619eec182ba9a22fe9e0d706cbffaf0632c3c Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 1 Feb 2023 10:27:18 +0100 Subject: [PATCH 03/17] WIP --- Modules/_collectionsmodule.c | 169 ++++++++++++++++++++--------------- 1 file changed, 97 insertions(+), 72 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 75edb8c922d6c6..c03d51d88f8645 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1,6 +1,7 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_long.h" // _PyLong_GetZero() +#include "pycore_moduleobject.h" // _PyModule_GetState() #include "structmember.h" // PyMemberDef #include @@ -76,11 +77,34 @@ static PyTypeObject tuplegetter_type; */ typedef struct { + PyTypeObject *deque_type; } collections_state; -static collections_state global_state; +static inline collections_state * +get_module_state(PyObject *mod) +{ + void *state = _PyModule_GetState(mod); + assert(state != NULL); + return (collections_state *)state; +} + +static inline collections_state * +get_module_state_by_cls(PyTypeObject *cls) +{ + void *state = PyType_GetModuleState(cls); + assert(state != NULL); + return (collections_state *)state; +} -#define GLOBAL_STATE() (&global_state) +static struct PyModuleDef _collectionsmodule; + +static inline collections_state * +find_module_state_by_type(PyTypeObject *type) +{ + PyObject *mod = PyType_GetModuleByDef(type, &_collectionsmodule); + assert(mod != NULL); + return get_module_state(mod); +} typedef struct BLOCK { struct BLOCK *leftlink; @@ -101,8 +125,6 @@ typedef struct { PyObject *weakreflist; } dequeobject; -static PyTypeObject deque_type; - /* For debug builds, add error checking to track the endpoints * in the chain of links. The goal is to make sure that link * assignments only take place at endpoints so that links already @@ -491,11 +513,13 @@ deque_copy(PyObject *deque, PyObject *Py_UNUSED(ignored)) { PyObject *result; dequeobject *old_deque = (dequeobject *)deque; - if (Py_IS_TYPE(deque, &deque_type)) { + collections_state *state = find_module_state_by_type(Py_TYPE(deque)); + if (Py_IS_TYPE(deque, state->deque_type)) { dequeobject *new_deque; PyObject *rv; - new_deque = (dequeobject *)deque_new(&deque_type, (PyObject *)NULL, (PyObject *)NULL); + new_deque = (dequeobject *)deque_new(state->deque_type, + (PyObject *)NULL, (PyObject *)NULL); if (new_deque == NULL) return NULL; new_deque->maxlen = old_deque->maxlen; @@ -518,7 +542,7 @@ deque_copy(PyObject *deque, PyObject *Py_UNUSED(ignored)) else result = PyObject_CallFunction((PyObject *)(Py_TYPE(deque)), "Oi", deque, old_deque->maxlen, NULL); - if (result != NULL && !PyObject_TypeCheck(result, &deque_type)) { + if (result != NULL && !PyObject_TypeCheck(result, state->deque_type)) { PyErr_Format(PyExc_TypeError, "%.200s() must return a deque, not %.200s", Py_TYPE(deque)->tp_name, Py_TYPE(result)->tp_name); @@ -536,7 +560,8 @@ deque_concat(dequeobject *deque, PyObject *other) PyObject *new_deque, *result; int rv; - rv = PyObject_IsInstance(other, (PyObject *)&deque_type); + collections_state *state = find_module_state_by_type(Py_TYPE(deque)); + rv = PyObject_IsInstance(other, (PyObject *)state->deque_type); if (rv <= 0) { if (rv == 0) { PyErr_Format(PyExc_TypeError, @@ -1295,6 +1320,7 @@ deque_ass_item(dequeobject *deque, Py_ssize_t i, PyObject *v) static void deque_dealloc(dequeobject *deque) { + PyTypeObject *tp = Py_TYPE(deque); Py_ssize_t i; PyObject_GC_UnTrack(deque); @@ -1310,12 +1336,15 @@ deque_dealloc(dequeobject *deque) for (i=0 ; i < deque->numfreeblocks ; i++) { PyMem_Free(deque->freeblocks[i]); } - Py_TYPE(deque)->tp_free(deque); + tp->tp_free(deque); + Py_DECREF(tp); } static int deque_traverse(dequeobject *deque, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(deque)); + block *b; PyObject *item; Py_ssize_t index; @@ -1400,8 +1429,9 @@ deque_richcompare(PyObject *v, PyObject *w, int op) Py_ssize_t vs, ws; int b, cmp=-1; - if (!PyObject_TypeCheck(v, &deque_type) || - !PyObject_TypeCheck(w, &deque_type)) { + collections_state *state = find_module_state_by_type(Py_TYPE(v)); + if (!PyObject_TypeCheck(v, state->deque_type) || + !PyObject_TypeCheck(w, state->deque_type)) { Py_RETURN_NOTIMPLEMENTED; } @@ -1544,19 +1574,6 @@ static PyGetSetDef deque_getset[] = { {0} }; -static PySequenceMethods deque_as_sequence = { - (lenfunc)deque_len, /* sq_length */ - (binaryfunc)deque_concat, /* sq_concat */ - (ssizeargfunc)deque_repeat, /* sq_repeat */ - (ssizeargfunc)deque_item, /* sq_item */ - 0, /* sq_slice */ - (ssizeobjargproc)deque_ass_item, /* sq_ass_item */ - 0, /* sq_ass_slice */ - (objobjproc)deque_contains, /* sq_contains */ - (binaryfunc)deque_inplace_concat, /* sq_inplace_concat */ - (ssizeargfunc)deque_inplace_repeat, /* sq_inplace_repeat */ -}; - static PyObject *deque_iter(dequeobject *deque); static PyObject *deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored)); PyDoc_STRVAR(reversed_doc, @@ -1604,54 +1621,53 @@ static PyMethodDef deque_methods[] = { {NULL, NULL} /* sentinel */ }; +static PyMemberDef deque_members[] = { + {"__weaklistoffset__", T_PYSSIZET, offsetof(dequeobject, weakreflist), READONLY}, + {NULL}, +}; + PyDoc_STRVAR(deque_doc, "deque([iterable[, maxlen]]) --> deque object\n\ \n\ A list-like sequence optimized for data accesses near its endpoints."); -static PyTypeObject deque_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "collections.deque", /* tp_name */ - sizeof(dequeobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)deque_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - deque_repr, /* tp_repr */ - 0, /* tp_as_number */ - &deque_as_sequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - PyObject_HashNotImplemented, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_SEQUENCE, - /* tp_flags */ - deque_doc, /* tp_doc */ - (traverseproc)deque_traverse, /* tp_traverse */ - (inquiry)deque_clear, /* tp_clear */ - (richcmpfunc)deque_richcompare, /* tp_richcompare */ - offsetof(dequeobject, weakreflist), /* tp_weaklistoffset*/ - (getiterfunc)deque_iter, /* tp_iter */ - 0, /* tp_iternext */ - deque_methods, /* tp_methods */ - 0, /* tp_members */ - deque_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)deque_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - deque_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot deque_slots[] = { + {Py_tp_dealloc, deque_dealloc}, + {Py_tp_repr, deque_repr}, + {Py_tp_hash, PyObject_HashNotImplemented}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)deque_doc}, + {Py_tp_traverse, deque_traverse}, + {Py_tp_clear, deque_clear}, + {Py_tp_richcompare, deque_richcompare}, + {Py_tp_iter, deque_iter}, + {Py_tp_getset, deque_getset}, + {Py_tp_init, deque_init}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_new, deque_new}, + {Py_tp_free, PyObject_GC_Del}, + {Py_tp_methods, deque_methods}, + {Py_tp_members, deque_members}, + + // Sequence protocol + {Py_sq_length, deque_len}, + {Py_sq_concat, deque_concat}, + {Py_sq_repeat, deque_repeat}, + {Py_sq_item, deque_item}, + {Py_sq_ass_item, deque_ass_item}, + {Py_sq_contains, deque_contains}, + {Py_sq_inplace_concat, deque_inplace_concat}, + {Py_sq_inplace_repeat, deque_inplace_repeat}, + {0, NULL}, +}; + +static PyType_Spec deque_spec = { + .name = "collections.deque", + .basicsize = sizeof(dequeobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_SEQUENCE | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = deque_slots, }; /*********************** Deque Iterator **************************/ @@ -1733,7 +1749,8 @@ dequeiter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_ssize_t i, index=0; PyObject *deque; dequeiterobject *it; - if (!PyArg_ParseTuple(args, "O!|n", &deque_type, &deque, &index)) + collections_state *state = find_module_state_by_type(Py_TYPE(type)); + if (!PyArg_ParseTuple(args, "O!|n", state->deque_type, &deque, &index)) return NULL; assert(type == &dequeiter_type); @@ -1873,7 +1890,8 @@ dequereviter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_ssize_t i, index=0; PyObject *deque; dequeiterobject *it; - if (!PyArg_ParseTuple(args, "O!|n", &deque_type, &deque, &index)) + collections_state *state = find_module_state_by_type(Py_TYPE(type)); + if (!PyArg_ParseTuple(args, "O!|n", state->deque_type, &deque, &index)) return NULL; assert(type == &dequereviter_type); @@ -2541,14 +2559,18 @@ static PyTypeObject tuplegetter_type = { /* module level code ********************************************************/ static int -collections_traverse(PyObject *module, visitproc visit, void *arg) +collections_traverse(PyObject *mod, visitproc visit, void *arg) { + collections_state *state = get_module_state(mod); + Py_VISIT(state->deque_type); return 0; } static int -collections_clear(PyObject *module) +collections_clear(PyObject *mod) { + collections_state *state = get_module_state(mod); + Py_CLEAR(state->deque_type); return 0; } @@ -2583,8 +2605,10 @@ static struct PyMethodDef collections_methods[] = { static int collections_exec(PyObject *module) { + collections_state *state = get_module_state(module); + ADD_TYPE(module, &deque_spec, state->deque_type); + PyTypeObject *typelist[] = { - &deque_type, &defdict_type, &PyODict_Type, &dequeiter_type, @@ -2612,6 +2636,7 @@ static struct PyModuleDef _collectionsmodule = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "_collections", .m_doc = collections_doc, + .m_size = sizeof(collections_state), .m_methods = collections_methods, .m_slots = collections_slots, .m_traverse = collections_traverse, From cde3cd97445f9152f0b62d2a63f78c284d6a3f18 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 3 Feb 2023 09:54:32 +0100 Subject: [PATCH 04/17] More WIP --- Modules/_collectionsmodule.c | 407 +++++++++++--------------- Modules/clinic/_collectionsmodule.c.h | 4 +- 2 files changed, 170 insertions(+), 241 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index c03d51d88f8645..fe6c2702bca8dd 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -5,14 +5,51 @@ #include "structmember.h" // PyMemberDef #include +typedef struct { + PyTypeObject *deque_type; + PyTypeObject *defdict_type; + PyTypeObject *dequeiter_type; + PyTypeObject *dequereviter_type; + PyTypeObject *tuplegetter_type; +} collections_state; + +static inline collections_state * +get_module_state(PyObject *mod) +{ + void *state = _PyModule_GetState(mod); + assert(state != NULL); + return (collections_state *)state; +} + +static inline collections_state * +get_module_state_by_cls(PyTypeObject *cls) +{ + void *state = PyType_GetModuleState(cls); + assert(state != NULL); + return (collections_state *)state; +} + +static struct PyModuleDef _collectionsmodule; + +static inline collections_state * +find_module_state_by_def(PyTypeObject *type) +{ + PyObject *mod = PyType_GetModuleByDef(type, &_collectionsmodule); + assert(mod != NULL); + return get_module_state(mod); +} + /*[clinic input] module _collections -class _tuplegetter "_tuplegetterobject *" "&tuplegetter_type" +class _tuplegetter "_tuplegetterobject *" "clinic_state()->tuplegetter_type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a8ece4ccad7e30ac]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7356042a89862e0e]*/ -static PyTypeObject tuplegetter_type; +/* We can safely assume type to be the defining class, + * since tuplegetter is not a base type */ +#define clinic_state() (get_module_state_by_cls(type)) #include "clinic/_collectionsmodule.c.h" +#undef clinic_state /* collections module implementation of a deque() datatype Written and maintained by Raymond D. Hettinger @@ -76,36 +113,6 @@ static PyTypeObject tuplegetter_type; * Checking for d.len == 0 is the intended way to see whether d is empty. */ -typedef struct { - PyTypeObject *deque_type; -} collections_state; - -static inline collections_state * -get_module_state(PyObject *mod) -{ - void *state = _PyModule_GetState(mod); - assert(state != NULL); - return (collections_state *)state; -} - -static inline collections_state * -get_module_state_by_cls(PyTypeObject *cls) -{ - void *state = PyType_GetModuleState(cls); - assert(state != NULL); - return (collections_state *)state; -} - -static struct PyModuleDef _collectionsmodule; - -static inline collections_state * -find_module_state_by_type(PyTypeObject *type) -{ - PyObject *mod = PyType_GetModuleByDef(type, &_collectionsmodule); - assert(mod != NULL); - return get_module_state(mod); -} - typedef struct BLOCK { struct BLOCK *leftlink; PyObject *data[BLOCKLEN]; @@ -513,7 +520,7 @@ deque_copy(PyObject *deque, PyObject *Py_UNUSED(ignored)) { PyObject *result; dequeobject *old_deque = (dequeobject *)deque; - collections_state *state = find_module_state_by_type(Py_TYPE(deque)); + collections_state *state = find_module_state_by_def(Py_TYPE(deque)); if (Py_IS_TYPE(deque, state->deque_type)) { dequeobject *new_deque; PyObject *rv; @@ -560,7 +567,7 @@ deque_concat(dequeobject *deque, PyObject *other) PyObject *new_deque, *result; int rv; - collections_state *state = find_module_state_by_type(Py_TYPE(deque)); + collections_state *state = find_module_state_by_def(Py_TYPE(deque)); rv = PyObject_IsInstance(other, (PyObject *)state->deque_type); if (rv <= 0) { if (rv == 0) { @@ -1429,7 +1436,7 @@ deque_richcompare(PyObject *v, PyObject *w, int op) Py_ssize_t vs, ws; int b, cmp=-1; - collections_state *state = find_module_state_by_type(Py_TYPE(v)); + collections_state *state = find_module_state_by_def(Py_TYPE(v)); if (!PyObject_TypeCheck(v, state->deque_type) || !PyObject_TypeCheck(w, state->deque_type)) { Py_RETURN_NOTIMPLEMENTED; @@ -1662,7 +1669,7 @@ static PyType_Slot deque_slots[] = { }; static PyType_Spec deque_spec = { - .name = "collections.deque", + .name = "_collections.deque", .basicsize = sizeof(dequeobject), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_SEQUENCE | @@ -1681,14 +1688,13 @@ typedef struct { Py_ssize_t counter; /* number of items remaining for iteration */ } dequeiterobject; -static PyTypeObject dequeiter_type; - static PyObject * deque_iter(dequeobject *deque) { dequeiterobject *it; - it = PyObject_GC_New(dequeiterobject, &dequeiter_type); + collections_state *state = find_module_state_by_def(Py_TYPE(deque)); + it = PyObject_GC_New(dequeiterobject, state->dequeiter_type); if (it == NULL) return NULL; it->b = deque->leftblock; @@ -1703,17 +1709,27 @@ deque_iter(dequeobject *deque) static int dequeiter_traverse(dequeiterobject *dio, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(dio)); Py_VISIT(dio->deque); return 0; } +static int +dequeiter_clear(dequeiterobject *dio) +{ + Py_CLEAR(dio->deque); + return 0; +} + static void dequeiter_dealloc(dequeiterobject *dio) { /* bpo-31095: UnTrack is needed before calling any callbacks */ + PyTypeObject *tp = Py_TYPE(dio); PyObject_GC_UnTrack(dio); - Py_XDECREF(dio->deque); + tp->tp_clear((PyObject *)dio); PyObject_GC_Del(dio); + Py_DECREF(tp); } static PyObject * @@ -1749,10 +1765,10 @@ dequeiter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_ssize_t i, index=0; PyObject *deque; dequeiterobject *it; - collections_state *state = find_module_state_by_type(Py_TYPE(type)); + collections_state *state = get_module_state_by_cls(type); if (!PyArg_ParseTuple(args, "O!|n", state->deque_type, &deque, &index)) return NULL; - assert(type == &dequeiter_type); + assert(type == state->dequeiter_type); it = (dequeiterobject*)deque_iter((dequeobject *)deque); if (!it) @@ -1793,59 +1809,35 @@ static PyMethodDef dequeiter_methods[] = { {NULL, NULL} /* sentinel */ }; -static PyTypeObject dequeiter_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_collections._deque_iterator", /* tp_name */ - sizeof(dequeiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)dequeiter_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)dequeiter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)dequeiter_next, /* tp_iternext */ - dequeiter_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - dequeiter_new, /* tp_new */ - 0, +static PyType_Slot dequeiter_slots[] = { + {Py_tp_dealloc, dequeiter_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_traverse, dequeiter_traverse}, + {Py_tp_clear, dequeiter_clear}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, dequeiter_next}, + {Py_tp_methods, dequeiter_methods}, + {Py_tp_new, dequeiter_new}, + {0, NULL}, }; -/*********************** Deque Reverse Iterator **************************/ +static PyType_Spec dequeiter_spec = { + .name = "_collections._deque_iterator", + .basicsize = sizeof(dequeiterobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = dequeiter_slots, +}; -static PyTypeObject dequereviter_type; +/*********************** Deque Reverse Iterator **************************/ static PyObject * deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored)) { dequeiterobject *it; + collections_state *state = find_module_state_by_def(Py_TYPE(deque)); - it = PyObject_GC_New(dequeiterobject, &dequereviter_type); + it = PyObject_GC_New(dequeiterobject, state->dequereviter_type); if (it == NULL) return NULL; it->b = deque->rightblock; @@ -1890,10 +1882,10 @@ dequereviter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_ssize_t i, index=0; PyObject *deque; dequeiterobject *it; - collections_state *state = find_module_state_by_type(Py_TYPE(type)); + collections_state *state = get_module_state_by_cls(type); if (!PyArg_ParseTuple(args, "O!|n", state->deque_type, &deque, &index)) return NULL; - assert(type == &dequereviter_type); + assert(type == state->dequereviter_type); it = (dequeiterobject*)deque_reviter((dequeobject *)deque, NULL); if (!it) @@ -1914,47 +1906,24 @@ dequereviter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject*)it; } -static PyTypeObject dequereviter_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_collections._deque_reverse_iterator", /* tp_name */ - sizeof(dequeiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)dequeiter_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)dequeiter_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)dequereviter_next, /* tp_iternext */ - dequeiter_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - dequereviter_new, /* tp_new */ - 0, +static PyType_Slot dequereviter_slots[] = { + {Py_tp_dealloc, dequeiter_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_traverse, dequeiter_traverse}, + {Py_tp_clear, dequeiter_clear}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, dequereviter_next}, + {Py_tp_methods, dequeiter_methods}, + {Py_tp_new, dequereviter_new}, + {0, NULL}, +}; + +static PyType_Spec dequereviter_spec = { + .name = "_collections._deque_reverse_iterator", + .basicsize = sizeof(dequeiterobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = dequereviter_slots, }; /* defaultdict type *********************************************************/ @@ -1964,8 +1933,6 @@ typedef struct { PyObject *default_factory; } defdictobject; -static PyTypeObject defdict_type; /* Forward */ - PyDoc_STRVAR(defdict_missing_doc, "__missing__(key) # Called by __getitem__ for missing key; pseudo-code:\n\ if self.default_factory is None: raise KeyError((key,))\n\ @@ -2096,9 +2063,11 @@ static void defdict_dealloc(defdictobject *dd) { /* bpo-31095: UnTrack is needed before calling any callbacks */ + PyTypeObject *tp = Py_TYPE(dd); PyObject_GC_UnTrack(dd); - Py_CLEAR(dd->default_factory); + tp->tp_clear((PyObject *)dd); PyDict_Type.tp_dealloc((PyObject *)dd); + Py_DECREF(tp); } static PyObject * @@ -2142,7 +2111,8 @@ static PyObject* defdict_or(PyObject* left, PyObject* right) { PyObject *self, *other; - if (PyObject_TypeCheck(left, &defdict_type)) { + collections_state *state = find_module_state_by_def(Py_TYPE(left)); + if (PyObject_TypeCheck(left, state->defdict_type)) { self = left; other = right; } @@ -2166,13 +2136,10 @@ defdict_or(PyObject* left, PyObject* right) return new; } -static PyNumberMethods defdict_as_number = { - .nb_or = defdict_or, -}; - static int defdict_traverse(PyObject *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); Py_VISIT(((defdictobject *)self)->default_factory); return PyDict_Type.tp_traverse(self, visit, arg); } @@ -2228,48 +2195,28 @@ passed to the dict constructor, including keyword arguments.\n\ /* See comment in xxsubtype.c */ #define DEFERRED_ADDRESS(ADDR) 0 -static PyTypeObject defdict_type = { - PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) - "collections.defaultdict", /* tp_name */ - sizeof(defdictobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)defdict_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)defdict_repr, /* tp_repr */ - &defdict_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - /* tp_flags */ - defdict_doc, /* tp_doc */ - defdict_traverse, /* tp_traverse */ - (inquiry)defdict_tp_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset*/ - 0, /* tp_iter */ - 0, /* tp_iternext */ - defdict_methods, /* tp_methods */ - defdict_members, /* tp_members */ - 0, /* tp_getset */ - DEFERRED_ADDRESS(&PyDict_Type), /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - defdict_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - 0, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot defdict_slots[] = { + {Py_tp_dealloc, defdict_dealloc}, + {Py_tp_repr, defdict_repr}, + {Py_nb_or, defdict_or}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)defdict_doc}, + {Py_tp_traverse, defdict_traverse}, + {Py_tp_clear, defdict_tp_clear}, + {Py_tp_methods, defdict_methods}, + {Py_tp_members, defdict_members}, + {Py_tp_init, defdict_init}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec defdict_spec = { + .name = "_collections.defaultdict", + .basicsize = sizeof(defdictobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = defdict_slots, }; /* helper function for Counter *********************************************/ @@ -2467,6 +2414,7 @@ static int tuplegetter_traverse(PyObject *self, visitproc visit, void *arg) { _tuplegetterobject *tuplegetter = (_tuplegetterobject *)self; + Py_VISIT(Py_TYPE(tuplegetter)); Py_VISIT(tuplegetter->doc); return 0; } @@ -2482,9 +2430,11 @@ tuplegetter_clear(PyObject *self) static void tuplegetter_dealloc(_tuplegetterobject *self) { + PyTypeObject *tp = Py_TYPE(self); PyObject_GC_UnTrack(self); tuplegetter_clear((PyObject*)self); - Py_TYPE(self)->tp_free((PyObject*)self); + tp->tp_free((PyObject*)self); + Py_DECREF(tp); } static PyObject* @@ -2512,47 +2462,25 @@ static PyMethodDef tuplegetter_methods[] = { {NULL}, }; -static PyTypeObject tuplegetter_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_collections._tuplegetter", /* tp_name */ - sizeof(_tuplegetterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)tuplegetter_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)tuplegetter_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)tuplegetter_traverse, /* tp_traverse */ - (inquiry)tuplegetter_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - tuplegetter_methods, /* tp_methods */ - tuplegetter_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - tuplegetter_descr_get, /* tp_descr_get */ - tuplegetter_descr_set, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - tuplegetter_new, /* tp_new */ - 0, +static PyType_Slot tuplegetter_slots[] = { + {Py_tp_dealloc, tuplegetter_dealloc}, + {Py_tp_repr, tuplegetter_repr}, + {Py_tp_traverse, tuplegetter_traverse}, + {Py_tp_clear, tuplegetter_clear}, + {Py_tp_methods, tuplegetter_methods}, + {Py_tp_members, tuplegetter_members}, + {Py_tp_descr_get, tuplegetter_descr_get}, + {Py_tp_descr_set, tuplegetter_descr_set}, + {Py_tp_new, tuplegetter_new}, + {0, NULL}, +}; + +static PyType_Spec tuplegetter_spec = { + .name = "_collections._tuplegetter", + .basicsize = sizeof(_tuplegetterobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = tuplegetter_slots, }; @@ -2563,6 +2491,10 @@ collections_traverse(PyObject *mod, visitproc visit, void *arg) { collections_state *state = get_module_state(mod); Py_VISIT(state->deque_type); + Py_VISIT(state->defdict_type); + Py_VISIT(state->dequeiter_type); + Py_VISIT(state->dequereviter_type); + Py_VISIT(state->tuplegetter_type); return 0; } @@ -2571,6 +2503,10 @@ collections_clear(PyObject *mod) { collections_state *state = get_module_state(mod); Py_CLEAR(state->deque_type); + Py_CLEAR(state->defdict_type); + Py_CLEAR(state->dequeiter_type); + Py_CLEAR(state->dequereviter_type); + Py_CLEAR(state->tuplegetter_type); return 0; } @@ -2591,9 +2527,10 @@ static struct PyMethodDef collections_methods[] = { {NULL, NULL} /* sentinel */ }; -#define ADD_TYPE(mod, spec, type) \ +#define ADD_TYPE(mod, spec, type, base) \ do { \ - type = (PyTypeObject *)PyType_FromModuleAndSpec(mod, spec, NULL); \ + type = (PyTypeObject *)PyType_FromModuleAndSpec(mod, spec, \ + (PyObject *)base); \ if (type == NULL) { \ return -1; \ } \ @@ -2606,22 +2543,14 @@ static struct PyMethodDef collections_methods[] = { static int collections_exec(PyObject *module) { collections_state *state = get_module_state(module); - ADD_TYPE(module, &deque_spec, state->deque_type); - - PyTypeObject *typelist[] = { - &defdict_type, - &PyODict_Type, - &dequeiter_type, - &dequereviter_type, - &tuplegetter_type - }; - - defdict_type.tp_base = &PyDict_Type; + ADD_TYPE(module, &deque_spec, state->deque_type, NULL); + ADD_TYPE(module, &defdict_spec, state->defdict_type, &PyDict_Type); + ADD_TYPE(module, &dequeiter_spec, state->dequeiter_type, NULL); + ADD_TYPE(module, &dequereviter_spec, state->dequereviter_type, NULL); + ADD_TYPE(module, &tuplegetter_spec, state->tuplegetter_type, NULL); - for (size_t i = 0; i < Py_ARRAY_LENGTH(typelist); i++) { - if (PyModule_AddType(module, typelist[i]) < 0) { - return -1; - } + if (PyModule_AddType(module, &PyODict_Type) < 0) { + return -1; } return 0; diff --git a/Modules/clinic/_collectionsmodule.c.h b/Modules/clinic/_collectionsmodule.c.h index 8ea0255b061070..3882d069216e28 100644 --- a/Modules/clinic/_collectionsmodule.c.h +++ b/Modules/clinic/_collectionsmodule.c.h @@ -46,7 +46,7 @@ static PyObject * tuplegetter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; - PyTypeObject *base_tp = &tuplegetter_type; + PyTypeObject *base_tp = clinic_state()->tuplegetter_type; Py_ssize_t index; PyObject *doc; @@ -75,4 +75,4 @@ tuplegetter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=91a0f221c7b1f96c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=00e516317d2b8bed input=a9049054013a1b77]*/ From 83ccb7f36f366e6aac6688ba7c41b41f9c0fb758 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 28 Mar 2023 23:14:38 +0200 Subject: [PATCH 05/17] Purge globals-to-fix --- Tools/c-analyzer/cpython/globals-to-fix.tsv | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 57b8542fb46482..c729e54862e15f 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -311,11 +311,6 @@ Objects/sliceobject.c - _Py_EllipsisObject - ##----------------------- ## static types -Modules/_collectionsmodule.c - defdict_type - -Modules/_collectionsmodule.c - deque_type - -Modules/_collectionsmodule.c - dequeiter_type - -Modules/_collectionsmodule.c - dequereviter_type - -Modules/_collectionsmodule.c - tuplegetter_type - Modules/_io/bufferedio.c - PyBufferedIOBase_Type - Modules/_io/bytesio.c - _PyBytesIOBuffer_Type - Modules/_io/iobase.c - PyIOBase_Type - From e815144d10628f96f041686873748c3daa8ac764 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Thu, 6 Apr 2023 21:23:01 +0200 Subject: [PATCH 06/17] Fix up ADD_TYPE --- Modules/_collectionsmodule.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index fe6c2702bca8dd..d5b030691c2b0e 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -2527,18 +2527,17 @@ static struct PyMethodDef collections_methods[] = { {NULL, NULL} /* sentinel */ }; -#define ADD_TYPE(mod, spec, type, base) \ - do { \ - type = (PyTypeObject *)PyType_FromModuleAndSpec(mod, spec, \ - (PyObject *)base); \ - if (type == NULL) { \ - return -1; \ - } \ - if (PyModule_AddType(mod, type) < 0) { \ - return -1; \ - } \ - return 0; \ - } while (0) +#define ADD_TYPE(MOD, SPEC, TYPE, BASE) do { \ + TYPE = (PyTypeObject *)PyType_FromMetaclass(NULL, MOD, SPEC, \ + (PyObject *)BASE); \ + if (TYPE == NULL) { \ + return -1; \ + } \ + if (PyModule_AddType(MOD, TYPE) < 0) { \ + return -1; \ + } \ + return 0; \ +} while (0) static int collections_exec(PyObject *module) { @@ -2556,6 +2555,8 @@ collections_exec(PyObject *module) { return 0; } +#undef ADD_TYPE + static struct PyModuleDef_Slot collections_slots[] = { {Py_mod_exec, collections_exec}, {0, NULL} From c9de410012560116dad9ca65e0480b8e75adae74 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Sun, 9 Apr 2023 06:52:18 +0530 Subject: [PATCH 07/17] fix return --- Modules/_collectionsmodule.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index d5b030691c2b0e..9f06eaaf0ecace 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -2536,7 +2536,6 @@ static struct PyMethodDef collections_methods[] = { if (PyModule_AddType(MOD, TYPE) < 0) { \ return -1; \ } \ - return 0; \ } while (0) static int From a0af77358d39a97cb3aacacf6153472a42bb2106 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Sun, 9 Apr 2023 06:54:31 +0530 Subject: [PATCH 08/17] use _PyType_GetModuleState --- Modules/_collectionsmodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 9f06eaaf0ecace..80d4cc6417e785 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -2,6 +2,7 @@ #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_moduleobject.h" // _PyModule_GetState() +#include "pycore_typeobject.h" // _PyType_GetModuleState #include "structmember.h" // PyMemberDef #include @@ -24,7 +25,7 @@ get_module_state(PyObject *mod) static inline collections_state * get_module_state_by_cls(PyTypeObject *cls) { - void *state = PyType_GetModuleState(cls); + void *state = _PyType_GetModuleState(cls); assert(state != NULL); return (collections_state *)state; } From 3d6080633a2cd66ed308729e89bae9c35419f59d Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Sun, 9 Apr 2023 06:55:49 +0530 Subject: [PATCH 09/17] add parens --- Modules/_collectionsmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 80d4cc6417e785..4cf9cd1847e2c6 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -2,7 +2,7 @@ #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_moduleobject.h" // _PyModule_GetState() -#include "pycore_typeobject.h" // _PyType_GetModuleState +#include "pycore_typeobject.h" // _PyType_GetModuleState() #include "structmember.h" // PyMemberDef #include From 1b05b8260ffa24877581d6c36db12744bf383894 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Sun, 9 Apr 2023 07:00:05 +0530 Subject: [PATCH 10/17] blurb --- .../next/Library/2023-04-09-06-59-36.gh-issue-103092.vskbro.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2023-04-09-06-59-36.gh-issue-103092.vskbro.rst diff --git a/Misc/NEWS.d/next/Library/2023-04-09-06-59-36.gh-issue-103092.vskbro.rst b/Misc/NEWS.d/next/Library/2023-04-09-06-59-36.gh-issue-103092.vskbro.rst new file mode 100644 index 00000000000000..6977c1489a29cb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-09-06-59-36.gh-issue-103092.vskbro.rst @@ -0,0 +1 @@ +Isolate :mod:`!_collections` (apply :pep:`687`). Patch by Erlend E. Aasland. From 45a26f3bed971d9d8a08bdf293e96f97b50dcabe Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 10 Apr 2023 00:31:49 +0200 Subject: [PATCH 11/17] Don't call PyDict_Type stuff directly from dealloc, traverse, and clear --- Modules/_collectionsmodule.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 4cf9cd1847e2c6..f55ee6d9904b33 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -2067,7 +2067,7 @@ defdict_dealloc(defdictobject *dd) PyTypeObject *tp = Py_TYPE(dd); PyObject_GC_UnTrack(dd); tp->tp_clear((PyObject *)dd); - PyDict_Type.tp_dealloc((PyObject *)dd); + tp->tp_free((PyObject *)dd); Py_DECREF(tp); } @@ -2142,14 +2142,14 @@ defdict_traverse(PyObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); Py_VISIT(((defdictobject *)self)->default_factory); - return PyDict_Type.tp_traverse(self, visit, arg); + return 0; } static int defdict_tp_clear(defdictobject *dd) { Py_CLEAR(dd->default_factory); - return PyDict_Type.tp_clear((PyObject *)dd); + return 0; } static int From 2e4e957d5ef1803cfda012a14ee09c6100835615 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 10 Apr 2023 00:38:14 +0200 Subject: [PATCH 12/17] Revert unneeded change and cast in defdict_dealloc --- Modules/_collectionsmodule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index f55ee6d9904b33..85aff5d9b6532b 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -2066,8 +2066,8 @@ defdict_dealloc(defdictobject *dd) /* bpo-31095: UnTrack is needed before calling any callbacks */ PyTypeObject *tp = Py_TYPE(dd); PyObject_GC_UnTrack(dd); - tp->tp_clear((PyObject *)dd); - tp->tp_free((PyObject *)dd); + Py_CLEAR(dd->default_factory); + tp->tp_free(dd); Py_DECREF(tp); } From f4c937fee03bd367dd606d866da6722e3eaa1079 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 10 Apr 2023 00:40:57 +0200 Subject: [PATCH 13/17] Fixup dequeiter_dealloc() --- Modules/_collectionsmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 85aff5d9b6532b..c9fef7a3a936fb 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1728,7 +1728,7 @@ dequeiter_dealloc(dequeiterobject *dio) /* bpo-31095: UnTrack is needed before calling any callbacks */ PyTypeObject *tp = Py_TYPE(dio); PyObject_GC_UnTrack(dio); - tp->tp_clear((PyObject *)dio); + (void)dequeiter_clear(dio); PyObject_GC_Del(dio); Py_DECREF(tp); } From d7afd96e93aaaab894b6e1d74d34f3fcaa52d218 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 10 Apr 2023 09:37:52 +0200 Subject: [PATCH 14/17] Fix typenames --- Modules/_collectionsmodule.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index c9fef7a3a936fb..8b6ed93261535c 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1670,7 +1670,7 @@ static PyType_Slot deque_slots[] = { }; static PyType_Spec deque_spec = { - .name = "_collections.deque", + .name = "collections.deque", .basicsize = sizeof(dequeobject), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_SEQUENCE | @@ -1823,7 +1823,7 @@ static PyType_Slot dequeiter_slots[] = { }; static PyType_Spec dequeiter_spec = { - .name = "_collections._deque_iterator", + .name = "collections._deque_iterator", .basicsize = sizeof(dequeiterobject), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE), @@ -1920,7 +1920,7 @@ static PyType_Slot dequereviter_slots[] = { }; static PyType_Spec dequereviter_spec = { - .name = "_collections._deque_reverse_iterator", + .name = "collections._deque_reverse_iterator", .basicsize = sizeof(dequeiterobject), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE), @@ -2213,7 +2213,7 @@ static PyType_Slot defdict_slots[] = { }; static PyType_Spec defdict_spec = { - .name = "_collections.defaultdict", + .name = "collections.defaultdict", .basicsize = sizeof(defdictobject), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE), @@ -2477,7 +2477,7 @@ static PyType_Slot tuplegetter_slots[] = { }; static PyType_Spec tuplegetter_spec = { - .name = "_collections._tuplegetter", + .name = "collections._tuplegetter", .basicsize = sizeof(_tuplegetterobject), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE), From e4aa153133c29971017cfa29bd33b16df2b04c28 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 10 Apr 2023 10:06:31 +0200 Subject: [PATCH 15/17] Fix defdict_or --- Modules/_collectionsmodule.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 8b6ed93261535c..3663dda22b4828 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -2112,12 +2112,24 @@ static PyObject* defdict_or(PyObject* left, PyObject* right) { PyObject *self, *other; - collections_state *state = find_module_state_by_def(Py_TYPE(left)); + + // Find module state + PyTypeObject *tp = Py_TYPE(left); + PyObject *mod = PyType_GetModuleByDef(tp, &_collectionsmodule); + if (mod == NULL) { + PyErr_Clear(); + tp = Py_TYPE(right); + mod = PyType_GetModuleByDef(tp, &_collectionsmodule); + } + assert(mod != NULL); + collections_state *state = get_module_state(mod); + if (PyObject_TypeCheck(left, state->defdict_type)) { self = left; other = right; } else { + assert(PyObject_TypeCheck(right, state->defdict_type)); self = right; other = left; } From 0dcfcefbc98aecabd25eda84017c34f1437cf829 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 10 Apr 2023 11:37:42 +0200 Subject: [PATCH 16/17] Explicitly import _deque_iterator --- Lib/collections/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index a5393aad4249c0..03ca2d7e18f6f0 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -45,6 +45,11 @@ else: _collections_abc.MutableSequence.register(deque) +try: + from _collections import _deque_iterator +except ImportError: + pass + try: from _collections import defaultdict except ImportError: From 0381b45ebe868faa44d59bfdb6c6b54241e78b8c Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Wed, 12 Apr 2023 16:43:44 +0530 Subject: [PATCH 17/17] Fix deallocation (hopefully) --- Modules/_collectionsmodule.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 3663dda22b4828..a9b1425177c3d7 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -2067,7 +2067,7 @@ defdict_dealloc(defdictobject *dd) PyTypeObject *tp = Py_TYPE(dd); PyObject_GC_UnTrack(dd); Py_CLEAR(dd->default_factory); - tp->tp_free(dd); + PyDict_Type.tp_dealloc((PyObject *)dd); Py_DECREF(tp); } @@ -2154,14 +2154,14 @@ defdict_traverse(PyObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); Py_VISIT(((defdictobject *)self)->default_factory); - return 0; + return PyDict_Type.tp_traverse(self, visit, arg); } static int defdict_tp_clear(defdictobject *dd) { Py_CLEAR(dd->default_factory); - return 0; + return PyDict_Type.tp_clear((PyObject *)dd); } static int