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.
This commit is contained in:
Dong-hee Na 2020-03-30 23:35:38 +09:00 committed by GitHub
parent ce105541f8
commit 53e4c91725
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 31 deletions

View File

@ -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,)))

View File

@ -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 PyModuleDef_Slot _abc_slots[] = {
{Py_mod_exec, _abc_exec},
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 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