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:
parent
ce105541f8
commit
53e4c91725
|
@ -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,)))
|
||||
|
||||
|
|
105
Modules/_abc.c
105
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 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
|
||||
|
|
Loading…
Reference in New Issue