diff options
-rw-r--r-- | Lib/test/test_abc.py | 2 | ||||
-rw-r--r-- | Modules/_abc.c | 105 |
2 files changed, 76 insertions, 31 deletions
diff --git a/Lib/test/test_abc.py b/Lib/test/test_abc.py index 000e583..7e9c47b 100644 --- a/Lib/test/test_abc.py +++ b/Lib/test/test_abc.py @@ -326,7 +326,7 @@ def test_factory(abc_ABCMeta, abc_get_cache_token): token_old = abc_get_cache_token() A.register(B) token_new = abc_get_cache_token() - self.assertNotEqual(token_old, token_new) + self.assertGreater(token_new, token_old) self.assertTrue(isinstance(b, A)) self.assertTrue(isinstance(b, (A,))) diff --git a/Modules/_abc.c b/Modules/_abc.c index c991295..6270982 100644 --- a/Modules/_abc.c +++ b/Modules/_abc.c @@ -20,13 +20,26 @@ _Py_IDENTIFIER(_abc_impl); _Py_IDENTIFIER(__subclasscheck__); _Py_IDENTIFIER(__subclasshook__); +typedef struct { + PyTypeObject *_abc_data_type; +} _abcmodule_state; + /* A global counter that is incremented each time a class is registered as a virtual subclass of anything. It forces the negative cache to be cleared before its next use. Note: this counter is private. Use `abc.get_cache_token()` for external code. */ +// FIXME: PEP 573: Move abc_invalidation_counter into _abcmodule_state. static unsigned long long abc_invalidation_counter = 0; +static inline _abcmodule_state* +get_abc_state(PyObject *module) +{ + void *state = PyModule_GetState(module); + assert(state != NULL); + return (_abcmodule_state *)state; +} + /* This object stores internal state for ABCs. Note that we can use normal sets for caches, since they are never iterated over. */ @@ -41,10 +54,12 @@ typedef struct { static void abc_data_dealloc(_abc_data *self) { + PyTypeObject *tp = Py_TYPE(self); Py_XDECREF(self->_abc_registry); Py_XDECREF(self->_abc_cache); Py_XDECREF(self->_abc_negative_cache); - Py_TYPE(self)->tp_free(self); + tp->tp_free(self); + Py_DECREF(tp); } static PyObject * @@ -65,24 +80,29 @@ abc_data_new(PyTypeObject *type, PyObject *args, PyObject *kwds) PyDoc_STRVAR(abc_data_doc, "Internal state held by ABC machinery."); -static PyTypeObject _abc_data_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_abc_data", /*tp_name*/ - sizeof(_abc_data), /*tp_basicsize*/ - .tp_dealloc = (destructor)abc_data_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_alloc = PyType_GenericAlloc, - .tp_new = abc_data_new, +static PyType_Slot _abc_data_type_spec_slots[] = { + {Py_tp_doc, (void *)abc_data_doc}, + {Py_tp_new, abc_data_new}, + {Py_tp_dealloc, abc_data_dealloc}, + {0, 0} +}; + +static PyType_Spec _abc_data_type_spec = { + .name = "_abc._abc_data", + .basicsize = sizeof(_abc_data), + .flags = Py_TPFLAGS_DEFAULT, + .slots = _abc_data_type_spec_slots, }; static _abc_data * -_get_impl(PyObject *self) +_get_impl(PyObject *module, PyObject *self) { + _abcmodule_state *state = get_abc_state(module); PyObject *impl = _PyObject_GetAttrId(self, &PyId__abc_impl); if (impl == NULL) { return NULL; } - if (!Py_IS_TYPE(impl, &_abc_data_type)) { + if (!Py_IS_TYPE(impl, state->_abc_data_type)) { PyErr_SetString(PyExc_TypeError, "_abc_impl is set to a wrong type"); Py_DECREF(impl); return NULL; @@ -179,7 +199,7 @@ static PyObject * _abc__reset_registry(PyObject *module, PyObject *self) /*[clinic end generated code: output=92d591a43566cc10 input=12a0b7eb339ac35c]*/ { - _abc_data *impl = _get_impl(self); + _abc_data *impl = _get_impl(module, self); if (impl == NULL) { return NULL; } @@ -206,7 +226,7 @@ static PyObject * _abc__reset_caches(PyObject *module, PyObject *self) /*[clinic end generated code: output=f296f0d5c513f80c input=c0ac616fd8acfb6f]*/ { - _abc_data *impl = _get_impl(self); + _abc_data *impl = _get_impl(module, self); if (impl == NULL) { return NULL; } @@ -241,7 +261,7 @@ static PyObject * _abc__get_dump(PyObject *module, PyObject *self) /*[clinic end generated code: output=9d9569a8e2c1c443 input=2c5deb1bfe9e3c79]*/ { - _abc_data *impl = _get_impl(self); + _abc_data *impl = _get_impl(module, self); if (impl == NULL) { return NULL; } @@ -391,13 +411,14 @@ static PyObject * _abc__abc_init(PyObject *module, PyObject *self) /*[clinic end generated code: output=594757375714cda1 input=8d7fe470ff77f029]*/ { + _abcmodule_state *state = get_abc_state(module); PyObject *data; if (compute_abstract_methods(self) < 0) { return NULL; } /* Set up inheritance registry. */ - data = abc_data_new(&_abc_data_type, NULL, NULL); + data = abc_data_new(state->_abc_data_type, NULL, NULL); if (data == NULL) { return NULL; } @@ -446,7 +467,7 @@ _abc__abc_register_impl(PyObject *module, PyObject *self, PyObject *subclass) if (result < 0) { return NULL; } - _abc_data *impl = _get_impl(self); + _abc_data *impl = _get_impl(module, self); if (impl == NULL) { return NULL; } @@ -480,7 +501,7 @@ _abc__abc_instancecheck_impl(PyObject *module, PyObject *self, /*[clinic end generated code: output=b8b5148f63b6b56f input=a4f4525679261084]*/ { PyObject *subtype, *result = NULL, *subclass = NULL; - _abc_data *impl = _get_impl(self); + _abc_data *impl = _get_impl(module, self); if (impl == NULL) { return NULL; } @@ -576,7 +597,7 @@ _abc__abc_subclasscheck_impl(PyObject *module, PyObject *self, PyObject *ok, *subclasses = NULL, *result = NULL; Py_ssize_t pos; int incache; - _abc_data *impl = _get_impl(self); + _abc_data *impl = _get_impl(module, self); if (impl == NULL) { return NULL; } @@ -795,7 +816,7 @@ _abc_get_cache_token_impl(PyObject *module) return PyLong_FromUnsignedLongLong(abc_invalidation_counter); } -static struct PyMethodDef module_functions[] = { +static struct PyMethodDef _abcmodule_methods[] = { _ABC_GET_CACHE_TOKEN_METHODDEF _ABC__ABC_INIT_METHODDEF _ABC__RESET_REGISTRY_METHODDEF @@ -808,17 +829,41 @@ static struct PyMethodDef module_functions[] = { }; static int -_abc_exec(PyObject *module) +_abcmodule_exec(PyObject *module) { - if (PyType_Ready(&_abc_data_type) < 0) { + _abcmodule_state *state = get_abc_state(module); + state->_abc_data_type = (PyTypeObject *)PyType_FromSpec(&_abc_data_type_spec); + if (state->_abc_data_type == NULL) { return -1; } - _abc_data_type.tp_doc = abc_data_doc; + + return 0; +} + +static int +_abcmodule_traverse(PyObject *module, visitproc visit, void *arg) +{ + _abcmodule_state *state = get_abc_state(module); + Py_VISIT(state->_abc_data_type); return 0; } -static PyModuleDef_Slot _abc_slots[] = { - {Py_mod_exec, _abc_exec}, +static int +_abcmodule_clear(PyObject *module) +{ + _abcmodule_state *state = get_abc_state(module); + Py_CLEAR(state->_abc_data_type); + return 0; +} + +static void +_abcmodule_free(void *module) +{ + _abcmodule_clear((PyObject *)module); +} + +static PyModuleDef_Slot _abcmodule_slots[] = { + {Py_mod_exec, _abcmodule_exec}, {0, NULL} }; @@ -826,12 +871,12 @@ static struct PyModuleDef _abcmodule = { PyModuleDef_HEAD_INIT, "_abc", _abc__doc__, - 0, - module_functions, - _abc_slots, - NULL, - NULL, - NULL + sizeof(_abcmodule_state), + _abcmodule_methods, + _abcmodule_slots, + _abcmodule_traverse, + _abcmodule_clear, + _abcmodule_free, }; PyMODINIT_FUNC |