bpo-46541: Replace core use of _Py_IDENTIFIER() with statically initialized global objects. (gh-30928)

We're no longer using _Py_IDENTIFIER() (or _Py_static_string()) in any core CPython code.  It is still used in a number of non-builtin stdlib modules.

The replacement is: PyUnicodeObject (not pointer) fields under _PyRuntimeState, statically initialized as part of _PyRuntime.  A new _Py_GET_GLOBAL_IDENTIFIER() macro facilitates lookup of the fields (along with _Py_GET_GLOBAL_STRING() for non-identifier strings).

https://bugs.python.org/issue46541#msg411799 explains the rationale for this change.

The core of the change is in:

* (new) Include/internal/pycore_global_strings.h - the declarations for the global strings, along with the macros
* Include/internal/pycore_runtime_init.h - added the static initializers for the global strings
* Include/internal/pycore_global_objects.h - where the struct in pycore_global_strings.h is hooked into _PyRuntimeState
* Tools/scripts/generate_global_objects.py - added generation of the global string declarations and static initializers

I've also added a --check flag to generate_global_objects.py (along with make check-global-objects) to check for unused global strings.  That check is added to the PR CI config.

The remainder of this change updates the core code to use _Py_GET_GLOBAL_IDENTIFIER() instead of _Py_IDENTIFIER() and the related _Py*Id functions (likewise for _Py_GET_GLOBAL_STRING() instead of _Py_static_string()).  This includes adding a few functions where there wasn't already an alternative to _Py*Id(), replacing the _Py_Identifier * parameter with PyObject *.

The following are not changed (yet):

* stop using _Py_IDENTIFIER() in the stdlib modules
* (maybe) get rid of _Py_IDENTIFIER(), etc. entirely -- this may not be doable as at least one package on PyPI using this (private) API
* (maybe) intern the strings during runtime init

https://bugs.python.org/issue46541
This commit is contained in:
Eric Snow 2022-02-08 13:39:07 -07:00 committed by GitHub
parent c018d3037b
commit 81c72044a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
108 changed files with 2282 additions and 1573 deletions

View file

