mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
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:
parent
c018d3037b
commit
81c72044a1
108 changed files with 2282 additions and 1573 deletions
|
@ -48,8 +48,6 @@
|
|||
# error "ceval.c must be build with Py_BUILD_CORE define for best performance"
|
||||
#endif
|
||||
|
||||
_Py_IDENTIFIER(__name__);
|
||||
|
||||
/* Forward declarations */
|
||||
static PyObject *trace_call_function(
|
||||
PyThreadState *tstate, PyObject *callable, PyObject **stack,
|
||||
|
@ -864,18 +862,12 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys)
|
|||
PyObject *seen = NULL;
|
||||
PyObject *dummy = NULL;
|
||||
PyObject *values = NULL;
|
||||
PyObject *get_name = NULL;
|
||||
PyObject *get = NULL;
|
||||
// We use the two argument form of map.get(key, default) for two reasons:
|
||||
// - Atomically check for a key and get its value without error handling.
|
||||
// - Don't cause key creation or resizing in dict subclasses like
|
||||
// collections.defaultdict that define __missing__ (or similar).
|
||||
_Py_IDENTIFIER(get);
|
||||
get_name = _PyUnicode_FromId(&PyId_get); // borrowed
|
||||
if (get_name == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
int meth_found = _PyObject_GetMethod(map, get_name, &get);
|
||||
int meth_found = _PyObject_GetMethod(map, &_Py_ID(get), &get);
|
||||
if (get == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
@ -1692,9 +1684,8 @@ resume_frame:
|
|||
SET_LOCALS_FROM_FRAME();
|
||||
|
||||
#ifdef LLTRACE
|
||||
_Py_IDENTIFIER(__ltrace__);
|
||||
{
|
||||
int r = _PyDict_ContainsId(GLOBALS(), &PyId___ltrace__);
|
||||
int r = PyDict_Contains(GLOBALS(), &_Py_ID(__ltrace__));
|
||||
if (r < 0) {
|
||||
goto exit_unwind;
|
||||
}
|
||||
|
@ -2330,9 +2321,8 @@ handle_eval_breaker:
|
|||
}
|
||||
|
||||
TARGET(PRINT_EXPR) {
|
||||
_Py_IDENTIFIER(displayhook);
|
||||
PyObject *value = POP();
|
||||
PyObject *hook = _PySys_GetObjectId(&PyId_displayhook);
|
||||
PyObject *hook = _PySys_GetAttr(tstate, &_Py_ID(displayhook));
|
||||
PyObject *res;
|
||||
if (hook == NULL) {
|
||||
_PyErr_SetString(tstate, PyExc_RuntimeError,
|
||||
|
@ -2537,12 +2527,11 @@ handle_eval_breaker:
|
|||
if (tstate->c_tracefunc == NULL) {
|
||||
gen_status = PyIter_Send(receiver, v, &retval);
|
||||
} else {
|
||||
_Py_IDENTIFIER(send);
|
||||
if (Py_IsNone(v) && PyIter_Check(receiver)) {
|
||||
retval = Py_TYPE(receiver)->tp_iternext(receiver);
|
||||
}
|
||||
else {
|
||||
retval = _PyObject_CallMethodIdOneArg(receiver, &PyId_send, v);
|
||||
retval = PyObject_CallMethodOneArg(receiver, &_Py_ID(send), v);
|
||||
}
|
||||
if (retval == NULL) {
|
||||
if (tstate->c_tracefunc != NULL
|
||||
|
@ -2675,11 +2664,10 @@ handle_eval_breaker:
|
|||
}
|
||||
|
||||
TARGET(LOAD_BUILD_CLASS) {
|
||||
_Py_IDENTIFIER(__build_class__);
|
||||
|
||||
PyObject *bc;
|
||||
if (PyDict_CheckExact(BUILTINS())) {
|
||||
bc = _PyDict_GetItemIdWithError(BUILTINS(), &PyId___build_class__);
|
||||
bc = _PyDict_GetItemWithError(BUILTINS(),
|
||||
&_Py_ID(__build_class__));
|
||||
if (bc == NULL) {
|
||||
if (!_PyErr_Occurred(tstate)) {
|
||||
_PyErr_SetString(tstate, PyExc_NameError,
|
||||
|
@ -2690,10 +2678,7 @@ handle_eval_breaker:
|
|||
Py_INCREF(bc);
|
||||
}
|
||||
else {
|
||||
PyObject *build_class_str = _PyUnicode_FromId(&PyId___build_class__);
|
||||
if (build_class_str == NULL)
|
||||
goto error;
|
||||
bc = PyObject_GetItem(BUILTINS(), build_class_str);
|
||||
bc = PyObject_GetItem(BUILTINS(), &_Py_ID(__build_class__));
|
||||
if (bc == NULL) {
|
||||
if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError))
|
||||
_PyErr_SetString(tstate, PyExc_NameError,
|
||||
|
@ -3252,7 +3237,6 @@ handle_eval_breaker:
|
|||
}
|
||||
|
||||
TARGET(SETUP_ANNOTATIONS) {
|
||||
_Py_IDENTIFIER(__annotations__);
|
||||
int err;
|
||||
PyObject *ann_dict;
|
||||
if (LOCALS() == NULL) {
|
||||
|
@ -3262,8 +3246,8 @@ handle_eval_breaker:
|
|||
}
|
||||
/* check if __annotations__ in locals()... */
|
||||
if (PyDict_CheckExact(LOCALS())) {
|
||||
ann_dict = _PyDict_GetItemIdWithError(LOCALS(),
|
||||
&PyId___annotations__);
|
||||
ann_dict = _PyDict_GetItemWithError(LOCALS(),
|
||||
&_Py_ID(__annotations__));
|
||||
if (ann_dict == NULL) {
|
||||
if (_PyErr_Occurred(tstate)) {
|
||||
goto error;
|
||||
|
@ -3273,8 +3257,8 @@ handle_eval_breaker:
|
|||
if (ann_dict == NULL) {
|
||||
goto error;
|
||||
}
|
||||
err = _PyDict_SetItemId(LOCALS(),
|
||||
&PyId___annotations__, ann_dict);
|
||||
err = PyDict_SetItem(LOCALS(), &_Py_ID(__annotations__),
|
||||
ann_dict);
|
||||
Py_DECREF(ann_dict);
|
||||
if (err != 0) {
|
||||
goto error;
|
||||
|
@ -3283,11 +3267,7 @@ handle_eval_breaker:
|
|||
}
|
||||
else {
|
||||
/* do the same if locals() is not a dict */
|
||||
PyObject *ann_str = _PyUnicode_FromId(&PyId___annotations__);
|
||||
if (ann_str == NULL) {
|
||||
goto error;
|
||||
}
|
||||
ann_dict = PyObject_GetItem(LOCALS(), ann_str);
|
||||
ann_dict = PyObject_GetItem(LOCALS(), &_Py_ID(__annotations__));
|
||||
if (ann_dict == NULL) {
|
||||
if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
|
||||
goto error;
|
||||
|
@ -3297,7 +3277,8 @@ handle_eval_breaker:
|
|||
if (ann_dict == NULL) {
|
||||
goto error;
|
||||
}
|
||||
err = PyObject_SetItem(LOCALS(), ann_str, ann_dict);
|
||||
err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__),
|
||||
ann_dict);
|
||||
Py_DECREF(ann_dict);
|
||||
if (err != 0) {
|
||||
goto error;
|
||||
|
@ -4203,11 +4184,9 @@ handle_eval_breaker:
|
|||
}
|
||||
|
||||
TARGET(BEFORE_ASYNC_WITH) {
|
||||
_Py_IDENTIFIER(__aenter__);
|
||||
_Py_IDENTIFIER(__aexit__);
|
||||
PyObject *mgr = TOP();
|
||||
PyObject *res;
|
||||
PyObject *enter = _PyObject_LookupSpecial(mgr, &PyId___aenter__);
|
||||
PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__));
|
||||
if (enter == NULL) {
|
||||
if (!_PyErr_Occurred(tstate)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
|
@ -4217,7 +4196,7 @@ handle_eval_breaker:
|
|||
}
|
||||
goto error;
|
||||
}
|
||||
PyObject *exit = _PyObject_LookupSpecial(mgr, &PyId___aexit__);
|
||||
PyObject *exit = _PyObject_LookupSpecial(mgr, &_Py_ID(__aexit__));
|
||||
if (exit == NULL) {
|
||||
if (!_PyErr_Occurred(tstate)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
|
@ -4241,11 +4220,9 @@ handle_eval_breaker:
|
|||
}
|
||||
|
||||
TARGET(BEFORE_WITH) {
|
||||
_Py_IDENTIFIER(__enter__);
|
||||
_Py_IDENTIFIER(__exit__);
|
||||
PyObject *mgr = TOP();
|
||||
PyObject *res;
|
||||
PyObject *enter = _PyObject_LookupSpecial(mgr, &PyId___enter__);
|
||||
PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__enter__));
|
||||
if (enter == NULL) {
|
||||
if (!_PyErr_Occurred(tstate)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
|
@ -4255,7 +4232,7 @@ handle_eval_breaker:
|
|||
}
|
||||
goto error;
|
||||
}
|
||||
PyObject *exit = _PyObject_LookupSpecial(mgr, &PyId___exit__);
|
||||
PyObject *exit = _PyObject_LookupSpecial(mgr, &_Py_ID(__exit__));
|
||||
if (exit == NULL) {
|
||||
if (!_PyErr_Occurred(tstate)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
|
@ -6793,19 +6770,25 @@ PyEval_GetBuiltins(void)
|
|||
|
||||
/* Convenience function to get a builtin from its name */
|
||||
PyObject *
|
||||
_PyEval_GetBuiltinId(_Py_Identifier *name)
|
||||
_PyEval_GetBuiltin(PyObject *name)
|
||||
{
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
PyObject *attr = _PyDict_GetItemIdWithError(PyEval_GetBuiltins(), name);
|
||||
PyObject *attr = PyDict_GetItemWithError(PyEval_GetBuiltins(), name);
|
||||
if (attr) {
|
||||
Py_INCREF(attr);
|
||||
}
|
||||
else if (!_PyErr_Occurred(tstate)) {
|
||||
_PyErr_SetObject(tstate, PyExc_AttributeError, _PyUnicode_FromId(name));
|
||||
_PyErr_SetObject(tstate, PyExc_AttributeError, name);
|
||||
}
|
||||
return attr;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyEval_GetBuiltinId(_Py_Identifier *name)
|
||||
{
|
||||
return _PyEval_GetBuiltin(_PyUnicode_FromId(name));
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyEval_GetLocals(void)
|
||||
{
|
||||
|
@ -7047,11 +7030,10 @@ static PyObject *
|
|||
import_name(PyThreadState *tstate, InterpreterFrame *frame,
|
||||
PyObject *name, PyObject *fromlist, PyObject *level)
|
||||
{
|
||||
_Py_IDENTIFIER(__import__);
|
||||
PyObject *import_func, *res;
|
||||
PyObject* stack[5];
|
||||
|
||||
import_func = _PyDict_GetItemIdWithError(frame->f_builtins, &PyId___import__);
|
||||
import_func = _PyDict_GetItemWithError(frame->f_builtins, &_Py_ID(__import__));
|
||||
if (import_func == NULL) {
|
||||
if (!_PyErr_Occurred(tstate)) {
|
||||
_PyErr_SetString(tstate, PyExc_ImportError, "__import__ not found");
|
||||
|
@ -7098,7 +7080,7 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name)
|
|||
/* Issue #17636: in case this failed because of a circular relative
|
||||
import, try to fallback on reading the module directly from
|
||||
sys.modules. */
|
||||
pkgname = _PyObject_GetAttrId(v, &PyId___name__);
|
||||
pkgname = PyObject_GetAttr(v, &_Py_ID(__name__));
|
||||
if (pkgname == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
@ -7140,8 +7122,7 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name)
|
|||
PyErr_SetImportError(errmsg, pkgname, NULL);
|
||||
}
|
||||
else {
|
||||
_Py_IDENTIFIER(__spec__);
|
||||
PyObject *spec = _PyObject_GetAttrId(v, &PyId___spec__);
|
||||
PyObject *spec = PyObject_GetAttr(v, &_Py_ID(__spec__));
|
||||
const char *fmt =
|
||||
_PyModuleSpec_IsInitializing(spec) ?
|
||||
"cannot import name %R from partially initialized module %R "
|
||||
|
@ -7163,17 +7144,15 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name)
|
|||
static int
|
||||
import_all_from(PyThreadState *tstate, PyObject *locals, PyObject *v)
|
||||
{
|
||||
_Py_IDENTIFIER(__all__);
|
||||
_Py_IDENTIFIER(__dict__);
|
||||
PyObject *all, *dict, *name, *value;
|
||||
int skip_leading_underscores = 0;
|
||||
int pos, err;
|
||||
|
||||
if (_PyObject_LookupAttrId(v, &PyId___all__, &all) < 0) {
|
||||
if (_PyObject_LookupAttr(v, &_Py_ID(__all__), &all) < 0) {
|
||||
return -1; /* Unexpected error */
|
||||
}
|
||||
if (all == NULL) {
|
||||
if (_PyObject_LookupAttrId(v, &PyId___dict__, &dict) < 0) {
|
||||
if (_PyObject_LookupAttr(v, &_Py_ID(__dict__), &dict) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (dict == NULL) {
|
||||
|
@ -7200,7 +7179,7 @@ import_all_from(PyThreadState *tstate, PyObject *locals, PyObject *v)
|
|||
break;
|
||||
}
|
||||
if (!PyUnicode_Check(name)) {
|
||||
PyObject *modname = _PyObject_GetAttrId(v, &PyId___name__);
|
||||
PyObject *modname = PyObject_GetAttr(v, &_Py_ID(__name__));
|
||||
if (modname == NULL) {
|
||||
Py_DECREF(name);
|
||||
err = -1;
|
||||
|
@ -7400,14 +7379,13 @@ format_exc_check_arg(PyThreadState *tstate, PyObject *exc,
|
|||
|
||||
if (exc == PyExc_NameError) {
|
||||
// Include the name in the NameError exceptions to offer suggestions later.
|
||||
_Py_IDENTIFIER(name);
|
||||
PyObject *type, *value, *traceback;
|
||||
PyErr_Fetch(&type, &value, &traceback);
|
||||
PyErr_NormalizeException(&type, &value, &traceback);
|
||||
if (PyErr_GivenExceptionMatches(value, PyExc_NameError)) {
|
||||
// We do not care if this fails because we are going to restore the
|
||||
// NameError anyway.
|
||||
(void)_PyObject_SetAttrId(value, &PyId_name, obj);
|
||||
(void)PyObject_SetAttr(value, &_Py_ID(name), obj);
|
||||
}
|
||||
PyErr_Restore(type, value, traceback);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue