Skip to content

Commit 53e4c91

Browse files
authored
bpo-40077: Convert _abc module to use PyType_FromSpec() (GH-19202)
Replace statically allocated types with heap allocated types: use PyType_FromSpec(). Add a module state to store the _abc_data_type. Add traverse, clear and free functions to the module.
1 parent ce10554 commit 53e4c91

File tree

2 files changed

+76
-31
lines changed

2 files changed

+76
-31
lines changed

Lib/test/test_abc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ class B:
326326
token_old = abc_get_cache_token()
327327
A.register(B)
328328
token_new = abc_get_cache_token()
329-
self.assertNotEqual(token_old, token_new)
329+
self.assertGreater(token_new, token_old)
330330
self.assertTrue(isinstance(b, A))
331331
self.assertTrue(isinstance(b, (A,)))
332332

Modules/_abc.c

Lines changed: 75 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,26 @@ _Py_IDENTIFIER(_abc_impl);
2020
_Py_IDENTIFIER(__subclasscheck__);
2121
_Py_IDENTIFIER(__subclasshook__);
2222

23+
typedef struct {
24+
PyTypeObject *_abc_data_type;
25+
} _abcmodule_state;
26+
2327
/* A global counter that is incremented each time a class is
2428
registered as a virtual subclass of anything. It forces the
2529
negative cache to be cleared before its next use.
2630
Note: this counter is private. Use `abc.get_cache_token()` for
2731
external code. */
32+
// FIXME: PEP 573: Move abc_invalidation_counter into _abcmodule_state.
2833
static unsigned long long abc_invalidation_counter = 0;
2934

35+
static inline _abcmodule_state*
36+
get_abc_state(PyObject *module)
37+
{
38+
void *state = PyModule_GetState(module);
39+
assert(state != NULL);
40+
return (_abcmodule_state *)state;
41+
}
42+
3043
/* This object stores internal state for ABCs.
3144
Note that we can use normal sets for caches,
3245
since they are never iterated over. */
@@ -41,10 +54,12 @@ typedef struct {
4154
static void
4255
abc_data_dealloc(_abc_data *self)
4356
{
57+
PyTypeObject *tp = Py_TYPE(self);
4458
Py_XDECREF(self->_abc_registry);
4559
Py_XDECREF(self->_abc_cache);
4660
Py_XDECREF(self->_abc_negative_cache);
47-
Py_TYPE(self)->tp_free(self);
61+
tp->tp_free(self);
62+
Py_DECREF(tp);
4863
}
4964

5065
static PyObject *
@@ -65,24 +80,29 @@ abc_data_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
6580
PyDoc_STRVAR(abc_data_doc,
6681
"Internal state held by ABC machinery.");
6782

68-
static PyTypeObject _abc_data_type = {
69-
PyVarObject_HEAD_INIT(NULL, 0)
70-
"_abc_data", /*tp_name*/
71-
sizeof(_abc_data), /*tp_basicsize*/
72-
.tp_dealloc = (destructor)abc_data_dealloc,
73-
.tp_flags = Py_TPFLAGS_DEFAULT,
74-
.tp_alloc = PyType_GenericAlloc,
75-
.tp_new = abc_data_new,
83+
static PyType_Slot _abc_data_type_spec_slots[] = {
84+
{Py_tp_doc, (void *)abc_data_doc},
85+
{Py_tp_new, abc_data_new},
86+
{Py_tp_dealloc, abc_data_dealloc},
87+
{0, 0}
88+
};
89+
90+
static PyType_Spec _abc_data_type_spec = {
91+
.name = "_abc._abc_data",
92+
.basicsize = sizeof(_abc_data),
93+
.flags = Py_TPFLAGS_DEFAULT,
94+
.slots = _abc_data_type_spec_slots,
7695
};
7796

7897
static _abc_data *
79-
_get_impl(PyObject *self)
98+
_get_impl(PyObject *module, PyObject *self)
8099
{
100+
_abcmodule_state *state = get_abc_state(module);
81101
PyObject *impl = _PyObject_GetAttrId(self, &PyId__abc_impl);
82102
if (impl == NULL) {
83103
return NULL;
84104
}
85-
if (!Py_IS_TYPE(impl, &_abc_data_type)) {
105+
if (!Py_IS_TYPE(impl, state->_abc_data_type)) {
86106
PyErr_SetString(PyExc_TypeError, "_abc_impl is set to a wrong type");
87107
Py_DECREF(impl);
88108
return NULL;
@@ -179,7 +199,7 @@ static PyObject *
179199
_abc__reset_registry(PyObject *module, PyObject *self)
180200
/*[clinic end generated code: output=92d591a43566cc10 input=12a0b7eb339ac35c]*/
181201
{
182-
_abc_data *impl = _get_impl(self);
202+
_abc_data *impl = _get_impl(module, self);
183203
if (impl == NULL) {
184204
return NULL;
185205
}
@@ -206,7 +226,7 @@ static PyObject *
206226
_abc__reset_caches(PyObject *module, PyObject *self)
207227
/*[clinic end generated code: output=f296f0d5c513f80c input=c0ac616fd8acfb6f]*/
208228
{
209-
_abc_data *impl = _get_impl(self);
229+
_abc_data *impl = _get_impl(module, self);
210230
if (impl == NULL) {
211231
return NULL;
212232
}
@@ -241,7 +261,7 @@ static PyObject *
241261
_abc__get_dump(PyObject *module, PyObject *self)
242262
/*[clinic end generated code: output=9d9569a8e2c1c443 input=2c5deb1bfe9e3c79]*/
243263
{
244-
_abc_data *impl = _get_impl(self);
264+
_abc_data *impl = _get_impl(module, self);
245265
if (impl == NULL) {
246266
return NULL;
247267
}
@@ -391,13 +411,14 @@ static PyObject *
391411
_abc__abc_init(PyObject *module, PyObject *self)
392412
/*[clinic end generated code: output=594757375714cda1 input=8d7fe470ff77f029]*/
393413
{
414+
_abcmodule_state *state = get_abc_state(module);
394415
PyObject *data;
395416
if (compute_abstract_methods(self) < 0) {
396417
return NULL;
397418
}
398419

399420
/* Set up inheritance registry. */
400-
data = abc_data_new(&_abc_data_type, NULL, NULL);
421+
data = abc_data_new(state->_abc_data_type, NULL, NULL);
401422
if (data == NULL) {
402423
return NULL;
403424
}
@@ -446,7 +467,7 @@ _abc__abc_register_impl(PyObject *module, PyObject *self, PyObject *subclass)
446467
if (result < 0) {
447468
return NULL;
448469
}
449-
_abc_data *impl = _get_impl(self);
470+
_abc_data *impl = _get_impl(module, self);
450471
if (impl == NULL) {
451472
return NULL;
452473
}
@@ -480,7 +501,7 @@ _abc__abc_instancecheck_impl(PyObject *module, PyObject *self,
480501
/*[clinic end generated code: output=b8b5148f63b6b56f input=a4f4525679261084]*/
481502
{
482503
PyObject *subtype, *result = NULL, *subclass = NULL;
483-
_abc_data *impl = _get_impl(self);
504+
_abc_data *impl = _get_impl(module, self);
484505
if (impl == NULL) {
485506
return NULL;
486507
}
@@ -576,7 +597,7 @@ _abc__abc_subclasscheck_impl(PyObject *module, PyObject *self,
576597
PyObject *ok, *subclasses = NULL, *result = NULL;
577598
Py_ssize_t pos;
578599
int incache;
579-
_abc_data *impl = _get_impl(self);
600+
_abc_data *impl = _get_impl(module, self);
580601
if (impl == NULL) {
581602
return NULL;
582603
}
@@ -795,7 +816,7 @@ _abc_get_cache_token_impl(PyObject *module)
795816
return PyLong_FromUnsignedLongLong(abc_invalidation_counter);
796817
}
797818

798-
static struct PyMethodDef module_functions[] = {
819+
static struct PyMethodDef _abcmodule_methods[] = {
799820
_ABC_GET_CACHE_TOKEN_METHODDEF
800821
_ABC__ABC_INIT_METHODDEF
801822
_ABC__RESET_REGISTRY_METHODDEF
@@ -808,30 +829,54 @@ static struct PyMethodDef module_functions[] = {
808829
};
809830

810831
static int
811-
_abc_exec(PyObject *module)
832+
_abcmodule_exec(PyObject *module)
812833
{
813-
if (PyType_Ready(&_abc_data_type) < 0) {
834+
_abcmodule_state *state = get_abc_state(module);
835+
state->_abc_data_type = (PyTypeObject *)PyType_FromSpec(&_abc_data_type_spec);
836+
if (state->_abc_data_type == NULL) {
814837
return -1;
815838
}
816-
_abc_data_type.tp_doc = abc_data_doc;
839+
840+
return 0;
841+
}
842+
843+
static int
844+
_abcmodule_traverse(PyObject *module, visitproc visit, void *arg)
845+
{
846+
_abcmodule_state *state = get_abc_state(module);
847+
Py_VISIT(state->_abc_data_type);
817848
return 0;
818849
}
819850

820-
static PyModuleDef_Slot _abc_slots[] = {
821-
{Py_mod_exec, _abc_exec},
851+
static int
852+
_abcmodule_clear(PyObject *module)
853+
{
854+
_abcmodule_state *state = get_abc_state(module);
855+
Py_CLEAR(state->_abc_data_type);
856+
return 0;
857+
}
858+
859+
static void
860+
_abcmodule_free(void *module)
861+
{
862+
_abcmodule_clear((PyObject *)module);
863+
}
864+
865+
static PyModuleDef_Slot _abcmodule_slots[] = {
866+
{Py_mod_exec, _abcmodule_exec},
822867
{0, NULL}
823868
};
824869

825870
static struct PyModuleDef _abcmodule = {
826871
PyModuleDef_HEAD_INIT,
827872
"_abc",
828873
_abc__doc__,
829-
0,
830-
module_functions,
831-
_abc_slots,
832-
NULL,
833-
NULL,
834-
NULL
874+
sizeof(_abcmodule_state),
875+
_abcmodule_methods,
876+
_abcmodule_slots,
877+
_abcmodule_traverse,
878+
_abcmodule_clear,
879+
_abcmodule_free,
835880
};
836881

837882
PyMODINIT_FUNC

0 commit comments

Comments
 (0)