@ -4,8 +4,9 @@
#endif
#include "Python.h"
#include "pycore_object.h" // _PyType_GetSubclasses()
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_object.h" // _PyType_GetSubclasses()
#include "pycore_runtime.h" // _Py_ID()
#include "clinic/_abc.c.h"
/*[clinic input]
@ -16,15 +17,6 @@ module _abc
PyDoc_STRVAR(_abc__doc__,
"Module contains faster C implementation of abc.ABCMeta");
_Py_IDENTIFIER(__abstractmethods__);
_Py_IDENTIFIER(__class__);
_Py_IDENTIFIER(__dict__);
_Py_IDENTIFIER(__abc_tpflags__);
_Py_IDENTIFIER(__bases__);
_Py_IDENTIFIER(_abc_impl);
_Py_IDENTIFIER(__subclasscheck__);
_Py_IDENTIFIER(__subclasshook__);
typedef struct {
PyTypeObject *_abc_data_type;
unsigned long long abc_invalidation_counter;
@ -122,7 +114,7 @@ static _abc_data *
_get_impl(PyObject *module, PyObject *self)
{
_abcmodule_state *state = get_abc_state(module);
PyObject *impl = _PyObject_GetAttrId(self, &PyId__abc_impl);
PyObject *impl = PyObject_GetAttr(self, &_Py_ID(_abc_impl));
if (impl == NULL) {
return NULL;
}
@ -311,7 +303,7 @@ compute_abstract_methods(PyObject *self)
PyObject *ns = NULL, *items = NULL, *bases = NULL; // Py_XDECREF()ed on error.
/* Stage 1: direct abstract methods. */
ns = _PyObject_GetAttrId(self, &PyId___dict__);
ns = PyObject_GetAttr(self, &_Py_ID(__dict__));
if (!ns) {
goto error;
}
@ -355,7 +347,7 @@ compute_abstract_methods(PyObject *self)
}
/* Stage 2: inherited abstract methods. */
bases = _PyObject_GetAttrId(self, &PyId___bases__);
bases = PyObject_GetAttr(self, &_Py_ID(__bases__));
if (!bases) {
goto error;
}
@ -368,8 +360,8 @@ compute_abstract_methods(PyObject *self)
PyObject *item = PyTuple_GET_ITEM(bases, pos); // borrowed
PyObject *base_abstracts, *iter;
if (_PyObject_LookupAttrId(item, &PyId___abstractmethods__,
&base_abstracts) < 0) {
if (_PyObject_LookupAttr(item, &_Py_ID(__abstractmethods__),
&base_abstracts) < 0) {
goto error;
}
if (base_abstracts == NULL) {
@ -409,7 +401,7 @@ compute_abstract_methods(PyObject *self)
}
}
if (_PyObject_SetAttrId(self, &PyId___abstractmethods__, abstracts) < 0) {
if (PyObject_SetAttr(self, &_Py_ID(__abstractmethods__), abstracts) < 0) {
goto error;
}
@ -448,7 +440,7 @@ _abc__abc_init(PyObject *module, PyObject *self)
if (data == NULL) {
return NULL;
}
if (_PyObject_SetAttrId(self, &PyId__abc_impl, data) < 0) {
if (PyObject_SetAttr(self, &_Py_ID(_abc_impl), data) < 0) {
Py_DECREF(data);
return NULL;
}
@ -459,7 +451,8 @@ _abc__abc_init(PyObject *module, PyObject *self)
* their special status w.r.t. pattern matching. */
if (PyType_Check(self)) {
PyTypeObject *cls = (PyTypeObject *)self;
PyObject *flags = _PyDict_GetItemIdWithError(cls->tp_dict, &PyId___abc_tpflags__);
PyObject *flags = PyDict_GetItemWithError(cls->tp_dict,
&_Py_ID(__abc_tpflags__));
if (flags == NULL) {
if (PyErr_Occurred()) {
return NULL;
@ -477,7 +470,7 @@ _abc__abc_init(PyObject *module, PyObject *self)
}
((PyTypeObject *)self)->tp_flags |= (val & COLLECTION_FLAGS);
}
if (_PyDict_DelItemId(cls->tp_dict, &PyId___abc_tpflags__) < 0) {
if (PyDict_DelItem(cls->tp_dict, &_Py_ID(__abc_tpflags__)) < 0) {
return NULL;
}
}
@ -593,7 +586,7 @@ _abc__abc_instancecheck_impl(PyObject *module, PyObject *self,
return NULL;
}
subclass = _PyObject_GetAttrId(instance, &PyId___class__);
subclass = PyObject_GetAttr(instance, &_Py_ID(__class__));
if (subclass == NULL) {
Py_DECREF(impl);
return NULL;
@ -622,12 +615,12 @@ _abc__abc_instancecheck_impl(PyObject *module, PyObject *self,
}
}
/* Fall back to the subclass check. */
result = _PyObject_CallMethodIdOneArg(self, &PyId___subclasscheck__,
subclass);
result = PyObject_CallMethodOneArg(self, &_Py_ID(__subclasscheck__),
subclass);
goto end;
}
result = _PyObject_CallMethodIdOneArg(self, &PyId___subclasscheck__,
subclass);
result = PyObject_CallMethodOneArg(self, &_Py_ID(__subclasscheck__),
subclass);
if (result == NULL) {
goto end;
}
@ -639,8 +632,8 @@ _abc__abc_instancecheck_impl(PyObject *module, PyObject *self,
break;
case 0:
Py_DECREF(result);
result = _PyObject_CallMethodIdOneArg(self, &PyId___subclasscheck__,
subtype);
result = PyObject_CallMethodOneArg(self, &_Py_ID(__subclasscheck__),
subtype);
break;
case 1: // Nothing to do.
break;
@ -723,8 +716,8 @@ _abc__abc_subclasscheck_impl(PyObject *module, PyObject *self,
}
/* 3. Check the subclass hook. */
ok = _PyObject_CallMethodIdOneArg((PyObject *)self, &PyId___subclasshook__,
subclass);
ok = PyObject_CallMethodOneArg(
(PyObject *)self, &_Py_ID(__subclasshook__), subclass);
if (ok == NULL) {
goto end;
}